blob: c800017860bdeaefa56d9a574b53837899159fab [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"
Austin Schuhe84c3ed2019-12-14 15:29:48 -080010#include "gmock/gmock.h"
Austin Schuhcb108412019-10-13 16:09:54 -070011
12namespace aos {
13namespace configuration {
14namespace testing {
15
Austin Schuh66602132020-02-28 13:38:37 -080016const std::string kConfigPrefix = "aos/testdata/";
17
Austin Schuhcb108412019-10-13 16:09:54 -070018class ConfigurationTest : public ::testing::Test {
19 public:
20 ConfigurationTest() { ::aos::testing::EnableTestLogging(); }
21};
22
23typedef ConfigurationTest ConfigurationDeathTest;
24
25// *the* expected location for all working tests.
26const char *kExpectedLocation =
27 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5 }";
Austin Schuhbca6cf02019-12-22 17:28:34 -080028// And for multinode setups
29const char *kExpectedMultinodeLocation =
Ravago Jonescf453ab2020-05-06 21:14:53 -070030 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5, "
31 "\"source_node\": \"pi1\" }";
Austin Schuhcb108412019-10-13 16:09:54 -070032
33// Tests that we can read and merge a configuration.
34TEST_F(ConfigurationTest, ConfigMerge) {
Austin Schuh40485ed2019-10-26 21:51:44 -070035 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -080036 ReadConfig(kConfigPrefix + "config1.json");
Ravago Jonescf453ab2020-05-06 21:14:53 -070037 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuhcb108412019-10-13 16:09:54 -070038
39 EXPECT_EQ(
40 absl::StripSuffix(
Austin Schuh66602132020-02-28 13:38:37 -080041 util::ReadFileToStringOrDie(kConfigPrefix + "expected.json"), "\n"),
Ravago Jonescf453ab2020-05-06 21:14:53 -070042 FlatbufferToJson(config, {.multi_line = true}));
Austin Schuhcb108412019-10-13 16:09:54 -070043}
44
Austin Schuhc9e10ec2020-01-26 16:08:28 -080045// Tests that we can get back a ChannelIndex.
46TEST_F(ConfigurationTest, ChannelIndex) {
47 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -080048 ReadConfig(kConfigPrefix + "config1.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -080049
50 EXPECT_EQ(
51 ChannelIndex(&config.message(), config.message().channels()->Get(1u)),
52 1u);
53}
54
Austin Schuh217a9782019-12-21 23:02:50 -080055// Tests that we can read and merge a multinode configuration.
56TEST_F(ConfigurationTest, ConfigMergeMultinode) {
57 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -080058 ReadConfig(kConfigPrefix + "config1_multinode.json");
Ravago Jonescf453ab2020-05-06 21:14:53 -070059 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuh217a9782019-12-21 23:02:50 -080060
Ravago Jonescf453ab2020-05-06 21:14:53 -070061 EXPECT_EQ(std::string(absl::StripSuffix(
62 util::ReadFileToStringOrDie(kConfigPrefix +
63 "expected_multinode.json"),
64 "\n")),
65 FlatbufferToJson(config, {.multi_line = true}));
Austin Schuh217a9782019-12-21 23:02:50 -080066}
67
Alex Perrycb7da4b2019-08-28 19:35:56 -070068// Tests that we sort the entries in a config so we can look entries up.
69TEST_F(ConfigurationTest, UnsortedConfig) {
70 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -080071 ReadConfig(kConfigPrefix + "backwards.json");
Alex Perrycb7da4b2019-08-28 19:35:56 -070072
Ravago Jonescf453ab2020-05-06 21:14:53 -070073 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Alex Perrycb7da4b2019-08-28 19:35:56 -070074
Austin Schuhf1fff282020-03-28 16:57:32 -070075 EXPECT_EQ(FlatbufferToJson(GetChannel(config, "/aos/robot_state",
Austin Schuhbca6cf02019-12-22 17:28:34 -080076 "aos.RobotState", "app1", nullptr)),
Austin Schuhf1fff282020-03-28 16:57:32 -070077 "{ \"name\": \"/aos/robot_state\", \"type\": \"aos.RobotState\", "
Alex Perrycb7da4b2019-08-28 19:35:56 -070078 "\"max_size\": 5 }");
79}
80
Austin Schuhcb108412019-10-13 16:09:54 -070081// Tests that we die when a file is imported twice.
82TEST_F(ConfigurationDeathTest, DuplicateFile) {
83 EXPECT_DEATH(
84 {
Austin Schuh40485ed2019-10-26 21:51:44 -070085 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -080086 ReadConfig(kConfigPrefix + "config1_bad.json");
Austin Schuhcb108412019-10-13 16:09:54 -070087 },
Austin Schuh66602132020-02-28 13:38:37 -080088 kConfigPrefix + "config1_bad.json");
Austin Schuhcb108412019-10-13 16:09:54 -070089}
90
Austin Schuhf1fff282020-03-28 16:57:32 -070091// Tests that we reject invalid channel names. This means any channels with //
92// in their name, a trailing /, or regex characters.
93TEST_F(ConfigurationDeathTest, InvalidChannelName) {
94 EXPECT_DEATH(
95 {
96 FlatbufferDetachedBuffer<Configuration> config =
97 ReadConfig(kConfigPrefix + "invalid_channel_name1.json");
98 },
99 "Channel names can't end with '/'");
100 EXPECT_DEATH(
101 {
102 FlatbufferDetachedBuffer<Configuration> config =
103 ReadConfig(kConfigPrefix + "invalid_channel_name2.json");
104 },
105 "Invalid channel name");
106 EXPECT_DEATH(
107 {
108 FlatbufferDetachedBuffer<Configuration> config =
109 ReadConfig(kConfigPrefix + "invalid_channel_name3.json");
110 LOG(FATAL) << "Foo";
111 },
112 "Invalid channel name");
113}
114
Austin Schuh8d6cea82020-02-28 12:17:16 -0800115// Tests that we can modify a config with a json snippet.
116TEST_F(ConfigurationTest, MergeWithConfig) {
117 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800118 ReadConfig(kConfigPrefix + "config1.json");
Ravago Jonescf453ab2020-05-06 21:14:53 -0700119 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuh8d6cea82020-02-28 12:17:16 -0800120
121 FlatbufferDetachedBuffer<Configuration> updated_config =
122 MergeWithConfig(&config.message(),
123 R"channel({
124 "channels": [
125 {
126 "name": "/foo",
127 "type": ".aos.bar",
128 "max_size": 100
129 }
130 ]
131})channel");
132
Ravago Jonescf453ab2020-05-06 21:14:53 -0700133 EXPECT_EQ(absl::StripSuffix(util::ReadFileToStringOrDie(
134 kConfigPrefix + "expected_merge_with.json"),
135 "\n"),
136 FlatbufferToJson(updated_config, {.multi_line = true}));
Austin Schuh8d6cea82020-02-28 12:17:16 -0800137}
138
Austin Schuhcb108412019-10-13 16:09:54 -0700139// Tests that we can lookup a location, complete with maps, from a merged
140// config.
Austin Schuh40485ed2019-10-26 21:51:44 -0700141TEST_F(ConfigurationTest, GetChannel) {
142 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800143 ReadConfig(kConfigPrefix + "config1.json");
Austin Schuhcb108412019-10-13 16:09:54 -0700144
145 // Test a basic lookup first.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800146 EXPECT_EQ(
147 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", nullptr)),
148 kExpectedLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700149
150 // Test that an invalid name results in nullptr back.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800151 EXPECT_EQ(GetChannel(config, "/invalid_name", ".aos.bar", "app1", nullptr),
152 nullptr);
Austin Schuhcb108412019-10-13 16:09:54 -0700153
154 // Tests that a root map/rename works. And that they get processed from the
155 // bottom up.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800156 EXPECT_EQ(FlatbufferToJson(
157 GetChannel(config, "/batman", ".aos.bar", "app1", nullptr)),
158 kExpectedLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700159
160 // And then test that an application specific map/rename works.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800161 EXPECT_EQ(
162 FlatbufferToJson(GetChannel(config, "/bar", ".aos.bar", "app1", nullptr)),
163 kExpectedLocation);
164 EXPECT_EQ(
165 FlatbufferToJson(GetChannel(config, "/baz", ".aos.bar", "app2", nullptr)),
166 kExpectedLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700167
168 // And then test that an invalid application name gets properly ignored.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800169 EXPECT_EQ(
170 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app3", nullptr)),
171 kExpectedLocation);
172}
173
174// Tests that we can lookup a location with node specific maps.
175TEST_F(ConfigurationTest, GetChannelMultinode) {
176 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800177 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhbca6cf02019-12-22 17:28:34 -0800178 const Node *pi1 = GetNode(&config.message(), "pi1");
179 const Node *pi2 = GetNode(&config.message(), "pi2");
180
181 // Test a basic lookup first.
182 EXPECT_EQ(
183 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", pi1)),
184 kExpectedMultinodeLocation);
185 EXPECT_EQ(
186 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", pi2)),
187 kExpectedMultinodeLocation);
188
189 // Tests that a root map/rename works with a node specific map.
Ravago Jonescf453ab2020-05-06 21:14:53 -0700190 EXPECT_EQ(
191 FlatbufferToJson(GetChannel(config, "/batman", ".aos.bar", "app1", pi1)),
192 kExpectedMultinodeLocation);
Austin Schuhbca6cf02019-12-22 17:28:34 -0800193
194 // Tests that a root map/rename fails with a node specific map for the wrong
195 // node.
196 EXPECT_EQ(GetChannel(config, "/batman", ".aos.bar", "app1", pi2), nullptr);
197
198 // And then test that an application specific map/rename works.
199 EXPECT_EQ(
200 FlatbufferToJson(GetChannel(config, "/batman2", ".aos.bar", "app1", pi1)),
201 kExpectedMultinodeLocation);
202 EXPECT_EQ(
203 FlatbufferToJson(GetChannel(config, "/batman3", ".aos.bar", "app1", pi1)),
204 kExpectedMultinodeLocation);
205
206 // And then that it fails when the node changes.
207 EXPECT_EQ(GetChannel(config, "/batman3", ".aos.bar", "app1", pi2), nullptr);
208}
209
210// Tests that we can lookup a location with type specific maps.
211TEST_F(ConfigurationTest, GetChannelTypedMultinode) {
212 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800213 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhbca6cf02019-12-22 17:28:34 -0800214 const Node *pi1 = GetNode(&config.message(), "pi1");
215
216 // Test a basic lookup first.
217 EXPECT_EQ(
218 FlatbufferToJson(GetChannel(config, "/batman", ".aos.bar", "app1", pi1)),
219 kExpectedMultinodeLocation);
220
221 // Now confirm that a second message on the same name doesn't get remapped.
222 const char *kExpectedBazMultinodeLocation =
223 "{ \"name\": \"/batman\", \"type\": \".aos.baz\", \"max_size\": 5, "
224 "\"source_node\": \"pi1\" }";
225 EXPECT_EQ(
226 FlatbufferToJson(GetChannel(config, "/batman", ".aos.baz", "app1", pi1)),
227 kExpectedBazMultinodeLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700228}
229
Austin Schuhf1fff282020-03-28 16:57:32 -0700230// Tests that we can lookup a location with a glob
231TEST_F(ConfigurationTest, GetChannelGlob) {
232 FlatbufferDetachedBuffer<Configuration> config =
233 ReadConfig(kConfigPrefix + "good_multinode.json");
234 const Node *pi1 = GetNode(&config.message(), "pi1");
235
236 // Confirm that a glob with nothing after it matches.
237 const char *kExpectedMultinodeLocation =
238 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5, "
239 "\"source_node\": \"pi1\" }";
240 EXPECT_EQ(FlatbufferToJson(
241 GetChannel(config, "/magic/string", ".aos.bar", "app7", pi1)),
242 kExpectedMultinodeLocation);
243
244 // Now confirm that glob with something following it matches and renames
245 // correctly.
246 const char *kExpectedSubfolderMultinodeLocation =
247 "{ \"name\": \"/foo/subfolder\", \"type\": \".aos.bar\", \"max_size\": "
248 "5, \"source_node\": \"pi1\" }";
249 EXPECT_EQ(FlatbufferToJson(GetChannel(config, "/magic/string/subfolder",
250 ".aos.bar", "app7", pi1)),
251 kExpectedSubfolderMultinodeLocation);
252}
253
Austin Schuh217a9782019-12-21 23:02:50 -0800254// Tests that we reject a configuration which has a nodes list, but has channels
255// withoout source_node filled out.
256TEST_F(ConfigurationDeathTest, InvalidSourceNode) {
257 EXPECT_DEATH(
258 {
259 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800260 ReadConfig(kConfigPrefix + "invalid_nodes.json");
Austin Schuh217a9782019-12-21 23:02:50 -0800261 },
262 "source_node");
263
264 EXPECT_DEATH(
265 {
266 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800267 ReadConfig(kConfigPrefix + "invalid_source_node.json");
Austin Schuh217a9782019-12-21 23:02:50 -0800268 },
269 "source_node");
270
271 EXPECT_DEATH(
272 {
273 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800274 ReadConfig(kConfigPrefix + "invalid_destination_node.json");
Austin Schuh217a9782019-12-21 23:02:50 -0800275 },
276 "destination_nodes");
277
278 EXPECT_DEATH(
279 {
280 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800281 ReadConfig(kConfigPrefix + "self_forward.json");
Austin Schuh217a9782019-12-21 23:02:50 -0800282 },
283 "forwarding data to itself");
284}
285
286// Tests that our node writeable helpers work as intended.
287TEST_F(ConfigurationTest, ChannelIsSendableOnNode) {
288 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800289 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800290 "name": "/test",
291 "type": "aos.examples.Ping",
292 "source_node": "foo"
293})channel",
294 Channel::MiniReflectTypeTable()));
295
296 FlatbufferDetachedBuffer<Channel> bad_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800297 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800298 "name": "/test",
299 "type": "aos.examples.Ping",
300 "source_node": "bar"
301})channel",
302 Channel::MiniReflectTypeTable()));
303
304 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800305 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800306 "name": "foo"
307})node",
308 Node::MiniReflectTypeTable()));
309
310 EXPECT_TRUE(
311 ChannelIsSendableOnNode(&good_channel.message(), &node.message()));
312 EXPECT_FALSE(
313 ChannelIsSendableOnNode(&bad_channel.message(), &node.message()));
314}
315
316// Tests that our node readable and writeable helpers work as intended.
317TEST_F(ConfigurationTest, ChannelIsReadableOnNode) {
318 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800319 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800320 "name": "/test",
321 "type": "aos.examples.Ping",
322 "source_node": "bar",
323 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800324 {
325 "name": "baz"
326 },
327 {
328 "name": "foo"
329 }
Austin Schuh217a9782019-12-21 23:02:50 -0800330 ]
331})channel",
332 Channel::MiniReflectTypeTable()));
333
334 FlatbufferDetachedBuffer<Channel> bad_channel1(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800335 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800336 "name": "/test",
337 "type": "aos.examples.Ping",
338 "source_node": "bar"
339})channel",
340 Channel::MiniReflectTypeTable()));
341
342 FlatbufferDetachedBuffer<Channel> bad_channel2(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800343 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800344 "name": "/test",
345 "type": "aos.examples.Ping",
346 "source_node": "bar",
347 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800348 {
349 "name": "baz"
350 }
Austin Schuh217a9782019-12-21 23:02:50 -0800351 ]
352})channel",
353 Channel::MiniReflectTypeTable()));
354
355 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800356 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800357 "name": "foo"
358})node",
359 Node::MiniReflectTypeTable()));
360
361 EXPECT_TRUE(
362 ChannelIsReadableOnNode(&good_channel.message(), &node.message()));
363 EXPECT_FALSE(
364 ChannelIsReadableOnNode(&bad_channel1.message(), &node.message()));
365 EXPECT_FALSE(
366 ChannelIsReadableOnNode(&bad_channel2.message(), &node.message()));
367}
368
Austin Schuh719946b2019-12-28 14:51:01 -0800369// Tests that our node message is logged helpers work as intended.
370TEST_F(ConfigurationTest, ChannelMessageIsLoggedOnNode) {
371 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
372 R"channel({
373 "name": "/test",
374 "type": "aos.examples.Ping",
375 "source_node": "bar",
376 "destination_nodes": [
377 {
378 "name": "baz"
379 }
380 ]
381})channel",
382 Channel::MiniReflectTypeTable()));
Austin Schuh217a9782019-12-21 23:02:50 -0800383
Austin Schuh719946b2019-12-28 14:51:01 -0800384 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
385 R"channel({
386 "name": "/test",
387 "type": "aos.examples.Ping",
388 "source_node": "bar",
389 "logger": "NOT_LOGGED",
390 "destination_nodes": [
391 {
392 "name": "baz",
393 "timestamp_logger": "LOCAL_LOGGER"
394 }
395 ]
396})channel",
397 Channel::MiniReflectTypeTable()));
398
399 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
400 R"channel({
401 "name": "/test",
402 "type": "aos.examples.Ping",
403 "source_node": "bar",
404 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700405 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800406 "destination_nodes": [
407 {
408 "name": "baz"
409 }
410 ]
411})channel",
412 Channel::MiniReflectTypeTable()));
413
414 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
415 JsonToFlatbuffer(
416 R"channel({
417 "name": "/test",
418 "type": "aos.examples.Ping",
419 "source_node": "bar",
420 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700421 "logger_nodes": ["foo"],
Austin Schuh719946b2019-12-28 14:51:01 -0800422 "destination_nodes": [
423 {
424 "name": "baz"
425 }
426 ]
427})channel",
428 Channel::MiniReflectTypeTable()));
429
Ravago Jonescf453ab2020-05-06 21:14:53 -0700430 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
431 R"channel({
Austin Schuh719946b2019-12-28 14:51:01 -0800432 "name": "/test",
433 "type": "aos.examples.Ping",
434 "source_node": "bar",
435 "logger": "LOCAL_AND_REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700436 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800437 "destination_nodes": [
438 {
439 "name": "baz"
440 }
441 ]
442})channel",
Ravago Jonescf453ab2020-05-06 21:14:53 -0700443 Channel::MiniReflectTypeTable()));
Austin Schuh719946b2019-12-28 14:51:01 -0800444
445 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
446 R"node({
447 "name": "foo"
448})node",
449 Node::MiniReflectTypeTable()));
450
451 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
452 R"node({
453 "name": "bar"
454})node",
455 Node::MiniReflectTypeTable()));
456
457 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
458 R"node({
459 "name": "baz"
460})node",
461 Node::MiniReflectTypeTable()));
462
463 // Local logger.
464 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
465 &foo_node.message()));
466 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
467 &bar_node.message()));
468 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
469 &baz_node.message()));
470
471 // No logger.
472 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
473 &foo_node.message()));
474 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
Ravago Jonescf453ab2020-05-06 21:14:53 -0700475 &bar_node.message()));
Austin Schuh719946b2019-12-28 14:51:01 -0800476 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
477 &baz_node.message()));
478
479 // Remote logger.
480 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
481 &foo_node.message()));
482 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
483 &bar_node.message()));
484 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
485 &baz_node.message()));
486
487 // Separate logger.
488 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(
489 &logged_on_separate_logger_node_channel.message(), &foo_node.message()));
490 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
491 &logged_on_separate_logger_node_channel.message(), &bar_node.message()));
492 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
493 &logged_on_separate_logger_node_channel.message(), &baz_node.message()));
494
495 // Logged in multiple places.
496 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
497 &foo_node.message()));
498 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
499 &bar_node.message()));
500 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
501 &baz_node.message()));
502}
503
504// Tests that our forwarding timestamps are logged helpers work as intended.
505TEST_F(ConfigurationTest, ConnectionDeliveryTimeIsLoggedOnNode) {
506 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
507 R"channel({
508 "name": "/test",
509 "type": "aos.examples.Ping",
510 "source_node": "bar",
511 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700512 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800513 "destination_nodes": [
514 {
515 "name": "baz"
516 }
517 ]
518})channel",
519 Channel::MiniReflectTypeTable()));
520
521 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
522 R"channel({
523 "name": "/test",
524 "type": "aos.examples.Ping",
525 "source_node": "bar",
526 "logger": "NOT_LOGGED",
527 "destination_nodes": [
528 {
529 "name": "baz",
530 "timestamp_logger": "NOT_LOGGED"
531 }
532 ]
533})channel",
534 Channel::MiniReflectTypeTable()));
535
536 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
537 R"channel({
538 "name": "/test",
539 "type": "aos.examples.Ping",
540 "source_node": "bar",
541 "destination_nodes": [
542 {
543 "name": "baz",
544 "timestamp_logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700545 "timestamp_logger_nodes": ["bar"]
Austin Schuh719946b2019-12-28 14:51:01 -0800546 }
547 ]
548})channel",
549 Channel::MiniReflectTypeTable()));
550
551 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
552 JsonToFlatbuffer(
553 R"channel({
554 "name": "/test",
555 "type": "aos.examples.Ping",
556 "source_node": "bar",
557 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700558 "logger_nodes": ["foo"],
Austin Schuh719946b2019-12-28 14:51:01 -0800559 "destination_nodes": [
560 {
561 "name": "baz",
562 "timestamp_logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700563 "timestamp_logger_nodes": ["foo"]
Austin Schuh719946b2019-12-28 14:51:01 -0800564 }
565 ]
566})channel",
567 Channel::MiniReflectTypeTable()));
568
Ravago Jonescf453ab2020-05-06 21:14:53 -0700569 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
570 R"channel({
Austin Schuh719946b2019-12-28 14:51:01 -0800571 "name": "/test",
572 "type": "aos.examples.Ping",
573 "source_node": "bar",
574 "destination_nodes": [
575 {
576 "name": "baz",
577 "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700578 "timestamp_logger_nodes": ["bar"]
Austin Schuh719946b2019-12-28 14:51:01 -0800579 }
580 ]
581})channel",
Ravago Jonescf453ab2020-05-06 21:14:53 -0700582 Channel::MiniReflectTypeTable()));
Austin Schuh719946b2019-12-28 14:51:01 -0800583
584 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
585 R"node({
586 "name": "foo"
587})node",
588 Node::MiniReflectTypeTable()));
589
590 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
591 R"node({
592 "name": "bar"
593})node",
594 Node::MiniReflectTypeTable()));
595
596 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
597 R"node({
598 "name": "baz"
599})node",
600 Node::MiniReflectTypeTable()));
601
602 // Local logger.
603 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
604 &logged_on_self_channel.message(), &baz_node.message(),
605 &foo_node.message()));
606 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
607 &logged_on_self_channel.message(), &baz_node.message(),
608 &bar_node.message()));
609 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
610 &logged_on_self_channel.message(), &baz_node.message(),
611 &baz_node.message()));
612
613 // No logger means.
614 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
615 &not_logged_channel.message(), &baz_node.message(), &foo_node.message()));
616 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
617 &not_logged_channel.message(), &baz_node.message(), &bar_node.message()));
618 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
619 &not_logged_channel.message(), &baz_node.message(), &baz_node.message()));
620
621 // Remote logger.
622 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
623 &logged_on_remote_channel.message(), &baz_node.message(),
624 &foo_node.message()));
625 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
626 &logged_on_remote_channel.message(), &baz_node.message(),
627 &bar_node.message()));
628 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
629 &logged_on_remote_channel.message(), &baz_node.message(),
630 &baz_node.message()));
631
632 // Separate logger.
633 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
634 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
635 &foo_node.message()));
636 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
637 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
638 &bar_node.message()));
639 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
640 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
641 &baz_node.message()));
642
643 // Logged on both the node and a remote node.
644 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
645 &logged_on_both_channel.message(), &baz_node.message(),
646 &foo_node.message()));
647 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
648 &logged_on_both_channel.message(), &baz_node.message(),
649 &bar_node.message()));
650 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
651 &logged_on_both_channel.message(), &baz_node.message(),
652 &baz_node.message()));
653}
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800654
655// Tests that we can deduce source nodes from a multinode config.
656TEST_F(ConfigurationTest, SourceNodeNames) {
657 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800658 ReadConfig(kConfigPrefix + "config1_multinode.json");
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800659
660 // This is a bit simplistic in that it doesn't test deduplication, but it does
661 // exercise a lot of the logic.
662 EXPECT_THAT(
663 SourceNodeNames(&config.message(), config.message().nodes()->Get(0)),
664 ::testing::ElementsAreArray({"pi2"}));
665 EXPECT_THAT(
666 SourceNodeNames(&config.message(), config.message().nodes()->Get(1)),
667 ::testing::ElementsAreArray({"pi1"}));
668}
669
670// Tests that we can deduce destination nodes from a multinode config.
671TEST_F(ConfigurationTest, DestinationNodeNames) {
672 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800673 ReadConfig(kConfigPrefix + "config1_multinode.json");
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800674
675 // This is a bit simplistic in that it doesn't test deduplication, but it does
676 // exercise a lot of the logic.
677 EXPECT_THAT(
678 DestinationNodeNames(&config.message(), config.message().nodes()->Get(0)),
679 ::testing::ElementsAreArray({"pi2"}));
680 EXPECT_THAT(
681 DestinationNodeNames(&config.message(), config.message().nodes()->Get(1)),
682 ::testing::ElementsAreArray({"pi1"}));
683}
684
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800685// Tests that we can pull out all the nodes.
686TEST_F(ConfigurationTest, GetNodes) {
687 {
688 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800689 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800690 const Node *pi1 = GetNode(&config.message(), "pi1");
691 const Node *pi2 = GetNode(&config.message(), "pi2");
692
693 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(pi1, pi2));
694 }
695
696 {
697 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800698 ReadConfig(kConfigPrefix + "config1.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800699 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(nullptr));
700 }
701}
702
703// Tests that we can extract a node index from a config.
704TEST_F(ConfigurationTest, GetNodeIndex) {
705 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800706 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuh04408fc2020-02-16 21:48:54 -0800707 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh66602132020-02-28 13:38:37 -0800708 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800709 const Node *pi1 = GetNode(&config.message(), "pi1");
710 const Node *pi2 = GetNode(&config.message(), "pi2");
711
Austin Schuh04408fc2020-02-16 21:48:54 -0800712 // Try the normal case.
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800713 EXPECT_EQ(GetNodeIndex(&config.message(), pi1), 0);
714 EXPECT_EQ(GetNodeIndex(&config.message(), pi2), 1);
Austin Schuh04408fc2020-02-16 21:48:54 -0800715
716 // Now try if we have node pointers from a different message.
717 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1), 0);
718 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2), 1);
719
720 // And now try string names.
721 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1->name()->string_view()), 0);
722 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2->name()->string_view()), 1);
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800723}
724
725// Tests that GetNodeOrDie handles both single and multi-node worlds and returns
726// valid nodes.
727TEST_F(ConfigurationDeathTest, GetNodeOrDie) {
728 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800729 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800730 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh66602132020-02-28 13:38:37 -0800731 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800732 {
733 // Simple case, nullptr -> nullptr
734 FlatbufferDetachedBuffer<Configuration> single_node_config =
Austin Schuh66602132020-02-28 13:38:37 -0800735 ReadConfig(kConfigPrefix + "config1.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800736 EXPECT_EQ(nullptr, GetNodeOrDie(&single_node_config.message(), nullptr));
737
738 // Confirm that we die when a node is passed in.
739 EXPECT_DEATH(
740 {
741 GetNodeOrDie(&single_node_config.message(),
742 config.message().nodes()->Get(0));
743 },
744 "Provided a node in a single node world.");
745 }
746
747 const Node *pi1 = GetNode(&config.message(), "pi1");
748 // Now try a lookup using a node from a different instance of the config.
749 EXPECT_EQ(pi1,
750 GetNodeOrDie(&config.message(), config2.message().nodes()->Get(0)));
751}
752
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800753TEST_F(ConfigurationTest, GetNodeFromHostname) {
754 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800755 ReadConfig(kConfigPrefix + "good_multinode.json");
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800756 EXPECT_EQ("pi1",
757 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
758 ->name()
759 ->string_view());
760 EXPECT_EQ("pi2", CHECK_NOTNULL(
761 GetNodeFromHostname(&config.message(), "raspberrypi2"))
762 ->name()
763 ->string_view());
764 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi3"));
765 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
766 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
767}
768
769TEST_F(ConfigurationTest, GetNodeFromHostnames) {
770 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800771 ReadConfig(kConfigPrefix + "good_multinode_hostnames.json");
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800772 EXPECT_EQ("pi1",
773 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
774 ->name()
775 ->string_view());
776 EXPECT_EQ("pi2", CHECK_NOTNULL(
777 GetNodeFromHostname(&config.message(), "raspberrypi2"))
778 ->name()
779 ->string_view());
780 EXPECT_EQ("pi2", CHECK_NOTNULL(
781 GetNodeFromHostname(&config.message(), "raspberrypi3"))
782 ->name()
783 ->string_view());
Ravago Jonescf453ab2020-05-06 21:14:53 -0700784 EXPECT_EQ("pi2",
785 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "other"))
786 ->name()
787 ->string_view());
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800788 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi4"));
789 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
790 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
791}
792
Austin Schuhcb108412019-10-13 16:09:54 -0700793} // namespace testing
794} // namespace configuration
795} // namespace aos