blob: aa6de8e3c5fc2232d1ce694fcdb2d1bed57a916d [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
Austin Schuhf1fff282020-03-28 16:57:32 -070074 EXPECT_EQ(FlatbufferToJson(GetChannel(config, "/aos/robot_state",
Austin Schuhbca6cf02019-12-22 17:28:34 -080075 "aos.RobotState", "app1", nullptr)),
Austin Schuhf1fff282020-03-28 16:57:32 -070076 "{ \"name\": \"/aos/robot_state\", \"type\": \"aos.RobotState\", "
Alex Perrycb7da4b2019-08-28 19:35:56 -070077 "\"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 Schuhf1fff282020-03-28 16:57:32 -070090// Tests that we reject invalid channel names. This means any channels with //
91// in their name, a trailing /, or regex characters.
92TEST_F(ConfigurationDeathTest, InvalidChannelName) {
93 EXPECT_DEATH(
94 {
95 FlatbufferDetachedBuffer<Configuration> config =
96 ReadConfig(kConfigPrefix + "invalid_channel_name1.json");
97 },
98 "Channel names can't end with '/'");
99 EXPECT_DEATH(
100 {
101 FlatbufferDetachedBuffer<Configuration> config =
102 ReadConfig(kConfigPrefix + "invalid_channel_name2.json");
103 },
104 "Invalid channel name");
105 EXPECT_DEATH(
106 {
107 FlatbufferDetachedBuffer<Configuration> config =
108 ReadConfig(kConfigPrefix + "invalid_channel_name3.json");
109 LOG(FATAL) << "Foo";
110 },
111 "Invalid channel name");
112}
113
Austin Schuh8d6cea82020-02-28 12:17:16 -0800114// Tests that we can modify a config with a json snippet.
115TEST_F(ConfigurationTest, MergeWithConfig) {
116 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800117 ReadConfig(kConfigPrefix + "config1.json");
Austin Schuh8d6cea82020-02-28 12:17:16 -0800118 LOG(INFO) << "Read: " << FlatbufferToJson(config, true);
119
120 FlatbufferDetachedBuffer<Configuration> updated_config =
121 MergeWithConfig(&config.message(),
122 R"channel({
123 "channels": [
124 {
125 "name": "/foo",
126 "type": ".aos.bar",
127 "max_size": 100
128 }
129 ]
130})channel");
131
132 EXPECT_EQ(
133 absl::StripSuffix(util::ReadFileToStringOrDie(
Austin Schuh66602132020-02-28 13:38:37 -0800134 kConfigPrefix + "expected_merge_with.json"),
Austin Schuh8d6cea82020-02-28 12:17:16 -0800135 "\n"),
136 FlatbufferToJson(updated_config, true));
137}
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.
190 EXPECT_EQ(FlatbufferToJson(
191 GetChannel(config, "/batman", ".aos.bar", "app1", pi1)),
192 kExpectedMultinodeLocation);
193
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
430 FlatbufferDetachedBuffer<Channel> logged_on_both_channel (
431 JsonToFlatbuffer(
432 R"channel({
433 "name": "/test",
434 "type": "aos.examples.Ping",
435 "source_node": "bar",
436 "logger": "LOCAL_AND_REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700437 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800438 "destination_nodes": [
439 {
440 "name": "baz"
441 }
442 ]
443})channel",
444 Channel::MiniReflectTypeTable()));
445
446 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
447 R"node({
448 "name": "foo"
449})node",
450 Node::MiniReflectTypeTable()));
451
452 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
453 R"node({
454 "name": "bar"
455})node",
456 Node::MiniReflectTypeTable()));
457
458 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
459 R"node({
460 "name": "baz"
461})node",
462 Node::MiniReflectTypeTable()));
463
464 // Local logger.
465 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
466 &foo_node.message()));
467 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
468 &bar_node.message()));
469 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
470 &baz_node.message()));
471
472 // No logger.
473 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
474 &foo_node.message()));
475 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
476 &bar_node.message()));
477 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
478 &baz_node.message()));
479
480 // Remote logger.
481 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
482 &foo_node.message()));
483 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
484 &bar_node.message()));
485 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
486 &baz_node.message()));
487
488 // Separate logger.
489 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(
490 &logged_on_separate_logger_node_channel.message(), &foo_node.message()));
491 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
492 &logged_on_separate_logger_node_channel.message(), &bar_node.message()));
493 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
494 &logged_on_separate_logger_node_channel.message(), &baz_node.message()));
495
496 // Logged in multiple places.
497 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
498 &foo_node.message()));
499 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
500 &bar_node.message()));
501 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
502 &baz_node.message()));
503}
504
505// Tests that our forwarding timestamps are logged helpers work as intended.
506TEST_F(ConfigurationTest, ConnectionDeliveryTimeIsLoggedOnNode) {
507 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
508 R"channel({
509 "name": "/test",
510 "type": "aos.examples.Ping",
511 "source_node": "bar",
512 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700513 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800514 "destination_nodes": [
515 {
516 "name": "baz"
517 }
518 ]
519})channel",
520 Channel::MiniReflectTypeTable()));
521
522 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
523 R"channel({
524 "name": "/test",
525 "type": "aos.examples.Ping",
526 "source_node": "bar",
527 "logger": "NOT_LOGGED",
528 "destination_nodes": [
529 {
530 "name": "baz",
531 "timestamp_logger": "NOT_LOGGED"
532 }
533 ]
534})channel",
535 Channel::MiniReflectTypeTable()));
536
537 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
538 R"channel({
539 "name": "/test",
540 "type": "aos.examples.Ping",
541 "source_node": "bar",
542 "destination_nodes": [
543 {
544 "name": "baz",
545 "timestamp_logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700546 "timestamp_logger_nodes": ["bar"]
Austin Schuh719946b2019-12-28 14:51:01 -0800547 }
548 ]
549})channel",
550 Channel::MiniReflectTypeTable()));
551
552 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
553 JsonToFlatbuffer(
554 R"channel({
555 "name": "/test",
556 "type": "aos.examples.Ping",
557 "source_node": "bar",
558 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700559 "logger_nodes": ["foo"],
Austin Schuh719946b2019-12-28 14:51:01 -0800560 "destination_nodes": [
561 {
562 "name": "baz",
563 "timestamp_logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700564 "timestamp_logger_nodes": ["foo"]
Austin Schuh719946b2019-12-28 14:51:01 -0800565 }
566 ]
567})channel",
568 Channel::MiniReflectTypeTable()));
569
570 FlatbufferDetachedBuffer<Channel> logged_on_both_channel (
571 JsonToFlatbuffer(
572 R"channel({
573 "name": "/test",
574 "type": "aos.examples.Ping",
575 "source_node": "bar",
576 "destination_nodes": [
577 {
578 "name": "baz",
579 "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700580 "timestamp_logger_nodes": ["bar"]
Austin Schuh719946b2019-12-28 14:51:01 -0800581 }
582 ]
583})channel",
584 Channel::MiniReflectTypeTable()));
585
586 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
587 R"node({
588 "name": "foo"
589})node",
590 Node::MiniReflectTypeTable()));
591
592 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
593 R"node({
594 "name": "bar"
595})node",
596 Node::MiniReflectTypeTable()));
597
598 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
599 R"node({
600 "name": "baz"
601})node",
602 Node::MiniReflectTypeTable()));
603
604 // Local logger.
605 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
606 &logged_on_self_channel.message(), &baz_node.message(),
607 &foo_node.message()));
608 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
609 &logged_on_self_channel.message(), &baz_node.message(),
610 &bar_node.message()));
611 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
612 &logged_on_self_channel.message(), &baz_node.message(),
613 &baz_node.message()));
614
615 // No logger means.
616 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
617 &not_logged_channel.message(), &baz_node.message(), &foo_node.message()));
618 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
619 &not_logged_channel.message(), &baz_node.message(), &bar_node.message()));
620 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
621 &not_logged_channel.message(), &baz_node.message(), &baz_node.message()));
622
623 // Remote logger.
624 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
625 &logged_on_remote_channel.message(), &baz_node.message(),
626 &foo_node.message()));
627 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
628 &logged_on_remote_channel.message(), &baz_node.message(),
629 &bar_node.message()));
630 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
631 &logged_on_remote_channel.message(), &baz_node.message(),
632 &baz_node.message()));
633
634 // Separate logger.
635 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
636 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
637 &foo_node.message()));
638 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
639 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
640 &bar_node.message()));
641 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
642 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
643 &baz_node.message()));
644
645 // Logged on both the node and a remote node.
646 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
647 &logged_on_both_channel.message(), &baz_node.message(),
648 &foo_node.message()));
649 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
650 &logged_on_both_channel.message(), &baz_node.message(),
651 &bar_node.message()));
652 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
653 &logged_on_both_channel.message(), &baz_node.message(),
654 &baz_node.message()));
655}
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800656
657// Tests that we can deduce source nodes from a multinode config.
658TEST_F(ConfigurationTest, SourceNodeNames) {
659 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800660 ReadConfig(kConfigPrefix + "config1_multinode.json");
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800661
662 // This is a bit simplistic in that it doesn't test deduplication, but it does
663 // exercise a lot of the logic.
664 EXPECT_THAT(
665 SourceNodeNames(&config.message(), config.message().nodes()->Get(0)),
666 ::testing::ElementsAreArray({"pi2"}));
667 EXPECT_THAT(
668 SourceNodeNames(&config.message(), config.message().nodes()->Get(1)),
669 ::testing::ElementsAreArray({"pi1"}));
670}
671
672// Tests that we can deduce destination nodes from a multinode config.
673TEST_F(ConfigurationTest, DestinationNodeNames) {
674 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800675 ReadConfig(kConfigPrefix + "config1_multinode.json");
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800676
677 // This is a bit simplistic in that it doesn't test deduplication, but it does
678 // exercise a lot of the logic.
679 EXPECT_THAT(
680 DestinationNodeNames(&config.message(), config.message().nodes()->Get(0)),
681 ::testing::ElementsAreArray({"pi2"}));
682 EXPECT_THAT(
683 DestinationNodeNames(&config.message(), config.message().nodes()->Get(1)),
684 ::testing::ElementsAreArray({"pi1"}));
685}
686
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800687// Tests that we can pull out all the nodes.
688TEST_F(ConfigurationTest, GetNodes) {
689 {
690 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800691 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800692 const Node *pi1 = GetNode(&config.message(), "pi1");
693 const Node *pi2 = GetNode(&config.message(), "pi2");
694
695 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(pi1, pi2));
696 }
697
698 {
699 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800700 ReadConfig(kConfigPrefix + "config1.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800701 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(nullptr));
702 }
703}
704
705// Tests that we can extract a node index from a config.
706TEST_F(ConfigurationTest, GetNodeIndex) {
707 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800708 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuh04408fc2020-02-16 21:48:54 -0800709 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh66602132020-02-28 13:38:37 -0800710 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800711 const Node *pi1 = GetNode(&config.message(), "pi1");
712 const Node *pi2 = GetNode(&config.message(), "pi2");
713
Austin Schuh04408fc2020-02-16 21:48:54 -0800714 // Try the normal case.
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800715 EXPECT_EQ(GetNodeIndex(&config.message(), pi1), 0);
716 EXPECT_EQ(GetNodeIndex(&config.message(), pi2), 1);
Austin Schuh04408fc2020-02-16 21:48:54 -0800717
718 // Now try if we have node pointers from a different message.
719 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1), 0);
720 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2), 1);
721
722 // And now try string names.
723 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1->name()->string_view()), 0);
724 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2->name()->string_view()), 1);
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800725}
726
727// Tests that GetNodeOrDie handles both single and multi-node worlds and returns
728// valid nodes.
729TEST_F(ConfigurationDeathTest, GetNodeOrDie) {
730 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800731 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800732 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh66602132020-02-28 13:38:37 -0800733 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800734 {
735 // Simple case, nullptr -> nullptr
736 FlatbufferDetachedBuffer<Configuration> single_node_config =
Austin Schuh66602132020-02-28 13:38:37 -0800737 ReadConfig(kConfigPrefix + "config1.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800738 EXPECT_EQ(nullptr, GetNodeOrDie(&single_node_config.message(), nullptr));
739
740 // Confirm that we die when a node is passed in.
741 EXPECT_DEATH(
742 {
743 GetNodeOrDie(&single_node_config.message(),
744 config.message().nodes()->Get(0));
745 },
746 "Provided a node in a single node world.");
747 }
748
749 const Node *pi1 = GetNode(&config.message(), "pi1");
750 // Now try a lookup using a node from a different instance of the config.
751 EXPECT_EQ(pi1,
752 GetNodeOrDie(&config.message(), config2.message().nodes()->Get(0)));
753}
754
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800755TEST_F(ConfigurationTest, GetNodeFromHostname) {
756 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800757 ReadConfig(kConfigPrefix + "good_multinode.json");
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800758 EXPECT_EQ("pi1",
759 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
760 ->name()
761 ->string_view());
762 EXPECT_EQ("pi2", CHECK_NOTNULL(
763 GetNodeFromHostname(&config.message(), "raspberrypi2"))
764 ->name()
765 ->string_view());
766 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi3"));
767 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
768 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
769}
770
771TEST_F(ConfigurationTest, GetNodeFromHostnames) {
772 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800773 ReadConfig(kConfigPrefix + "good_multinode_hostnames.json");
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800774 EXPECT_EQ("pi1",
775 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
776 ->name()
777 ->string_view());
778 EXPECT_EQ("pi2", CHECK_NOTNULL(
779 GetNodeFromHostname(&config.message(), "raspberrypi2"))
780 ->name()
781 ->string_view());
782 EXPECT_EQ("pi2", CHECK_NOTNULL(
783 GetNodeFromHostname(&config.message(), "raspberrypi3"))
784 ->name()
785 ->string_view());
786 EXPECT_EQ("pi2", CHECK_NOTNULL(
787 GetNodeFromHostname(&config.message(), "other"))
788 ->name()
789 ->string_view());
790 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi4"));
791 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
792 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
793}
794
Austin Schuhcb108412019-10-13 16:09:54 -0700795} // namespace testing
796} // namespace configuration
797} // namespace aos