blob: f069277279abc73c07a68a149349802c47b48628 [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 =
30 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5, \"source_node\": \"pi1\" }";
Austin Schuhcb108412019-10-13 16:09:54 -070031
32// Tests that we can read and merge a configuration.
33TEST_F(ConfigurationTest, ConfigMerge) {
Austin Schuh40485ed2019-10-26 21:51:44 -070034 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -080035 ReadConfig(kConfigPrefix + "config1.json");
Alex Perrycb7da4b2019-08-28 19:35:56 -070036 LOG(INFO) << "Read: " << FlatbufferToJson(config, true);
Austin Schuhcb108412019-10-13 16:09:54 -070037
38 EXPECT_EQ(
39 absl::StripSuffix(
Austin Schuh66602132020-02-28 13:38:37 -080040 util::ReadFileToStringOrDie(kConfigPrefix + "expected.json"), "\n"),
Austin Schuhcb108412019-10-13 16:09:54 -070041 FlatbufferToJson(config, true));
42}
43
Austin Schuhc9e10ec2020-01-26 16:08:28 -080044// Tests that we can get back a ChannelIndex.
45TEST_F(ConfigurationTest, ChannelIndex) {
46 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -080047 ReadConfig(kConfigPrefix + "config1.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -080048
49 EXPECT_EQ(
50 ChannelIndex(&config.message(), config.message().channels()->Get(1u)),
51 1u);
52}
53
Austin Schuh217a9782019-12-21 23:02:50 -080054// Tests that we can read and merge a multinode configuration.
55TEST_F(ConfigurationTest, ConfigMergeMultinode) {
56 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -080057 ReadConfig(kConfigPrefix + "config1_multinode.json");
Austin Schuh217a9782019-12-21 23:02:50 -080058 LOG(INFO) << "Read: " << FlatbufferToJson(config, true);
59
60 EXPECT_EQ(
61 std::string(absl::StripSuffix(
Austin Schuh66602132020-02-28 13:38:37 -080062 util::ReadFileToStringOrDie(kConfigPrefix + "expected_multinode.json"),
Austin Schuh217a9782019-12-21 23:02:50 -080063 "\n")),
64 FlatbufferToJson(config, true));
65}
66
Alex Perrycb7da4b2019-08-28 19:35:56 -070067// Tests that we sort the entries in a config so we can look entries up.
68TEST_F(ConfigurationTest, UnsortedConfig) {
69 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -080070 ReadConfig(kConfigPrefix + "backwards.json");
Alex Perrycb7da4b2019-08-28 19:35:56 -070071
72 LOG(INFO) << "Read: " << FlatbufferToJson(config, true);
73
74 EXPECT_EQ(FlatbufferToJson(GetChannel(config, ".aos.robot_state",
Austin Schuhbca6cf02019-12-22 17:28:34 -080075 "aos.RobotState", "app1", nullptr)),
Alex Perrycb7da4b2019-08-28 19:35:56 -070076 "{ \"name\": \".aos.robot_state\", \"type\": \"aos.RobotState\", "
77 "\"max_size\": 5 }");
78}
79
Austin Schuhcb108412019-10-13 16:09:54 -070080// Tests that we die when a file is imported twice.
81TEST_F(ConfigurationDeathTest, DuplicateFile) {
82 EXPECT_DEATH(
83 {
Austin Schuh40485ed2019-10-26 21:51:44 -070084 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -080085 ReadConfig(kConfigPrefix + "config1_bad.json");
Austin Schuhcb108412019-10-13 16:09:54 -070086 },
Austin Schuh66602132020-02-28 13:38:37 -080087 kConfigPrefix + "config1_bad.json");
Austin Schuhcb108412019-10-13 16:09:54 -070088}
89
Austin Schuh8d6cea82020-02-28 12:17:16 -080090// Tests that we can modify a config with a json snippet.
91TEST_F(ConfigurationTest, MergeWithConfig) {
92 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -080093 ReadConfig(kConfigPrefix + "config1.json");
Austin Schuh8d6cea82020-02-28 12:17:16 -080094 LOG(INFO) << "Read: " << FlatbufferToJson(config, true);
95
96 FlatbufferDetachedBuffer<Configuration> updated_config =
97 MergeWithConfig(&config.message(),
98 R"channel({
99 "channels": [
100 {
101 "name": "/foo",
102 "type": ".aos.bar",
103 "max_size": 100
104 }
105 ]
106})channel");
107
108 EXPECT_EQ(
109 absl::StripSuffix(util::ReadFileToStringOrDie(
Austin Schuh66602132020-02-28 13:38:37 -0800110 kConfigPrefix + "expected_merge_with.json"),
Austin Schuh8d6cea82020-02-28 12:17:16 -0800111 "\n"),
112 FlatbufferToJson(updated_config, true));
113}
114
Austin Schuhcb108412019-10-13 16:09:54 -0700115// Tests that we can lookup a location, complete with maps, from a merged
116// config.
Austin Schuh40485ed2019-10-26 21:51:44 -0700117TEST_F(ConfigurationTest, GetChannel) {
118 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800119 ReadConfig(kConfigPrefix + "config1.json");
Austin Schuhcb108412019-10-13 16:09:54 -0700120
121 // Test a basic lookup first.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800122 EXPECT_EQ(
123 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", nullptr)),
124 kExpectedLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700125
126 // Test that an invalid name results in nullptr back.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800127 EXPECT_EQ(GetChannel(config, "/invalid_name", ".aos.bar", "app1", nullptr),
128 nullptr);
Austin Schuhcb108412019-10-13 16:09:54 -0700129
130 // Tests that a root map/rename works. And that they get processed from the
131 // bottom up.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800132 EXPECT_EQ(FlatbufferToJson(
133 GetChannel(config, "/batman", ".aos.bar", "app1", nullptr)),
134 kExpectedLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700135
136 // And then test that an application specific map/rename works.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800137 EXPECT_EQ(
138 FlatbufferToJson(GetChannel(config, "/bar", ".aos.bar", "app1", nullptr)),
139 kExpectedLocation);
140 EXPECT_EQ(
141 FlatbufferToJson(GetChannel(config, "/baz", ".aos.bar", "app2", nullptr)),
142 kExpectedLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700143
144 // And then test that an invalid application name gets properly ignored.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800145 EXPECT_EQ(
146 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app3", nullptr)),
147 kExpectedLocation);
148}
149
150// Tests that we can lookup a location with node specific maps.
151TEST_F(ConfigurationTest, GetChannelMultinode) {
152 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800153 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhbca6cf02019-12-22 17:28:34 -0800154 const Node *pi1 = GetNode(&config.message(), "pi1");
155 const Node *pi2 = GetNode(&config.message(), "pi2");
156
157 // Test a basic lookup first.
158 EXPECT_EQ(
159 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", pi1)),
160 kExpectedMultinodeLocation);
161 EXPECT_EQ(
162 FlatbufferToJson(GetChannel(config, "/foo", ".aos.bar", "app1", pi2)),
163 kExpectedMultinodeLocation);
164
165 // Tests that a root map/rename works with a node specific map.
166 EXPECT_EQ(FlatbufferToJson(
167 GetChannel(config, "/batman", ".aos.bar", "app1", pi1)),
168 kExpectedMultinodeLocation);
169
170 // Tests that a root map/rename fails with a node specific map for the wrong
171 // node.
172 EXPECT_EQ(GetChannel(config, "/batman", ".aos.bar", "app1", pi2), nullptr);
173
174 // And then test that an application specific map/rename works.
175 EXPECT_EQ(
176 FlatbufferToJson(GetChannel(config, "/batman2", ".aos.bar", "app1", pi1)),
177 kExpectedMultinodeLocation);
178 EXPECT_EQ(
179 FlatbufferToJson(GetChannel(config, "/batman3", ".aos.bar", "app1", pi1)),
180 kExpectedMultinodeLocation);
181
182 // And then that it fails when the node changes.
183 EXPECT_EQ(GetChannel(config, "/batman3", ".aos.bar", "app1", pi2), nullptr);
184}
185
186// Tests that we can lookup a location with type specific maps.
187TEST_F(ConfigurationTest, GetChannelTypedMultinode) {
188 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800189 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhbca6cf02019-12-22 17:28:34 -0800190 const Node *pi1 = GetNode(&config.message(), "pi1");
191
192 // Test a basic lookup first.
193 EXPECT_EQ(
194 FlatbufferToJson(GetChannel(config, "/batman", ".aos.bar", "app1", pi1)),
195 kExpectedMultinodeLocation);
196
197 // Now confirm that a second message on the same name doesn't get remapped.
198 const char *kExpectedBazMultinodeLocation =
199 "{ \"name\": \"/batman\", \"type\": \".aos.baz\", \"max_size\": 5, "
200 "\"source_node\": \"pi1\" }";
201 EXPECT_EQ(
202 FlatbufferToJson(GetChannel(config, "/batman", ".aos.baz", "app1", pi1)),
203 kExpectedBazMultinodeLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700204}
205
Austin Schuh217a9782019-12-21 23:02:50 -0800206// Tests that we reject a configuration which has a nodes list, but has channels
207// withoout source_node filled out.
208TEST_F(ConfigurationDeathTest, InvalidSourceNode) {
209 EXPECT_DEATH(
210 {
211 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800212 ReadConfig(kConfigPrefix + "invalid_nodes.json");
Austin Schuh217a9782019-12-21 23:02:50 -0800213 },
214 "source_node");
215
216 EXPECT_DEATH(
217 {
218 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800219 ReadConfig(kConfigPrefix + "invalid_source_node.json");
Austin Schuh217a9782019-12-21 23:02:50 -0800220 },
221 "source_node");
222
223 EXPECT_DEATH(
224 {
225 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800226 ReadConfig(kConfigPrefix + "invalid_destination_node.json");
Austin Schuh217a9782019-12-21 23:02:50 -0800227 },
228 "destination_nodes");
229
230 EXPECT_DEATH(
231 {
232 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800233 ReadConfig(kConfigPrefix + "self_forward.json");
Austin Schuh217a9782019-12-21 23:02:50 -0800234 },
235 "forwarding data to itself");
236}
237
238// Tests that our node writeable helpers work as intended.
239TEST_F(ConfigurationTest, ChannelIsSendableOnNode) {
240 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800241 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800242 "name": "/test",
243 "type": "aos.examples.Ping",
244 "source_node": "foo"
245})channel",
246 Channel::MiniReflectTypeTable()));
247
248 FlatbufferDetachedBuffer<Channel> bad_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800249 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800250 "name": "/test",
251 "type": "aos.examples.Ping",
252 "source_node": "bar"
253})channel",
254 Channel::MiniReflectTypeTable()));
255
256 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800257 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800258 "name": "foo"
259})node",
260 Node::MiniReflectTypeTable()));
261
262 EXPECT_TRUE(
263 ChannelIsSendableOnNode(&good_channel.message(), &node.message()));
264 EXPECT_FALSE(
265 ChannelIsSendableOnNode(&bad_channel.message(), &node.message()));
266}
267
268// Tests that our node readable and writeable helpers work as intended.
269TEST_F(ConfigurationTest, ChannelIsReadableOnNode) {
270 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800271 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800272 "name": "/test",
273 "type": "aos.examples.Ping",
274 "source_node": "bar",
275 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800276 {
277 "name": "baz"
278 },
279 {
280 "name": "foo"
281 }
Austin Schuh217a9782019-12-21 23:02:50 -0800282 ]
283})channel",
284 Channel::MiniReflectTypeTable()));
285
286 FlatbufferDetachedBuffer<Channel> bad_channel1(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800287 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800288 "name": "/test",
289 "type": "aos.examples.Ping",
290 "source_node": "bar"
291})channel",
292 Channel::MiniReflectTypeTable()));
293
294 FlatbufferDetachedBuffer<Channel> bad_channel2(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800295 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800296 "name": "/test",
297 "type": "aos.examples.Ping",
298 "source_node": "bar",
299 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800300 {
301 "name": "baz"
302 }
Austin Schuh217a9782019-12-21 23:02:50 -0800303 ]
304})channel",
305 Channel::MiniReflectTypeTable()));
306
307 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800308 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800309 "name": "foo"
310})node",
311 Node::MiniReflectTypeTable()));
312
313 EXPECT_TRUE(
314 ChannelIsReadableOnNode(&good_channel.message(), &node.message()));
315 EXPECT_FALSE(
316 ChannelIsReadableOnNode(&bad_channel1.message(), &node.message()));
317 EXPECT_FALSE(
318 ChannelIsReadableOnNode(&bad_channel2.message(), &node.message()));
319}
320
Austin Schuh719946b2019-12-28 14:51:01 -0800321// Tests that our node message is logged helpers work as intended.
322TEST_F(ConfigurationTest, ChannelMessageIsLoggedOnNode) {
323 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
324 R"channel({
325 "name": "/test",
326 "type": "aos.examples.Ping",
327 "source_node": "bar",
328 "destination_nodes": [
329 {
330 "name": "baz"
331 }
332 ]
333})channel",
334 Channel::MiniReflectTypeTable()));
Austin Schuh217a9782019-12-21 23:02:50 -0800335
Austin Schuh719946b2019-12-28 14:51:01 -0800336 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
337 R"channel({
338 "name": "/test",
339 "type": "aos.examples.Ping",
340 "source_node": "bar",
341 "logger": "NOT_LOGGED",
342 "destination_nodes": [
343 {
344 "name": "baz",
345 "timestamp_logger": "LOCAL_LOGGER"
346 }
347 ]
348})channel",
349 Channel::MiniReflectTypeTable()));
350
351 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
352 R"channel({
353 "name": "/test",
354 "type": "aos.examples.Ping",
355 "source_node": "bar",
356 "logger": "REMOTE_LOGGER",
357 "logger_node": "baz",
358 "destination_nodes": [
359 {
360 "name": "baz"
361 }
362 ]
363})channel",
364 Channel::MiniReflectTypeTable()));
365
366 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
367 JsonToFlatbuffer(
368 R"channel({
369 "name": "/test",
370 "type": "aos.examples.Ping",
371 "source_node": "bar",
372 "logger": "REMOTE_LOGGER",
373 "logger_node": "foo",
374 "destination_nodes": [
375 {
376 "name": "baz"
377 }
378 ]
379})channel",
380 Channel::MiniReflectTypeTable()));
381
382 FlatbufferDetachedBuffer<Channel> logged_on_both_channel (
383 JsonToFlatbuffer(
384 R"channel({
385 "name": "/test",
386 "type": "aos.examples.Ping",
387 "source_node": "bar",
388 "logger": "LOCAL_AND_REMOTE_LOGGER",
389 "logger_node": "baz",
390 "destination_nodes": [
391 {
392 "name": "baz"
393 }
394 ]
395})channel",
396 Channel::MiniReflectTypeTable()));
397
398 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
399 R"node({
400 "name": "foo"
401})node",
402 Node::MiniReflectTypeTable()));
403
404 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
405 R"node({
406 "name": "bar"
407})node",
408 Node::MiniReflectTypeTable()));
409
410 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
411 R"node({
412 "name": "baz"
413})node",
414 Node::MiniReflectTypeTable()));
415
416 // Local logger.
417 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
418 &foo_node.message()));
419 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
420 &bar_node.message()));
421 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
422 &baz_node.message()));
423
424 // No logger.
425 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
426 &foo_node.message()));
427 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
428 &bar_node.message()));
429 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
430 &baz_node.message()));
431
432 // Remote logger.
433 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
434 &foo_node.message()));
435 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
436 &bar_node.message()));
437 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
438 &baz_node.message()));
439
440 // Separate logger.
441 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(
442 &logged_on_separate_logger_node_channel.message(), &foo_node.message()));
443 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
444 &logged_on_separate_logger_node_channel.message(), &bar_node.message()));
445 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
446 &logged_on_separate_logger_node_channel.message(), &baz_node.message()));
447
448 // Logged in multiple places.
449 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
450 &foo_node.message()));
451 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
452 &bar_node.message()));
453 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
454 &baz_node.message()));
455}
456
457// Tests that our forwarding timestamps are logged helpers work as intended.
458TEST_F(ConfigurationTest, ConnectionDeliveryTimeIsLoggedOnNode) {
459 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
460 R"channel({
461 "name": "/test",
462 "type": "aos.examples.Ping",
463 "source_node": "bar",
464 "logger": "REMOTE_LOGGER",
465 "logger_node": "baz",
466 "destination_nodes": [
467 {
468 "name": "baz"
469 }
470 ]
471})channel",
472 Channel::MiniReflectTypeTable()));
473
474 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
475 R"channel({
476 "name": "/test",
477 "type": "aos.examples.Ping",
478 "source_node": "bar",
479 "logger": "NOT_LOGGED",
480 "destination_nodes": [
481 {
482 "name": "baz",
483 "timestamp_logger": "NOT_LOGGED"
484 }
485 ]
486})channel",
487 Channel::MiniReflectTypeTable()));
488
489 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
490 R"channel({
491 "name": "/test",
492 "type": "aos.examples.Ping",
493 "source_node": "bar",
494 "destination_nodes": [
495 {
496 "name": "baz",
497 "timestamp_logger": "REMOTE_LOGGER",
498 "timestamp_logger_node": "bar"
499 }
500 ]
501})channel",
502 Channel::MiniReflectTypeTable()));
503
504 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
505 JsonToFlatbuffer(
506 R"channel({
507 "name": "/test",
508 "type": "aos.examples.Ping",
509 "source_node": "bar",
510 "logger": "REMOTE_LOGGER",
511 "logger_node": "foo",
512 "destination_nodes": [
513 {
514 "name": "baz",
515 "timestamp_logger": "REMOTE_LOGGER",
516 "timestamp_logger_node": "foo"
517 }
518 ]
519})channel",
520 Channel::MiniReflectTypeTable()));
521
522 FlatbufferDetachedBuffer<Channel> logged_on_both_channel (
523 JsonToFlatbuffer(
524 R"channel({
525 "name": "/test",
526 "type": "aos.examples.Ping",
527 "source_node": "bar",
528 "destination_nodes": [
529 {
530 "name": "baz",
531 "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
532 "timestamp_logger_node": "bar"
533 }
534 ]
535})channel",
536 Channel::MiniReflectTypeTable()));
537
538 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
539 R"node({
540 "name": "foo"
541})node",
542 Node::MiniReflectTypeTable()));
543
544 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
545 R"node({
546 "name": "bar"
547})node",
548 Node::MiniReflectTypeTable()));
549
550 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
551 R"node({
552 "name": "baz"
553})node",
554 Node::MiniReflectTypeTable()));
555
556 // Local logger.
557 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
558 &logged_on_self_channel.message(), &baz_node.message(),
559 &foo_node.message()));
560 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
561 &logged_on_self_channel.message(), &baz_node.message(),
562 &bar_node.message()));
563 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
564 &logged_on_self_channel.message(), &baz_node.message(),
565 &baz_node.message()));
566
567 // No logger means.
568 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
569 &not_logged_channel.message(), &baz_node.message(), &foo_node.message()));
570 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
571 &not_logged_channel.message(), &baz_node.message(), &bar_node.message()));
572 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
573 &not_logged_channel.message(), &baz_node.message(), &baz_node.message()));
574
575 // Remote logger.
576 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
577 &logged_on_remote_channel.message(), &baz_node.message(),
578 &foo_node.message()));
579 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
580 &logged_on_remote_channel.message(), &baz_node.message(),
581 &bar_node.message()));
582 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
583 &logged_on_remote_channel.message(), &baz_node.message(),
584 &baz_node.message()));
585
586 // Separate logger.
587 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
588 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
589 &foo_node.message()));
590 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
591 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
592 &bar_node.message()));
593 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
594 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
595 &baz_node.message()));
596
597 // Logged on both the node and a remote node.
598 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
599 &logged_on_both_channel.message(), &baz_node.message(),
600 &foo_node.message()));
601 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
602 &logged_on_both_channel.message(), &baz_node.message(),
603 &bar_node.message()));
604 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
605 &logged_on_both_channel.message(), &baz_node.message(),
606 &baz_node.message()));
607}
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800608
609// Tests that we can deduce source nodes from a multinode config.
610TEST_F(ConfigurationTest, SourceNodeNames) {
611 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800612 ReadConfig(kConfigPrefix + "config1_multinode.json");
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800613
614 // This is a bit simplistic in that it doesn't test deduplication, but it does
615 // exercise a lot of the logic.
616 EXPECT_THAT(
617 SourceNodeNames(&config.message(), config.message().nodes()->Get(0)),
618 ::testing::ElementsAreArray({"pi2"}));
619 EXPECT_THAT(
620 SourceNodeNames(&config.message(), config.message().nodes()->Get(1)),
621 ::testing::ElementsAreArray({"pi1"}));
622}
623
624// Tests that we can deduce destination nodes from a multinode config.
625TEST_F(ConfigurationTest, DestinationNodeNames) {
626 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800627 ReadConfig(kConfigPrefix + "config1_multinode.json");
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800628
629 // This is a bit simplistic in that it doesn't test deduplication, but it does
630 // exercise a lot of the logic.
631 EXPECT_THAT(
632 DestinationNodeNames(&config.message(), config.message().nodes()->Get(0)),
633 ::testing::ElementsAreArray({"pi2"}));
634 EXPECT_THAT(
635 DestinationNodeNames(&config.message(), config.message().nodes()->Get(1)),
636 ::testing::ElementsAreArray({"pi1"}));
637}
638
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800639// Tests that we can pull out all the nodes.
640TEST_F(ConfigurationTest, GetNodes) {
641 {
642 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800643 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800644 const Node *pi1 = GetNode(&config.message(), "pi1");
645 const Node *pi2 = GetNode(&config.message(), "pi2");
646
647 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(pi1, pi2));
648 }
649
650 {
651 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800652 ReadConfig(kConfigPrefix + "config1.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800653 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(nullptr));
654 }
655}
656
657// Tests that we can extract a node index from a config.
658TEST_F(ConfigurationTest, GetNodeIndex) {
659 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800660 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuh04408fc2020-02-16 21:48:54 -0800661 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh66602132020-02-28 13:38:37 -0800662 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800663 const Node *pi1 = GetNode(&config.message(), "pi1");
664 const Node *pi2 = GetNode(&config.message(), "pi2");
665
Austin Schuh04408fc2020-02-16 21:48:54 -0800666 // Try the normal case.
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800667 EXPECT_EQ(GetNodeIndex(&config.message(), pi1), 0);
668 EXPECT_EQ(GetNodeIndex(&config.message(), pi2), 1);
Austin Schuh04408fc2020-02-16 21:48:54 -0800669
670 // Now try if we have node pointers from a different message.
671 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1), 0);
672 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2), 1);
673
674 // And now try string names.
675 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1->name()->string_view()), 0);
676 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2->name()->string_view()), 1);
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800677}
678
679// Tests that GetNodeOrDie handles both single and multi-node worlds and returns
680// valid nodes.
681TEST_F(ConfigurationDeathTest, GetNodeOrDie) {
682 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800683 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800684 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh66602132020-02-28 13:38:37 -0800685 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800686 {
687 // Simple case, nullptr -> nullptr
688 FlatbufferDetachedBuffer<Configuration> single_node_config =
Austin Schuh66602132020-02-28 13:38:37 -0800689 ReadConfig(kConfigPrefix + "config1.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800690 EXPECT_EQ(nullptr, GetNodeOrDie(&single_node_config.message(), nullptr));
691
692 // Confirm that we die when a node is passed in.
693 EXPECT_DEATH(
694 {
695 GetNodeOrDie(&single_node_config.message(),
696 config.message().nodes()->Get(0));
697 },
698 "Provided a node in a single node world.");
699 }
700
701 const Node *pi1 = GetNode(&config.message(), "pi1");
702 // Now try a lookup using a node from a different instance of the config.
703 EXPECT_EQ(pi1,
704 GetNodeOrDie(&config.message(), config2.message().nodes()->Get(0)));
705}
706
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800707TEST_F(ConfigurationTest, GetNodeFromHostname) {
708 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800709 ReadConfig(kConfigPrefix + "good_multinode.json");
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800710 EXPECT_EQ("pi1",
711 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
712 ->name()
713 ->string_view());
714 EXPECT_EQ("pi2", CHECK_NOTNULL(
715 GetNodeFromHostname(&config.message(), "raspberrypi2"))
716 ->name()
717 ->string_view());
718 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi3"));
719 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
720 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
721}
722
723TEST_F(ConfigurationTest, GetNodeFromHostnames) {
724 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800725 ReadConfig(kConfigPrefix + "good_multinode_hostnames.json");
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800726 EXPECT_EQ("pi1",
727 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
728 ->name()
729 ->string_view());
730 EXPECT_EQ("pi2", CHECK_NOTNULL(
731 GetNodeFromHostname(&config.message(), "raspberrypi2"))
732 ->name()
733 ->string_view());
734 EXPECT_EQ("pi2", CHECK_NOTNULL(
735 GetNodeFromHostname(&config.message(), "raspberrypi3"))
736 ->name()
737 ->string_view());
738 EXPECT_EQ("pi2", CHECK_NOTNULL(
739 GetNodeFromHostname(&config.message(), "other"))
740 ->name()
741 ->string_view());
742 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi4"));
743 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
744 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
745}
746
Austin Schuhcb108412019-10-13 16:09:54 -0700747} // namespace testing
748} // namespace configuration
749} // namespace aos