blob: ff0b57027b9fb81fc42e0292f84cb00d91d95a73 [file] [log] [blame]
Austin Schuhcb108412019-10-13 16:09:54 -07001#include "aos/configuration.h"
2
3#include "absl/strings/strip.h"
4#include "aos/json_to_flatbuffer.h"
5#include "aos/testing/test_logging.h"
6#include "aos/util/file.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -07007#include "flatbuffers/reflection.h"
8#include "glog/logging.h"
Austin Schuhcb108412019-10-13 16:09:54 -07009#include "gtest/gtest.h"
10
11namespace aos {
12namespace configuration {
13namespace testing {
14
15class ConfigurationTest : public ::testing::Test {
16 public:
17 ConfigurationTest() { ::aos::testing::EnableTestLogging(); }
18};
19
20typedef ConfigurationTest ConfigurationDeathTest;
21
22// *the* expected location for all working tests.
23const char *kExpectedLocation =
24 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5 }";
Austin Schuhbca6cf02019-12-22 17:28:34 -080025// And for multinode setups
26const char *kExpectedMultinodeLocation =
27 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5, \"source_node\": \"pi1\" }";
Austin Schuhcb108412019-10-13 16:09:54 -070028
29// Tests that we can read and merge a configuration.
30TEST_F(ConfigurationTest, ConfigMerge) {
Austin Schuh40485ed2019-10-26 21:51:44 -070031 FlatbufferDetachedBuffer<Configuration> config =
32 ReadConfig("aos/testdata/config1.json");
Alex Perrycb7da4b2019-08-28 19:35:56 -070033 LOG(INFO) << "Read: " << FlatbufferToJson(config, true);
Austin Schuhcb108412019-10-13 16:09:54 -070034
35 EXPECT_EQ(
36 absl::StripSuffix(
37 util::ReadFileToStringOrDie("aos/testdata/expected.json"), "\n"),
38 FlatbufferToJson(config, true));
39}
40
Austin Schuh217a9782019-12-21 23:02:50 -080041// Tests that we can read and merge a multinode configuration.
42TEST_F(ConfigurationTest, ConfigMergeMultinode) {
43 FlatbufferDetachedBuffer<Configuration> config =
44 ReadConfig("aos/testdata/config1_multinode.json");
45 LOG(INFO) << "Read: " << FlatbufferToJson(config, true);
46
47 EXPECT_EQ(
48 std::string(absl::StripSuffix(
49 util::ReadFileToStringOrDie("aos/testdata/expected_multinode.json"),
50 "\n")),
51 FlatbufferToJson(config, true));
52}
53
Alex Perrycb7da4b2019-08-28 19:35:56 -070054// Tests that we sort the entries in a config so we can look entries up.
55TEST_F(ConfigurationTest, UnsortedConfig) {
56 FlatbufferDetachedBuffer<Configuration> config =
57 ReadConfig("aos/testdata/backwards.json");
58
59 LOG(INFO) << "Read: " << FlatbufferToJson(config, true);
60
61 EXPECT_EQ(FlatbufferToJson(GetChannel(config, ".aos.robot_state",
Austin Schuhbca6cf02019-12-22 17:28:34 -080062 "aos.RobotState", "app1", nullptr)),
Alex Perrycb7da4b2019-08-28 19:35:56 -070063 "{ \"name\": \".aos.robot_state\", \"type\": \"aos.RobotState\", "
64 "\"max_size\": 5 }");
65}
66
Austin Schuhcb108412019-10-13 16:09:54 -070067// Tests that we die when a file is imported twice.
68TEST_F(ConfigurationDeathTest, DuplicateFile) {
69 EXPECT_DEATH(
70 {
Austin Schuh40485ed2019-10-26 21:51:44 -070071 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuhcb108412019-10-13 16:09:54 -070072 ReadConfig("aos/testdata/config1_bad.json");
73 },
74 "aos/testdata/config1_bad.json");
75}
76
77// Tests that we can lookup a location, complete with maps, from a merged
78// config.
Austin Schuh40485ed2019-10-26 21:51:44 -070079TEST_F(ConfigurationTest, GetChannel) {
80 FlatbufferDetachedBuffer<Configuration> config =
81 ReadConfig("aos/testdata/config1.json");
Austin Schuhcb108412019-10-13 16:09:54 -070082
83 // Test a basic lookup first.
Austin Schuhbca6cf02019-12-22 17:28:34 -080084 EXPECT_EQ(
85 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", nullptr)),
86 kExpectedLocation);
Austin Schuhcb108412019-10-13 16:09:54 -070087
88 // Test that an invalid name results in nullptr back.
Austin Schuhbca6cf02019-12-22 17:28:34 -080089 EXPECT_EQ(GetChannel(config, "/invalid_name", ".aos.bar", "app1", nullptr),
90 nullptr);
Austin Schuhcb108412019-10-13 16:09:54 -070091
92 // Tests that a root map/rename works. And that they get processed from the
93 // bottom up.
Austin Schuhbca6cf02019-12-22 17:28:34 -080094 EXPECT_EQ(FlatbufferToJson(
95 GetChannel(config, "/batman", ".aos.bar", "app1", nullptr)),
96 kExpectedLocation);
Austin Schuhcb108412019-10-13 16:09:54 -070097
98 // And then test that an application specific map/rename works.
Austin Schuhbca6cf02019-12-22 17:28:34 -080099 EXPECT_EQ(
100 FlatbufferToJson(GetChannel(config, "/bar", ".aos.bar", "app1", nullptr)),
101 kExpectedLocation);
102 EXPECT_EQ(
103 FlatbufferToJson(GetChannel(config, "/baz", ".aos.bar", "app2", nullptr)),
104 kExpectedLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700105
106 // And then test that an invalid application name gets properly ignored.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800107 EXPECT_EQ(
108 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app3", nullptr)),
109 kExpectedLocation);
110}
111
112// Tests that we can lookup a location with node specific maps.
113TEST_F(ConfigurationTest, GetChannelMultinode) {
114 FlatbufferDetachedBuffer<Configuration> config =
115 ReadConfig("aos/testdata/good_multinode.json");
116 const Node *pi1 = GetNode(&config.message(), "pi1");
117 const Node *pi2 = GetNode(&config.message(), "pi2");
118
119 // Test a basic lookup first.
120 EXPECT_EQ(
121 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", pi1)),
122 kExpectedMultinodeLocation);
123 EXPECT_EQ(
124 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", pi2)),
125 kExpectedMultinodeLocation);
126
127 // Tests that a root map/rename works with a node specific map.
128 EXPECT_EQ(FlatbufferToJson(
129 GetChannel(config, "/batman", ".aos.bar", "app1", pi1)),
130 kExpectedMultinodeLocation);
131
132 // Tests that a root map/rename fails with a node specific map for the wrong
133 // node.
134 EXPECT_EQ(GetChannel(config, "/batman", ".aos.bar", "app1", pi2), nullptr);
135
136 // And then test that an application specific map/rename works.
137 EXPECT_EQ(
138 FlatbufferToJson(GetChannel(config, "/batman2", ".aos.bar", "app1", pi1)),
139 kExpectedMultinodeLocation);
140 EXPECT_EQ(
141 FlatbufferToJson(GetChannel(config, "/batman3", ".aos.bar", "app1", pi1)),
142 kExpectedMultinodeLocation);
143
144 // And then that it fails when the node changes.
145 EXPECT_EQ(GetChannel(config, "/batman3", ".aos.bar", "app1", pi2), nullptr);
146}
147
148// Tests that we can lookup a location with type specific maps.
149TEST_F(ConfigurationTest, GetChannelTypedMultinode) {
150 FlatbufferDetachedBuffer<Configuration> config =
151 ReadConfig("aos/testdata/good_multinode.json");
152 const Node *pi1 = GetNode(&config.message(), "pi1");
153
154 // Test a basic lookup first.
155 EXPECT_EQ(
156 FlatbufferToJson(GetChannel(config, "/batman", ".aos.bar", "app1", pi1)),
157 kExpectedMultinodeLocation);
158
159 // Now confirm that a second message on the same name doesn't get remapped.
160 const char *kExpectedBazMultinodeLocation =
161 "{ \"name\": \"/batman\", \"type\": \".aos.baz\", \"max_size\": 5, "
162 "\"source_node\": \"pi1\" }";
163 EXPECT_EQ(
164 FlatbufferToJson(GetChannel(config, "/batman", ".aos.baz", "app1", pi1)),
165 kExpectedBazMultinodeLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700166}
167
Austin Schuh217a9782019-12-21 23:02:50 -0800168// Tests that we reject a configuration which has a nodes list, but has channels
169// withoout source_node filled out.
170TEST_F(ConfigurationDeathTest, InvalidSourceNode) {
171 EXPECT_DEATH(
172 {
173 FlatbufferDetachedBuffer<Configuration> config =
174 ReadConfig("aos/testdata/invalid_nodes.json");
175 },
176 "source_node");
177
178 EXPECT_DEATH(
179 {
180 FlatbufferDetachedBuffer<Configuration> config =
181 ReadConfig("aos/testdata/invalid_source_node.json");
182 },
183 "source_node");
184
185 EXPECT_DEATH(
186 {
187 FlatbufferDetachedBuffer<Configuration> config =
188 ReadConfig("aos/testdata/invalid_destination_node.json");
189 },
190 "destination_nodes");
191
192 EXPECT_DEATH(
193 {
194 FlatbufferDetachedBuffer<Configuration> config =
195 ReadConfig("aos/testdata/self_forward.json");
196 },
197 "forwarding data to itself");
198}
199
200// Tests that our node writeable helpers work as intended.
201TEST_F(ConfigurationTest, ChannelIsSendableOnNode) {
202 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
203R"channel({
204 "name": "/test",
205 "type": "aos.examples.Ping",
206 "source_node": "foo"
207})channel",
208 Channel::MiniReflectTypeTable()));
209
210 FlatbufferDetachedBuffer<Channel> bad_channel(JsonToFlatbuffer(
211R"channel({
212 "name": "/test",
213 "type": "aos.examples.Ping",
214 "source_node": "bar"
215})channel",
216 Channel::MiniReflectTypeTable()));
217
218 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
219R"node({
220 "name": "foo"
221})node",
222 Node::MiniReflectTypeTable()));
223
224 EXPECT_TRUE(
225 ChannelIsSendableOnNode(&good_channel.message(), &node.message()));
226 EXPECT_FALSE(
227 ChannelIsSendableOnNode(&bad_channel.message(), &node.message()));
228}
229
230// Tests that our node readable and writeable helpers work as intended.
231TEST_F(ConfigurationTest, ChannelIsReadableOnNode) {
232 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
233R"channel({
234 "name": "/test",
235 "type": "aos.examples.Ping",
236 "source_node": "bar",
237 "destination_nodes": [
238 "baz",
239 "foo",
240 ]
241})channel",
242 Channel::MiniReflectTypeTable()));
243
244 FlatbufferDetachedBuffer<Channel> bad_channel1(JsonToFlatbuffer(
245R"channel({
246 "name": "/test",
247 "type": "aos.examples.Ping",
248 "source_node": "bar"
249})channel",
250 Channel::MiniReflectTypeTable()));
251
252 FlatbufferDetachedBuffer<Channel> bad_channel2(JsonToFlatbuffer(
253R"channel({
254 "name": "/test",
255 "type": "aos.examples.Ping",
256 "source_node": "bar",
257 "destination_nodes": [
258 "baz"
259 ]
260})channel",
261 Channel::MiniReflectTypeTable()));
262
263 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
264R"node({
265 "name": "foo"
266})node",
267 Node::MiniReflectTypeTable()));
268
269 EXPECT_TRUE(
270 ChannelIsReadableOnNode(&good_channel.message(), &node.message()));
271 EXPECT_FALSE(
272 ChannelIsReadableOnNode(&bad_channel1.message(), &node.message()));
273 EXPECT_FALSE(
274 ChannelIsReadableOnNode(&bad_channel2.message(), &node.message()));
275}
276
277
Austin Schuhcb108412019-10-13 16:09:54 -0700278} // namespace testing
279} // namespace configuration
280} // namespace aos