blob: c36bd931e9e1d9ee772ee042df3047aca9d0f7ce [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
88// Tests that we can lookup a location, complete with maps, from a merged
89// config.
Austin Schuh40485ed2019-10-26 21:51:44 -070090TEST_F(ConfigurationTest, GetChannel) {
91 FlatbufferDetachedBuffer<Configuration> config =
92 ReadConfig("aos/testdata/config1.json");
Austin Schuhcb108412019-10-13 16:09:54 -070093
94 // Test a basic lookup first.
Austin Schuhbca6cf02019-12-22 17:28:34 -080095 EXPECT_EQ(
96 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", nullptr)),
97 kExpectedLocation);
Austin Schuhcb108412019-10-13 16:09:54 -070098
99 // Test that an invalid name results in nullptr back.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800100 EXPECT_EQ(GetChannel(config, "/invalid_name", ".aos.bar", "app1", nullptr),
101 nullptr);
Austin Schuhcb108412019-10-13 16:09:54 -0700102
103 // Tests that a root map/rename works. And that they get processed from the
104 // bottom up.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800105 EXPECT_EQ(FlatbufferToJson(
106 GetChannel(config, "/batman", ".aos.bar", "app1", nullptr)),
107 kExpectedLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700108
109 // And then test that an application specific map/rename works.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800110 EXPECT_EQ(
111 FlatbufferToJson(GetChannel(config, "/bar", ".aos.bar", "app1", nullptr)),
112 kExpectedLocation);
113 EXPECT_EQ(
114 FlatbufferToJson(GetChannel(config, "/baz", ".aos.bar", "app2", nullptr)),
115 kExpectedLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700116
117 // And then test that an invalid application name gets properly ignored.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800118 EXPECT_EQ(
119 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app3", nullptr)),
120 kExpectedLocation);
121}
122
123// Tests that we can lookup a location with node specific maps.
124TEST_F(ConfigurationTest, GetChannelMultinode) {
125 FlatbufferDetachedBuffer<Configuration> config =
126 ReadConfig("aos/testdata/good_multinode.json");
127 const Node *pi1 = GetNode(&config.message(), "pi1");
128 const Node *pi2 = GetNode(&config.message(), "pi2");
129
130 // Test a basic lookup first.
131 EXPECT_EQ(
132 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", pi1)),
133 kExpectedMultinodeLocation);
134 EXPECT_EQ(
135 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", pi2)),
136 kExpectedMultinodeLocation);
137
138 // Tests that a root map/rename works with a node specific map.
139 EXPECT_EQ(FlatbufferToJson(
140 GetChannel(config, "/batman", ".aos.bar", "app1", pi1)),
141 kExpectedMultinodeLocation);
142
143 // Tests that a root map/rename fails with a node specific map for the wrong
144 // node.
145 EXPECT_EQ(GetChannel(config, "/batman", ".aos.bar", "app1", pi2), nullptr);
146
147 // And then test that an application specific map/rename works.
148 EXPECT_EQ(
149 FlatbufferToJson(GetChannel(config, "/batman2", ".aos.bar", "app1", pi1)),
150 kExpectedMultinodeLocation);
151 EXPECT_EQ(
152 FlatbufferToJson(GetChannel(config, "/batman3", ".aos.bar", "app1", pi1)),
153 kExpectedMultinodeLocation);
154
155 // And then that it fails when the node changes.
156 EXPECT_EQ(GetChannel(config, "/batman3", ".aos.bar", "app1", pi2), nullptr);
157}
158
159// Tests that we can lookup a location with type specific maps.
160TEST_F(ConfigurationTest, GetChannelTypedMultinode) {
161 FlatbufferDetachedBuffer<Configuration> config =
162 ReadConfig("aos/testdata/good_multinode.json");
163 const Node *pi1 = GetNode(&config.message(), "pi1");
164
165 // Test a basic lookup first.
166 EXPECT_EQ(
167 FlatbufferToJson(GetChannel(config, "/batman", ".aos.bar", "app1", pi1)),
168 kExpectedMultinodeLocation);
169
170 // Now confirm that a second message on the same name doesn't get remapped.
171 const char *kExpectedBazMultinodeLocation =
172 "{ \"name\": \"/batman\", \"type\": \".aos.baz\", \"max_size\": 5, "
173 "\"source_node\": \"pi1\" }";
174 EXPECT_EQ(
175 FlatbufferToJson(GetChannel(config, "/batman", ".aos.baz", "app1", pi1)),
176 kExpectedBazMultinodeLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700177}
178
Austin Schuh217a9782019-12-21 23:02:50 -0800179// Tests that we reject a configuration which has a nodes list, but has channels
180// withoout source_node filled out.
181TEST_F(ConfigurationDeathTest, InvalidSourceNode) {
182 EXPECT_DEATH(
183 {
184 FlatbufferDetachedBuffer<Configuration> config =
185 ReadConfig("aos/testdata/invalid_nodes.json");
186 },
187 "source_node");
188
189 EXPECT_DEATH(
190 {
191 FlatbufferDetachedBuffer<Configuration> config =
192 ReadConfig("aos/testdata/invalid_source_node.json");
193 },
194 "source_node");
195
196 EXPECT_DEATH(
197 {
198 FlatbufferDetachedBuffer<Configuration> config =
199 ReadConfig("aos/testdata/invalid_destination_node.json");
200 },
201 "destination_nodes");
202
203 EXPECT_DEATH(
204 {
205 FlatbufferDetachedBuffer<Configuration> config =
206 ReadConfig("aos/testdata/self_forward.json");
207 },
208 "forwarding data to itself");
209}
210
211// Tests that our node writeable helpers work as intended.
212TEST_F(ConfigurationTest, ChannelIsSendableOnNode) {
213 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800214 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800215 "name": "/test",
216 "type": "aos.examples.Ping",
217 "source_node": "foo"
218})channel",
219 Channel::MiniReflectTypeTable()));
220
221 FlatbufferDetachedBuffer<Channel> bad_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800222 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800223 "name": "/test",
224 "type": "aos.examples.Ping",
225 "source_node": "bar"
226})channel",
227 Channel::MiniReflectTypeTable()));
228
229 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800230 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800231 "name": "foo"
232})node",
233 Node::MiniReflectTypeTable()));
234
235 EXPECT_TRUE(
236 ChannelIsSendableOnNode(&good_channel.message(), &node.message()));
237 EXPECT_FALSE(
238 ChannelIsSendableOnNode(&bad_channel.message(), &node.message()));
239}
240
241// Tests that our node readable and writeable helpers work as intended.
242TEST_F(ConfigurationTest, ChannelIsReadableOnNode) {
243 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800244 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800245 "name": "/test",
246 "type": "aos.examples.Ping",
247 "source_node": "bar",
248 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800249 {
250 "name": "baz"
251 },
252 {
253 "name": "foo"
254 }
Austin Schuh217a9782019-12-21 23:02:50 -0800255 ]
256})channel",
257 Channel::MiniReflectTypeTable()));
258
259 FlatbufferDetachedBuffer<Channel> bad_channel1(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800260 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800261 "name": "/test",
262 "type": "aos.examples.Ping",
263 "source_node": "bar"
264})channel",
265 Channel::MiniReflectTypeTable()));
266
267 FlatbufferDetachedBuffer<Channel> bad_channel2(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800268 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800269 "name": "/test",
270 "type": "aos.examples.Ping",
271 "source_node": "bar",
272 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800273 {
274 "name": "baz"
275 }
Austin Schuh217a9782019-12-21 23:02:50 -0800276 ]
277})channel",
278 Channel::MiniReflectTypeTable()));
279
280 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800281 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800282 "name": "foo"
283})node",
284 Node::MiniReflectTypeTable()));
285
286 EXPECT_TRUE(
287 ChannelIsReadableOnNode(&good_channel.message(), &node.message()));
288 EXPECT_FALSE(
289 ChannelIsReadableOnNode(&bad_channel1.message(), &node.message()));
290 EXPECT_FALSE(
291 ChannelIsReadableOnNode(&bad_channel2.message(), &node.message()));
292}
293
Austin Schuh719946b2019-12-28 14:51:01 -0800294// Tests that our node message is logged helpers work as intended.
295TEST_F(ConfigurationTest, ChannelMessageIsLoggedOnNode) {
296 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
297 R"channel({
298 "name": "/test",
299 "type": "aos.examples.Ping",
300 "source_node": "bar",
301 "destination_nodes": [
302 {
303 "name": "baz"
304 }
305 ]
306})channel",
307 Channel::MiniReflectTypeTable()));
Austin Schuh217a9782019-12-21 23:02:50 -0800308
Austin Schuh719946b2019-12-28 14:51:01 -0800309 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
310 R"channel({
311 "name": "/test",
312 "type": "aos.examples.Ping",
313 "source_node": "bar",
314 "logger": "NOT_LOGGED",
315 "destination_nodes": [
316 {
317 "name": "baz",
318 "timestamp_logger": "LOCAL_LOGGER"
319 }
320 ]
321})channel",
322 Channel::MiniReflectTypeTable()));
323
324 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
325 R"channel({
326 "name": "/test",
327 "type": "aos.examples.Ping",
328 "source_node": "bar",
329 "logger": "REMOTE_LOGGER",
330 "logger_node": "baz",
331 "destination_nodes": [
332 {
333 "name": "baz"
334 }
335 ]
336})channel",
337 Channel::MiniReflectTypeTable()));
338
339 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
340 JsonToFlatbuffer(
341 R"channel({
342 "name": "/test",
343 "type": "aos.examples.Ping",
344 "source_node": "bar",
345 "logger": "REMOTE_LOGGER",
346 "logger_node": "foo",
347 "destination_nodes": [
348 {
349 "name": "baz"
350 }
351 ]
352})channel",
353 Channel::MiniReflectTypeTable()));
354
355 FlatbufferDetachedBuffer<Channel> logged_on_both_channel (
356 JsonToFlatbuffer(
357 R"channel({
358 "name": "/test",
359 "type": "aos.examples.Ping",
360 "source_node": "bar",
361 "logger": "LOCAL_AND_REMOTE_LOGGER",
362 "logger_node": "baz",
363 "destination_nodes": [
364 {
365 "name": "baz"
366 }
367 ]
368})channel",
369 Channel::MiniReflectTypeTable()));
370
371 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
372 R"node({
373 "name": "foo"
374})node",
375 Node::MiniReflectTypeTable()));
376
377 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
378 R"node({
379 "name": "bar"
380})node",
381 Node::MiniReflectTypeTable()));
382
383 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
384 R"node({
385 "name": "baz"
386})node",
387 Node::MiniReflectTypeTable()));
388
389 // Local logger.
390 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
391 &foo_node.message()));
392 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
393 &bar_node.message()));
394 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
395 &baz_node.message()));
396
397 // No logger.
398 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
399 &foo_node.message()));
400 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
401 &bar_node.message()));
402 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
403 &baz_node.message()));
404
405 // Remote logger.
406 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
407 &foo_node.message()));
408 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
409 &bar_node.message()));
410 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
411 &baz_node.message()));
412
413 // Separate logger.
414 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(
415 &logged_on_separate_logger_node_channel.message(), &foo_node.message()));
416 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
417 &logged_on_separate_logger_node_channel.message(), &bar_node.message()));
418 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
419 &logged_on_separate_logger_node_channel.message(), &baz_node.message()));
420
421 // Logged in multiple places.
422 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
423 &foo_node.message()));
424 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
425 &bar_node.message()));
426 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
427 &baz_node.message()));
428}
429
430// Tests that our forwarding timestamps are logged helpers work as intended.
431TEST_F(ConfigurationTest, ConnectionDeliveryTimeIsLoggedOnNode) {
432 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
433 R"channel({
434 "name": "/test",
435 "type": "aos.examples.Ping",
436 "source_node": "bar",
437 "logger": "REMOTE_LOGGER",
438 "logger_node": "baz",
439 "destination_nodes": [
440 {
441 "name": "baz"
442 }
443 ]
444})channel",
445 Channel::MiniReflectTypeTable()));
446
447 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
448 R"channel({
449 "name": "/test",
450 "type": "aos.examples.Ping",
451 "source_node": "bar",
452 "logger": "NOT_LOGGED",
453 "destination_nodes": [
454 {
455 "name": "baz",
456 "timestamp_logger": "NOT_LOGGED"
457 }
458 ]
459})channel",
460 Channel::MiniReflectTypeTable()));
461
462 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
463 R"channel({
464 "name": "/test",
465 "type": "aos.examples.Ping",
466 "source_node": "bar",
467 "destination_nodes": [
468 {
469 "name": "baz",
470 "timestamp_logger": "REMOTE_LOGGER",
471 "timestamp_logger_node": "bar"
472 }
473 ]
474})channel",
475 Channel::MiniReflectTypeTable()));
476
477 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
478 JsonToFlatbuffer(
479 R"channel({
480 "name": "/test",
481 "type": "aos.examples.Ping",
482 "source_node": "bar",
483 "logger": "REMOTE_LOGGER",
484 "logger_node": "foo",
485 "destination_nodes": [
486 {
487 "name": "baz",
488 "timestamp_logger": "REMOTE_LOGGER",
489 "timestamp_logger_node": "foo"
490 }
491 ]
492})channel",
493 Channel::MiniReflectTypeTable()));
494
495 FlatbufferDetachedBuffer<Channel> logged_on_both_channel (
496 JsonToFlatbuffer(
497 R"channel({
498 "name": "/test",
499 "type": "aos.examples.Ping",
500 "source_node": "bar",
501 "destination_nodes": [
502 {
503 "name": "baz",
504 "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
505 "timestamp_logger_node": "bar"
506 }
507 ]
508})channel",
509 Channel::MiniReflectTypeTable()));
510
511 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
512 R"node({
513 "name": "foo"
514})node",
515 Node::MiniReflectTypeTable()));
516
517 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
518 R"node({
519 "name": "bar"
520})node",
521 Node::MiniReflectTypeTable()));
522
523 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
524 R"node({
525 "name": "baz"
526})node",
527 Node::MiniReflectTypeTable()));
528
529 // Local logger.
530 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
531 &logged_on_self_channel.message(), &baz_node.message(),
532 &foo_node.message()));
533 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
534 &logged_on_self_channel.message(), &baz_node.message(),
535 &bar_node.message()));
536 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
537 &logged_on_self_channel.message(), &baz_node.message(),
538 &baz_node.message()));
539
540 // No logger means.
541 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
542 &not_logged_channel.message(), &baz_node.message(), &foo_node.message()));
543 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
544 &not_logged_channel.message(), &baz_node.message(), &bar_node.message()));
545 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
546 &not_logged_channel.message(), &baz_node.message(), &baz_node.message()));
547
548 // Remote logger.
549 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
550 &logged_on_remote_channel.message(), &baz_node.message(),
551 &foo_node.message()));
552 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
553 &logged_on_remote_channel.message(), &baz_node.message(),
554 &bar_node.message()));
555 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
556 &logged_on_remote_channel.message(), &baz_node.message(),
557 &baz_node.message()));
558
559 // Separate logger.
560 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
561 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
562 &foo_node.message()));
563 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
564 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
565 &bar_node.message()));
566 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
567 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
568 &baz_node.message()));
569
570 // Logged on both the node and a remote node.
571 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
572 &logged_on_both_channel.message(), &baz_node.message(),
573 &foo_node.message()));
574 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
575 &logged_on_both_channel.message(), &baz_node.message(),
576 &bar_node.message()));
577 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
578 &logged_on_both_channel.message(), &baz_node.message(),
579 &baz_node.message()));
580}
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800581
582// Tests that we can deduce source nodes from a multinode config.
583TEST_F(ConfigurationTest, SourceNodeNames) {
584 FlatbufferDetachedBuffer<Configuration> config =
585 ReadConfig("aos/testdata/config1_multinode.json");
586
587 // This is a bit simplistic in that it doesn't test deduplication, but it does
588 // exercise a lot of the logic.
589 EXPECT_THAT(
590 SourceNodeNames(&config.message(), config.message().nodes()->Get(0)),
591 ::testing::ElementsAreArray({"pi2"}));
592 EXPECT_THAT(
593 SourceNodeNames(&config.message(), config.message().nodes()->Get(1)),
594 ::testing::ElementsAreArray({"pi1"}));
595}
596
597// Tests that we can deduce destination nodes from a multinode config.
598TEST_F(ConfigurationTest, DestinationNodeNames) {
599 FlatbufferDetachedBuffer<Configuration> config =
600 ReadConfig("aos/testdata/config1_multinode.json");
601
602 // This is a bit simplistic in that it doesn't test deduplication, but it does
603 // exercise a lot of the logic.
604 EXPECT_THAT(
605 DestinationNodeNames(&config.message(), config.message().nodes()->Get(0)),
606 ::testing::ElementsAreArray({"pi2"}));
607 EXPECT_THAT(
608 DestinationNodeNames(&config.message(), config.message().nodes()->Get(1)),
609 ::testing::ElementsAreArray({"pi1"}));
610}
611
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800612// Tests that we can pull out all the nodes.
613TEST_F(ConfigurationTest, GetNodes) {
614 {
615 FlatbufferDetachedBuffer<Configuration> config =
616 ReadConfig("aos/testdata/good_multinode.json");
617 const Node *pi1 = GetNode(&config.message(), "pi1");
618 const Node *pi2 = GetNode(&config.message(), "pi2");
619
620 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(pi1, pi2));
621 }
622
623 {
624 FlatbufferDetachedBuffer<Configuration> config =
625 ReadConfig("aos/testdata/config1.json");
626 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(nullptr));
627 }
628}
629
630// Tests that we can extract a node index from a config.
631TEST_F(ConfigurationTest, GetNodeIndex) {
632 FlatbufferDetachedBuffer<Configuration> config =
633 ReadConfig("aos/testdata/good_multinode.json");
Austin Schuh04408fc2020-02-16 21:48:54 -0800634 FlatbufferDetachedBuffer<Configuration> config2 =
635 ReadConfig("aos/testdata/good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800636 const Node *pi1 = GetNode(&config.message(), "pi1");
637 const Node *pi2 = GetNode(&config.message(), "pi2");
638
Austin Schuh04408fc2020-02-16 21:48:54 -0800639 // Try the normal case.
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800640 EXPECT_EQ(GetNodeIndex(&config.message(), pi1), 0);
641 EXPECT_EQ(GetNodeIndex(&config.message(), pi2), 1);
Austin Schuh04408fc2020-02-16 21:48:54 -0800642
643 // Now try if we have node pointers from a different message.
644 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1), 0);
645 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2), 1);
646
647 // And now try string names.
648 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1->name()->string_view()), 0);
649 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2->name()->string_view()), 1);
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800650}
651
652// Tests that GetNodeOrDie handles both single and multi-node worlds and returns
653// valid nodes.
654TEST_F(ConfigurationDeathTest, GetNodeOrDie) {
655 FlatbufferDetachedBuffer<Configuration> config =
656 ReadConfig("aos/testdata/good_multinode.json");
657 FlatbufferDetachedBuffer<Configuration> config2 =
658 ReadConfig("aos/testdata/good_multinode.json");
659 {
660 // Simple case, nullptr -> nullptr
661 FlatbufferDetachedBuffer<Configuration> single_node_config =
662 ReadConfig("aos/testdata/config1.json");
663 EXPECT_EQ(nullptr, GetNodeOrDie(&single_node_config.message(), nullptr));
664
665 // Confirm that we die when a node is passed in.
666 EXPECT_DEATH(
667 {
668 GetNodeOrDie(&single_node_config.message(),
669 config.message().nodes()->Get(0));
670 },
671 "Provided a node in a single node world.");
672 }
673
674 const Node *pi1 = GetNode(&config.message(), "pi1");
675 // Now try a lookup using a node from a different instance of the config.
676 EXPECT_EQ(pi1,
677 GetNodeOrDie(&config.message(), config2.message().nodes()->Get(0)));
678}
679
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800680TEST_F(ConfigurationTest, GetNodeFromHostname) {
681 FlatbufferDetachedBuffer<Configuration> config =
682 ReadConfig("aos/testdata/good_multinode.json");
683 EXPECT_EQ("pi1",
684 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
685 ->name()
686 ->string_view());
687 EXPECT_EQ("pi2", CHECK_NOTNULL(
688 GetNodeFromHostname(&config.message(), "raspberrypi2"))
689 ->name()
690 ->string_view());
691 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi3"));
692 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
693 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
694}
695
696TEST_F(ConfigurationTest, GetNodeFromHostnames) {
697 FlatbufferDetachedBuffer<Configuration> config =
698 ReadConfig("aos/testdata/good_multinode_hostnames.json");
699 EXPECT_EQ("pi1",
700 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
701 ->name()
702 ->string_view());
703 EXPECT_EQ("pi2", CHECK_NOTNULL(
704 GetNodeFromHostname(&config.message(), "raspberrypi2"))
705 ->name()
706 ->string_view());
707 EXPECT_EQ("pi2", CHECK_NOTNULL(
708 GetNodeFromHostname(&config.message(), "raspberrypi3"))
709 ->name()
710 ->string_view());
711 EXPECT_EQ("pi2", CHECK_NOTNULL(
712 GetNodeFromHostname(&config.message(), "other"))
713 ->name()
714 ->string_view());
715 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi4"));
716 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
717 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
718}
719
Austin Schuhcb108412019-10-13 16:09:54 -0700720} // namespace testing
721} // namespace configuration
722} // namespace aos