blob: 0ffa5df8c0da64eef41d59f832df543290f86cbd [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
16class ConfigurationTest : public ::testing::Test {
17 public:
18 ConfigurationTest() { ::aos::testing::EnableTestLogging(); }
19};
20
21typedef ConfigurationTest ConfigurationDeathTest;
22
23// *the* expected location for all working tests.
24const char *kExpectedLocation =
25 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5 }";
Austin Schuhbca6cf02019-12-22 17:28:34 -080026// And for multinode setups
27const char *kExpectedMultinodeLocation =
28 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5, \"source_node\": \"pi1\" }";
Austin Schuhcb108412019-10-13 16:09:54 -070029
30// Tests that we can read and merge a configuration.
31TEST_F(ConfigurationTest, ConfigMerge) {
Austin Schuh40485ed2019-10-26 21:51:44 -070032 FlatbufferDetachedBuffer<Configuration> config =
33 ReadConfig("aos/testdata/config1.json");
Alex Perrycb7da4b2019-08-28 19:35:56 -070034 LOG(INFO) << "Read: " << FlatbufferToJson(config, true);
Austin Schuhcb108412019-10-13 16:09:54 -070035
36 EXPECT_EQ(
37 absl::StripSuffix(
38 util::ReadFileToStringOrDie("aos/testdata/expected.json"), "\n"),
39 FlatbufferToJson(config, true));
40}
41
Austin Schuhc9e10ec2020-01-26 16:08:28 -080042// Tests that we can get back a ChannelIndex.
43TEST_F(ConfigurationTest, ChannelIndex) {
44 FlatbufferDetachedBuffer<Configuration> config =
45 ReadConfig("aos/testdata/config1.json");
46
47 EXPECT_EQ(
48 ChannelIndex(&config.message(), config.message().channels()->Get(1u)),
49 1u);
50}
51
Austin Schuh217a9782019-12-21 23:02:50 -080052// Tests that we can read and merge a multinode configuration.
53TEST_F(ConfigurationTest, ConfigMergeMultinode) {
54 FlatbufferDetachedBuffer<Configuration> config =
55 ReadConfig("aos/testdata/config1_multinode.json");
56 LOG(INFO) << "Read: " << FlatbufferToJson(config, true);
57
58 EXPECT_EQ(
59 std::string(absl::StripSuffix(
60 util::ReadFileToStringOrDie("aos/testdata/expected_multinode.json"),
61 "\n")),
62 FlatbufferToJson(config, true));
63}
64
Alex Perrycb7da4b2019-08-28 19:35:56 -070065// Tests that we sort the entries in a config so we can look entries up.
66TEST_F(ConfigurationTest, UnsortedConfig) {
67 FlatbufferDetachedBuffer<Configuration> config =
68 ReadConfig("aos/testdata/backwards.json");
69
70 LOG(INFO) << "Read: " << FlatbufferToJson(config, true);
71
72 EXPECT_EQ(FlatbufferToJson(GetChannel(config, ".aos.robot_state",
Austin Schuhbca6cf02019-12-22 17:28:34 -080073 "aos.RobotState", "app1", nullptr)),
Alex Perrycb7da4b2019-08-28 19:35:56 -070074 "{ \"name\": \".aos.robot_state\", \"type\": \"aos.RobotState\", "
75 "\"max_size\": 5 }");
76}
77
Austin Schuhcb108412019-10-13 16:09:54 -070078// Tests that we die when a file is imported twice.
79TEST_F(ConfigurationDeathTest, DuplicateFile) {
80 EXPECT_DEATH(
81 {
Austin Schuh40485ed2019-10-26 21:51:44 -070082 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuhcb108412019-10-13 16:09:54 -070083 ReadConfig("aos/testdata/config1_bad.json");
84 },
85 "aos/testdata/config1_bad.json");
86}
87
Austin Schuh8d6cea82020-02-28 12:17:16 -080088// Tests that we can modify a config with a json snippet.
89TEST_F(ConfigurationTest, MergeWithConfig) {
90 FlatbufferDetachedBuffer<Configuration> config =
91 ReadConfig("aos/testdata/config1.json");
92 LOG(INFO) << "Read: " << FlatbufferToJson(config, true);
93
94 FlatbufferDetachedBuffer<Configuration> updated_config =
95 MergeWithConfig(&config.message(),
96 R"channel({
97 "channels": [
98 {
99 "name": "/foo",
100 "type": ".aos.bar",
101 "max_size": 100
102 }
103 ]
104})channel");
105
106 EXPECT_EQ(
107 absl::StripSuffix(util::ReadFileToStringOrDie(
108 "aos/testdata/expected_merge_with.json"),
109 "\n"),
110 FlatbufferToJson(updated_config, true));
111}
112
Austin Schuhcb108412019-10-13 16:09:54 -0700113// Tests that we can lookup a location, complete with maps, from a merged
114// config.
Austin Schuh40485ed2019-10-26 21:51:44 -0700115TEST_F(ConfigurationTest, GetChannel) {
116 FlatbufferDetachedBuffer<Configuration> config =
117 ReadConfig("aos/testdata/config1.json");
Austin Schuhcb108412019-10-13 16:09:54 -0700118
119 // Test a basic lookup first.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800120 EXPECT_EQ(
121 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", nullptr)),
122 kExpectedLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700123
124 // Test that an invalid name results in nullptr back.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800125 EXPECT_EQ(GetChannel(config, "/invalid_name", ".aos.bar", "app1", nullptr),
126 nullptr);
Austin Schuhcb108412019-10-13 16:09:54 -0700127
128 // Tests that a root map/rename works. And that they get processed from the
129 // bottom up.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800130 EXPECT_EQ(FlatbufferToJson(
131 GetChannel(config, "/batman", ".aos.bar", "app1", nullptr)),
132 kExpectedLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700133
134 // And then test that an application specific map/rename works.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800135 EXPECT_EQ(
136 FlatbufferToJson(GetChannel(config, "/bar", ".aos.bar", "app1", nullptr)),
137 kExpectedLocation);
138 EXPECT_EQ(
139 FlatbufferToJson(GetChannel(config, "/baz", ".aos.bar", "app2", nullptr)),
140 kExpectedLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700141
142 // And then test that an invalid application name gets properly ignored.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800143 EXPECT_EQ(
144 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app3", nullptr)),
145 kExpectedLocation);
146}
147
148// Tests that we can lookup a location with node specific maps.
149TEST_F(ConfigurationTest, GetChannelMultinode) {
150 FlatbufferDetachedBuffer<Configuration> config =
151 ReadConfig("aos/testdata/good_multinode.json");
152 const Node *pi1 = GetNode(&config.message(), "pi1");
153 const Node *pi2 = GetNode(&config.message(), "pi2");
154
155 // Test a basic lookup first.
156 EXPECT_EQ(
157 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", pi1)),
158 kExpectedMultinodeLocation);
159 EXPECT_EQ(
160 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", pi2)),
161 kExpectedMultinodeLocation);
162
163 // Tests that a root map/rename works with a node specific map.
164 EXPECT_EQ(FlatbufferToJson(
165 GetChannel(config, "/batman", ".aos.bar", "app1", pi1)),
166 kExpectedMultinodeLocation);
167
168 // Tests that a root map/rename fails with a node specific map for the wrong
169 // node.
170 EXPECT_EQ(GetChannel(config, "/batman", ".aos.bar", "app1", pi2), nullptr);
171
172 // And then test that an application specific map/rename works.
173 EXPECT_EQ(
174 FlatbufferToJson(GetChannel(config, "/batman2", ".aos.bar", "app1", pi1)),
175 kExpectedMultinodeLocation);
176 EXPECT_EQ(
177 FlatbufferToJson(GetChannel(config, "/batman3", ".aos.bar", "app1", pi1)),
178 kExpectedMultinodeLocation);
179
180 // And then that it fails when the node changes.
181 EXPECT_EQ(GetChannel(config, "/batman3", ".aos.bar", "app1", pi2), nullptr);
182}
183
184// Tests that we can lookup a location with type specific maps.
185TEST_F(ConfigurationTest, GetChannelTypedMultinode) {
186 FlatbufferDetachedBuffer<Configuration> config =
187 ReadConfig("aos/testdata/good_multinode.json");
188 const Node *pi1 = GetNode(&config.message(), "pi1");
189
190 // Test a basic lookup first.
191 EXPECT_EQ(
192 FlatbufferToJson(GetChannel(config, "/batman", ".aos.bar", "app1", pi1)),
193 kExpectedMultinodeLocation);
194
195 // Now confirm that a second message on the same name doesn't get remapped.
196 const char *kExpectedBazMultinodeLocation =
197 "{ \"name\": \"/batman\", \"type\": \".aos.baz\", \"max_size\": 5, "
198 "\"source_node\": \"pi1\" }";
199 EXPECT_EQ(
200 FlatbufferToJson(GetChannel(config, "/batman", ".aos.baz", "app1", pi1)),
201 kExpectedBazMultinodeLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700202}
203
Austin Schuh217a9782019-12-21 23:02:50 -0800204// Tests that we reject a configuration which has a nodes list, but has channels
205// withoout source_node filled out.
206TEST_F(ConfigurationDeathTest, InvalidSourceNode) {
207 EXPECT_DEATH(
208 {
209 FlatbufferDetachedBuffer<Configuration> config =
210 ReadConfig("aos/testdata/invalid_nodes.json");
211 },
212 "source_node");
213
214 EXPECT_DEATH(
215 {
216 FlatbufferDetachedBuffer<Configuration> config =
217 ReadConfig("aos/testdata/invalid_source_node.json");
218 },
219 "source_node");
220
221 EXPECT_DEATH(
222 {
223 FlatbufferDetachedBuffer<Configuration> config =
224 ReadConfig("aos/testdata/invalid_destination_node.json");
225 },
226 "destination_nodes");
227
228 EXPECT_DEATH(
229 {
230 FlatbufferDetachedBuffer<Configuration> config =
231 ReadConfig("aos/testdata/self_forward.json");
232 },
233 "forwarding data to itself");
234}
235
236// Tests that our node writeable helpers work as intended.
237TEST_F(ConfigurationTest, ChannelIsSendableOnNode) {
238 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800239 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800240 "name": "/test",
241 "type": "aos.examples.Ping",
242 "source_node": "foo"
243})channel",
244 Channel::MiniReflectTypeTable()));
245
246 FlatbufferDetachedBuffer<Channel> bad_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800247 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800248 "name": "/test",
249 "type": "aos.examples.Ping",
250 "source_node": "bar"
251})channel",
252 Channel::MiniReflectTypeTable()));
253
254 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800255 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800256 "name": "foo"
257})node",
258 Node::MiniReflectTypeTable()));
259
260 EXPECT_TRUE(
261 ChannelIsSendableOnNode(&good_channel.message(), &node.message()));
262 EXPECT_FALSE(
263 ChannelIsSendableOnNode(&bad_channel.message(), &node.message()));
264}
265
266// Tests that our node readable and writeable helpers work as intended.
267TEST_F(ConfigurationTest, ChannelIsReadableOnNode) {
268 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800269 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800270 "name": "/test",
271 "type": "aos.examples.Ping",
272 "source_node": "bar",
273 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800274 {
275 "name": "baz"
276 },
277 {
278 "name": "foo"
279 }
Austin Schuh217a9782019-12-21 23:02:50 -0800280 ]
281})channel",
282 Channel::MiniReflectTypeTable()));
283
284 FlatbufferDetachedBuffer<Channel> bad_channel1(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800285 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800286 "name": "/test",
287 "type": "aos.examples.Ping",
288 "source_node": "bar"
289})channel",
290 Channel::MiniReflectTypeTable()));
291
292 FlatbufferDetachedBuffer<Channel> bad_channel2(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800293 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800294 "name": "/test",
295 "type": "aos.examples.Ping",
296 "source_node": "bar",
297 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800298 {
299 "name": "baz"
300 }
Austin Schuh217a9782019-12-21 23:02:50 -0800301 ]
302})channel",
303 Channel::MiniReflectTypeTable()));
304
305 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800306 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800307 "name": "foo"
308})node",
309 Node::MiniReflectTypeTable()));
310
311 EXPECT_TRUE(
312 ChannelIsReadableOnNode(&good_channel.message(), &node.message()));
313 EXPECT_FALSE(
314 ChannelIsReadableOnNode(&bad_channel1.message(), &node.message()));
315 EXPECT_FALSE(
316 ChannelIsReadableOnNode(&bad_channel2.message(), &node.message()));
317}
318
Austin Schuh719946b2019-12-28 14:51:01 -0800319// Tests that our node message is logged helpers work as intended.
320TEST_F(ConfigurationTest, ChannelMessageIsLoggedOnNode) {
321 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
322 R"channel({
323 "name": "/test",
324 "type": "aos.examples.Ping",
325 "source_node": "bar",
326 "destination_nodes": [
327 {
328 "name": "baz"
329 }
330 ]
331})channel",
332 Channel::MiniReflectTypeTable()));
Austin Schuh217a9782019-12-21 23:02:50 -0800333
Austin Schuh719946b2019-12-28 14:51:01 -0800334 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
335 R"channel({
336 "name": "/test",
337 "type": "aos.examples.Ping",
338 "source_node": "bar",
339 "logger": "NOT_LOGGED",
340 "destination_nodes": [
341 {
342 "name": "baz",
343 "timestamp_logger": "LOCAL_LOGGER"
344 }
345 ]
346})channel",
347 Channel::MiniReflectTypeTable()));
348
349 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
350 R"channel({
351 "name": "/test",
352 "type": "aos.examples.Ping",
353 "source_node": "bar",
354 "logger": "REMOTE_LOGGER",
355 "logger_node": "baz",
356 "destination_nodes": [
357 {
358 "name": "baz"
359 }
360 ]
361})channel",
362 Channel::MiniReflectTypeTable()));
363
364 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
365 JsonToFlatbuffer(
366 R"channel({
367 "name": "/test",
368 "type": "aos.examples.Ping",
369 "source_node": "bar",
370 "logger": "REMOTE_LOGGER",
371 "logger_node": "foo",
372 "destination_nodes": [
373 {
374 "name": "baz"
375 }
376 ]
377})channel",
378 Channel::MiniReflectTypeTable()));
379
380 FlatbufferDetachedBuffer<Channel> logged_on_both_channel (
381 JsonToFlatbuffer(
382 R"channel({
383 "name": "/test",
384 "type": "aos.examples.Ping",
385 "source_node": "bar",
386 "logger": "LOCAL_AND_REMOTE_LOGGER",
387 "logger_node": "baz",
388 "destination_nodes": [
389 {
390 "name": "baz"
391 }
392 ]
393})channel",
394 Channel::MiniReflectTypeTable()));
395
396 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
397 R"node({
398 "name": "foo"
399})node",
400 Node::MiniReflectTypeTable()));
401
402 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
403 R"node({
404 "name": "bar"
405})node",
406 Node::MiniReflectTypeTable()));
407
408 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
409 R"node({
410 "name": "baz"
411})node",
412 Node::MiniReflectTypeTable()));
413
414 // Local logger.
415 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
416 &foo_node.message()));
417 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
418 &bar_node.message()));
419 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
420 &baz_node.message()));
421
422 // No logger.
423 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
424 &foo_node.message()));
425 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
426 &bar_node.message()));
427 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
428 &baz_node.message()));
429
430 // Remote logger.
431 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
432 &foo_node.message()));
433 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
434 &bar_node.message()));
435 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
436 &baz_node.message()));
437
438 // Separate logger.
439 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(
440 &logged_on_separate_logger_node_channel.message(), &foo_node.message()));
441 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
442 &logged_on_separate_logger_node_channel.message(), &bar_node.message()));
443 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
444 &logged_on_separate_logger_node_channel.message(), &baz_node.message()));
445
446 // Logged in multiple places.
447 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
448 &foo_node.message()));
449 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
450 &bar_node.message()));
451 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
452 &baz_node.message()));
453}
454
455// Tests that our forwarding timestamps are logged helpers work as intended.
456TEST_F(ConfigurationTest, ConnectionDeliveryTimeIsLoggedOnNode) {
457 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
458 R"channel({
459 "name": "/test",
460 "type": "aos.examples.Ping",
461 "source_node": "bar",
462 "logger": "REMOTE_LOGGER",
463 "logger_node": "baz",
464 "destination_nodes": [
465 {
466 "name": "baz"
467 }
468 ]
469})channel",
470 Channel::MiniReflectTypeTable()));
471
472 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
473 R"channel({
474 "name": "/test",
475 "type": "aos.examples.Ping",
476 "source_node": "bar",
477 "logger": "NOT_LOGGED",
478 "destination_nodes": [
479 {
480 "name": "baz",
481 "timestamp_logger": "NOT_LOGGED"
482 }
483 ]
484})channel",
485 Channel::MiniReflectTypeTable()));
486
487 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
488 R"channel({
489 "name": "/test",
490 "type": "aos.examples.Ping",
491 "source_node": "bar",
492 "destination_nodes": [
493 {
494 "name": "baz",
495 "timestamp_logger": "REMOTE_LOGGER",
496 "timestamp_logger_node": "bar"
497 }
498 ]
499})channel",
500 Channel::MiniReflectTypeTable()));
501
502 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
503 JsonToFlatbuffer(
504 R"channel({
505 "name": "/test",
506 "type": "aos.examples.Ping",
507 "source_node": "bar",
508 "logger": "REMOTE_LOGGER",
509 "logger_node": "foo",
510 "destination_nodes": [
511 {
512 "name": "baz",
513 "timestamp_logger": "REMOTE_LOGGER",
514 "timestamp_logger_node": "foo"
515 }
516 ]
517})channel",
518 Channel::MiniReflectTypeTable()));
519
520 FlatbufferDetachedBuffer<Channel> logged_on_both_channel (
521 JsonToFlatbuffer(
522 R"channel({
523 "name": "/test",
524 "type": "aos.examples.Ping",
525 "source_node": "bar",
526 "destination_nodes": [
527 {
528 "name": "baz",
529 "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
530 "timestamp_logger_node": "bar"
531 }
532 ]
533})channel",
534 Channel::MiniReflectTypeTable()));
535
536 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
537 R"node({
538 "name": "foo"
539})node",
540 Node::MiniReflectTypeTable()));
541
542 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
543 R"node({
544 "name": "bar"
545})node",
546 Node::MiniReflectTypeTable()));
547
548 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
549 R"node({
550 "name": "baz"
551})node",
552 Node::MiniReflectTypeTable()));
553
554 // Local logger.
555 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
556 &logged_on_self_channel.message(), &baz_node.message(),
557 &foo_node.message()));
558 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
559 &logged_on_self_channel.message(), &baz_node.message(),
560 &bar_node.message()));
561 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
562 &logged_on_self_channel.message(), &baz_node.message(),
563 &baz_node.message()));
564
565 // No logger means.
566 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
567 &not_logged_channel.message(), &baz_node.message(), &foo_node.message()));
568 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
569 &not_logged_channel.message(), &baz_node.message(), &bar_node.message()));
570 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
571 &not_logged_channel.message(), &baz_node.message(), &baz_node.message()));
572
573 // Remote logger.
574 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
575 &logged_on_remote_channel.message(), &baz_node.message(),
576 &foo_node.message()));
577 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
578 &logged_on_remote_channel.message(), &baz_node.message(),
579 &bar_node.message()));
580 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
581 &logged_on_remote_channel.message(), &baz_node.message(),
582 &baz_node.message()));
583
584 // Separate logger.
585 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
586 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
587 &foo_node.message()));
588 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
589 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
590 &bar_node.message()));
591 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
592 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
593 &baz_node.message()));
594
595 // Logged on both the node and a remote node.
596 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
597 &logged_on_both_channel.message(), &baz_node.message(),
598 &foo_node.message()));
599 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
600 &logged_on_both_channel.message(), &baz_node.message(),
601 &bar_node.message()));
602 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
603 &logged_on_both_channel.message(), &baz_node.message(),
604 &baz_node.message()));
605}
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800606
607// Tests that we can deduce source nodes from a multinode config.
608TEST_F(ConfigurationTest, SourceNodeNames) {
609 FlatbufferDetachedBuffer<Configuration> config =
610 ReadConfig("aos/testdata/config1_multinode.json");
611
612 // This is a bit simplistic in that it doesn't test deduplication, but it does
613 // exercise a lot of the logic.
614 EXPECT_THAT(
615 SourceNodeNames(&config.message(), config.message().nodes()->Get(0)),
616 ::testing::ElementsAreArray({"pi2"}));
617 EXPECT_THAT(
618 SourceNodeNames(&config.message(), config.message().nodes()->Get(1)),
619 ::testing::ElementsAreArray({"pi1"}));
620}
621
622// Tests that we can deduce destination nodes from a multinode config.
623TEST_F(ConfigurationTest, DestinationNodeNames) {
624 FlatbufferDetachedBuffer<Configuration> config =
625 ReadConfig("aos/testdata/config1_multinode.json");
626
627 // This is a bit simplistic in that it doesn't test deduplication, but it does
628 // exercise a lot of the logic.
629 EXPECT_THAT(
630 DestinationNodeNames(&config.message(), config.message().nodes()->Get(0)),
631 ::testing::ElementsAreArray({"pi2"}));
632 EXPECT_THAT(
633 DestinationNodeNames(&config.message(), config.message().nodes()->Get(1)),
634 ::testing::ElementsAreArray({"pi1"}));
635}
636
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800637// Tests that we can pull out all the nodes.
638TEST_F(ConfigurationTest, GetNodes) {
639 {
640 FlatbufferDetachedBuffer<Configuration> config =
641 ReadConfig("aos/testdata/good_multinode.json");
642 const Node *pi1 = GetNode(&config.message(), "pi1");
643 const Node *pi2 = GetNode(&config.message(), "pi2");
644
645 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(pi1, pi2));
646 }
647
648 {
649 FlatbufferDetachedBuffer<Configuration> config =
650 ReadConfig("aos/testdata/config1.json");
651 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(nullptr));
652 }
653}
654
655// Tests that we can extract a node index from a config.
656TEST_F(ConfigurationTest, GetNodeIndex) {
657 FlatbufferDetachedBuffer<Configuration> config =
658 ReadConfig("aos/testdata/good_multinode.json");
Austin Schuh04408fc2020-02-16 21:48:54 -0800659 FlatbufferDetachedBuffer<Configuration> config2 =
660 ReadConfig("aos/testdata/good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800661 const Node *pi1 = GetNode(&config.message(), "pi1");
662 const Node *pi2 = GetNode(&config.message(), "pi2");
663
Austin Schuh04408fc2020-02-16 21:48:54 -0800664 // Try the normal case.
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800665 EXPECT_EQ(GetNodeIndex(&config.message(), pi1), 0);
666 EXPECT_EQ(GetNodeIndex(&config.message(), pi2), 1);
Austin Schuh04408fc2020-02-16 21:48:54 -0800667
668 // Now try if we have node pointers from a different message.
669 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1), 0);
670 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2), 1);
671
672 // And now try string names.
673 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1->name()->string_view()), 0);
674 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2->name()->string_view()), 1);
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800675}
676
677// Tests that GetNodeOrDie handles both single and multi-node worlds and returns
678// valid nodes.
679TEST_F(ConfigurationDeathTest, GetNodeOrDie) {
680 FlatbufferDetachedBuffer<Configuration> config =
681 ReadConfig("aos/testdata/good_multinode.json");
682 FlatbufferDetachedBuffer<Configuration> config2 =
683 ReadConfig("aos/testdata/good_multinode.json");
684 {
685 // Simple case, nullptr -> nullptr
686 FlatbufferDetachedBuffer<Configuration> single_node_config =
687 ReadConfig("aos/testdata/config1.json");
688 EXPECT_EQ(nullptr, GetNodeOrDie(&single_node_config.message(), nullptr));
689
690 // Confirm that we die when a node is passed in.
691 EXPECT_DEATH(
692 {
693 GetNodeOrDie(&single_node_config.message(),
694 config.message().nodes()->Get(0));
695 },
696 "Provided a node in a single node world.");
697 }
698
699 const Node *pi1 = GetNode(&config.message(), "pi1");
700 // Now try a lookup using a node from a different instance of the config.
701 EXPECT_EQ(pi1,
702 GetNodeOrDie(&config.message(), config2.message().nodes()->Get(0)));
703}
704
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800705TEST_F(ConfigurationTest, GetNodeFromHostname) {
706 FlatbufferDetachedBuffer<Configuration> config =
707 ReadConfig("aos/testdata/good_multinode.json");
708 EXPECT_EQ("pi1",
709 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
710 ->name()
711 ->string_view());
712 EXPECT_EQ("pi2", CHECK_NOTNULL(
713 GetNodeFromHostname(&config.message(), "raspberrypi2"))
714 ->name()
715 ->string_view());
716 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi3"));
717 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
718 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
719}
720
721TEST_F(ConfigurationTest, GetNodeFromHostnames) {
722 FlatbufferDetachedBuffer<Configuration> config =
723 ReadConfig("aos/testdata/good_multinode_hostnames.json");
724 EXPECT_EQ("pi1",
725 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
726 ->name()
727 ->string_view());
728 EXPECT_EQ("pi2", CHECK_NOTNULL(
729 GetNodeFromHostname(&config.message(), "raspberrypi2"))
730 ->name()
731 ->string_view());
732 EXPECT_EQ("pi2", CHECK_NOTNULL(
733 GetNodeFromHostname(&config.message(), "raspberrypi3"))
734 ->name()
735 ->string_view());
736 EXPECT_EQ("pi2", CHECK_NOTNULL(
737 GetNodeFromHostname(&config.message(), "other"))
738 ->name()
739 ->string_view());
740 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi4"));
741 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
742 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
743}
744
Austin Schuhcb108412019-10-13 16:09:54 -0700745} // namespace testing
746} // namespace configuration
747} // namespace aos