blob: e0c4dc35b146f3d61ab2ed23e7cf8365c2fb338a [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"
Austin Schuh1ef01ef2021-02-07 20:40:36 -08005#include "aos/testing/flatbuffer_eq.h"
Austin Schuhcb108412019-10-13 16:09:54 -07006#include "aos/testing/test_logging.h"
7#include "aos/util/file.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -07008#include "flatbuffers/reflection.h"
9#include "glog/logging.h"
Austin Schuhe84c3ed2019-12-14 15:29:48 -080010#include "gmock/gmock.h"
Austin Schuh1ef01ef2021-02-07 20:40:36 -080011#include "gtest/gtest.h"
Austin Schuhcb108412019-10-13 16:09:54 -070012
13namespace aos {
14namespace configuration {
15namespace testing {
16
Austin Schuh66602132020-02-28 13:38:37 -080017const std::string kConfigPrefix = "aos/testdata/";
18
Austin Schuhcb108412019-10-13 16:09:54 -070019class ConfigurationTest : public ::testing::Test {
20 public:
21 ConfigurationTest() { ::aos::testing::EnableTestLogging(); }
22};
23
24typedef ConfigurationTest ConfigurationDeathTest;
25
26// *the* expected location for all working tests.
Austin Schuh1ef01ef2021-02-07 20:40:36 -080027aos::FlatbufferDetachedBuffer<Channel> ExpectedLocation() {
28 return JsonToFlatbuffer<Channel>(
29 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5 }");
30}
31
Austin Schuhbca6cf02019-12-22 17:28:34 -080032// And for multinode setups
Austin Schuh1ef01ef2021-02-07 20:40:36 -080033aos::FlatbufferDetachedBuffer<Channel> ExpectedMultinodeLocation() {
34 return JsonToFlatbuffer<Channel>(
35 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5, "
36 "\"source_node\": \"pi1\" }");
37}
Austin Schuhcb108412019-10-13 16:09:54 -070038
39// Tests that we can read and merge a configuration.
40TEST_F(ConfigurationTest, ConfigMerge) {
Austin Schuh40485ed2019-10-26 21:51:44 -070041 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -080042 ReadConfig(kConfigPrefix + "config1.json");
Ravago Jonescf453ab2020-05-06 21:14:53 -070043 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuhcb108412019-10-13 16:09:54 -070044
45 EXPECT_EQ(
46 absl::StripSuffix(
Austin Schuh66602132020-02-28 13:38:37 -080047 util::ReadFileToStringOrDie(kConfigPrefix + "expected.json"), "\n"),
Ravago Jonescf453ab2020-05-06 21:14:53 -070048 FlatbufferToJson(config, {.multi_line = true}));
Austin Schuhcb108412019-10-13 16:09:54 -070049}
50
Austin Schuhc9e10ec2020-01-26 16:08:28 -080051// Tests that we can get back a ChannelIndex.
52TEST_F(ConfigurationTest, ChannelIndex) {
53 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -080054 ReadConfig(kConfigPrefix + "config1.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -080055
56 EXPECT_EQ(
57 ChannelIndex(&config.message(), config.message().channels()->Get(1u)),
58 1u);
59}
60
Austin Schuh217a9782019-12-21 23:02:50 -080061// Tests that we can read and merge a multinode configuration.
62TEST_F(ConfigurationTest, ConfigMergeMultinode) {
63 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -080064 ReadConfig(kConfigPrefix + "config1_multinode.json");
Ravago Jonescf453ab2020-05-06 21:14:53 -070065 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuh217a9782019-12-21 23:02:50 -080066
Ravago Jonescf453ab2020-05-06 21:14:53 -070067 EXPECT_EQ(std::string(absl::StripSuffix(
68 util::ReadFileToStringOrDie(kConfigPrefix +
69 "expected_multinode.json"),
70 "\n")),
71 FlatbufferToJson(config, {.multi_line = true}));
Austin Schuh217a9782019-12-21 23:02:50 -080072}
73
Alex Perrycb7da4b2019-08-28 19:35:56 -070074// Tests that we sort the entries in a config so we can look entries up.
75TEST_F(ConfigurationTest, UnsortedConfig) {
76 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -080077 ReadConfig(kConfigPrefix + "backwards.json");
Alex Perrycb7da4b2019-08-28 19:35:56 -070078
Ravago Jonescf453ab2020-05-06 21:14:53 -070079 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Alex Perrycb7da4b2019-08-28 19:35:56 -070080
Austin Schuhf1fff282020-03-28 16:57:32 -070081 EXPECT_EQ(FlatbufferToJson(GetChannel(config, "/aos/robot_state",
Austin Schuhbca6cf02019-12-22 17:28:34 -080082 "aos.RobotState", "app1", nullptr)),
Austin Schuhf1fff282020-03-28 16:57:32 -070083 "{ \"name\": \"/aos/robot_state\", \"type\": \"aos.RobotState\", "
Alex Perrycb7da4b2019-08-28 19:35:56 -070084 "\"max_size\": 5 }");
85}
86
Austin Schuhcb108412019-10-13 16:09:54 -070087// Tests that we die when a file is imported twice.
88TEST_F(ConfigurationDeathTest, DuplicateFile) {
89 EXPECT_DEATH(
90 {
Austin Schuh40485ed2019-10-26 21:51:44 -070091 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -080092 ReadConfig(kConfigPrefix + "config1_bad.json");
Austin Schuhcb108412019-10-13 16:09:54 -070093 },
Austin Schuh66602132020-02-28 13:38:37 -080094 kConfigPrefix + "config1_bad.json");
Austin Schuhcb108412019-10-13 16:09:54 -070095}
96
Austin Schuhf1fff282020-03-28 16:57:32 -070097// Tests that we reject invalid channel names. This means any channels with //
98// in their name, a trailing /, or regex characters.
99TEST_F(ConfigurationDeathTest, InvalidChannelName) {
100 EXPECT_DEATH(
101 {
102 FlatbufferDetachedBuffer<Configuration> config =
103 ReadConfig(kConfigPrefix + "invalid_channel_name1.json");
104 },
105 "Channel names can't end with '/'");
106 EXPECT_DEATH(
107 {
108 FlatbufferDetachedBuffer<Configuration> config =
109 ReadConfig(kConfigPrefix + "invalid_channel_name2.json");
110 },
111 "Invalid channel name");
112 EXPECT_DEATH(
113 {
114 FlatbufferDetachedBuffer<Configuration> config =
115 ReadConfig(kConfigPrefix + "invalid_channel_name3.json");
116 LOG(FATAL) << "Foo";
117 },
118 "Invalid channel name");
119}
120
Austin Schuh8d6cea82020-02-28 12:17:16 -0800121// Tests that we can modify a config with a json snippet.
122TEST_F(ConfigurationTest, MergeWithConfig) {
123 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800124 ReadConfig(kConfigPrefix + "config1.json");
Ravago Jonescf453ab2020-05-06 21:14:53 -0700125 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuh8d6cea82020-02-28 12:17:16 -0800126
127 FlatbufferDetachedBuffer<Configuration> updated_config =
128 MergeWithConfig(&config.message(),
129 R"channel({
130 "channels": [
131 {
132 "name": "/foo",
133 "type": ".aos.bar",
134 "max_size": 100
135 }
136 ]
137})channel");
138
Ravago Jonescf453ab2020-05-06 21:14:53 -0700139 EXPECT_EQ(absl::StripSuffix(util::ReadFileToStringOrDie(
140 kConfigPrefix + "expected_merge_with.json"),
141 "\n"),
142 FlatbufferToJson(updated_config, {.multi_line = true}));
Austin Schuh8d6cea82020-02-28 12:17:16 -0800143}
144
Austin Schuhcb108412019-10-13 16:09:54 -0700145// Tests that we can lookup a location, complete with maps, from a merged
146// config.
Austin Schuh40485ed2019-10-26 21:51:44 -0700147TEST_F(ConfigurationTest, GetChannel) {
148 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800149 ReadConfig(kConfigPrefix + "config1.json");
Austin Schuhcb108412019-10-13 16:09:54 -0700150
151 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800152 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", nullptr),
153 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700154
155 // Test that an invalid name results in nullptr back.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800156 EXPECT_EQ(GetChannel(config, "/invalid_name", ".aos.bar", "app1", nullptr),
157 nullptr);
Austin Schuhcb108412019-10-13 16:09:54 -0700158
159 // Tests that a root map/rename works. And that they get processed from the
160 // bottom up.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800161 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", nullptr),
162 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700163
164 // And then test that an application specific map/rename works.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800165 EXPECT_THAT(GetChannel(config, "/bar", ".aos.bar", "app1", nullptr),
166 aos::testing::FlatbufferEq(ExpectedLocation()));
167 EXPECT_THAT(GetChannel(config, "/baz", ".aos.bar", "app2", nullptr),
168 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700169
170 // And then test that an invalid application name gets properly ignored.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800171 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app3", nullptr),
172 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800173}
174
175// Tests that we can lookup a location with node specific maps.
176TEST_F(ConfigurationTest, GetChannelMultinode) {
177 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800178 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhbca6cf02019-12-22 17:28:34 -0800179 const Node *pi1 = GetNode(&config.message(), "pi1");
180 const Node *pi2 = GetNode(&config.message(), "pi2");
181
182 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800183 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", pi1),
184 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
185 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", pi2),
186 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800187
188 // Tests that a root map/rename works with a node specific map.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800189 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", pi1),
190 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800191
192 // Tests that a root map/rename fails with a node specific map for the wrong
193 // node.
194 EXPECT_EQ(GetChannel(config, "/batman", ".aos.bar", "app1", pi2), nullptr);
195
196 // And then test that an application specific map/rename works.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800197 EXPECT_THAT(GetChannel(config, "/batman2", ".aos.bar", "app1", pi1),
198 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
199 EXPECT_THAT(GetChannel(config, "/batman3", ".aos.bar", "app1", pi1),
200 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800201
202 // And then that it fails when the node changes.
203 EXPECT_EQ(GetChannel(config, "/batman3", ".aos.bar", "app1", pi2), nullptr);
204}
205
206// Tests that we can lookup a location with type specific maps.
207TEST_F(ConfigurationTest, GetChannelTypedMultinode) {
208 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800209 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhbca6cf02019-12-22 17:28:34 -0800210 const Node *pi1 = GetNode(&config.message(), "pi1");
211
212 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800213 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", pi1),
214 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800215
216 // Now confirm that a second message on the same name doesn't get remapped.
217 const char *kExpectedBazMultinodeLocation =
218 "{ \"name\": \"/batman\", \"type\": \".aos.baz\", \"max_size\": 5, "
219 "\"source_node\": \"pi1\" }";
220 EXPECT_EQ(
221 FlatbufferToJson(GetChannel(config, "/batman", ".aos.baz", "app1", pi1)),
222 kExpectedBazMultinodeLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700223}
224
Austin Schuhf1fff282020-03-28 16:57:32 -0700225// Tests that we can lookup a location with a glob
226TEST_F(ConfigurationTest, GetChannelGlob) {
227 FlatbufferDetachedBuffer<Configuration> config =
228 ReadConfig(kConfigPrefix + "good_multinode.json");
229 const Node *pi1 = GetNode(&config.message(), "pi1");
230
231 // Confirm that a glob with nothing after it matches.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800232 EXPECT_THAT(GetChannel(config, "/magic/string", ".aos.bar", "app7", pi1),
233 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhf1fff282020-03-28 16:57:32 -0700234
235 // Now confirm that glob with something following it matches and renames
236 // correctly.
237 const char *kExpectedSubfolderMultinodeLocation =
238 "{ \"name\": \"/foo/subfolder\", \"type\": \".aos.bar\", \"max_size\": "
239 "5, \"source_node\": \"pi1\" }";
240 EXPECT_EQ(FlatbufferToJson(GetChannel(config, "/magic/string/subfolder",
241 ".aos.bar", "app7", pi1)),
242 kExpectedSubfolderMultinodeLocation);
243}
244
Austin Schuh217a9782019-12-21 23:02:50 -0800245// Tests that we reject a configuration which has a nodes list, but has channels
246// withoout source_node filled out.
247TEST_F(ConfigurationDeathTest, InvalidSourceNode) {
248 EXPECT_DEATH(
249 {
250 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800251 ReadConfig(kConfigPrefix + "invalid_nodes.json");
Austin Schuh217a9782019-12-21 23:02:50 -0800252 },
253 "source_node");
254
255 EXPECT_DEATH(
256 {
257 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800258 ReadConfig(kConfigPrefix + "invalid_source_node.json");
Austin Schuh217a9782019-12-21 23:02:50 -0800259 },
260 "source_node");
261
262 EXPECT_DEATH(
263 {
264 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800265 ReadConfig(kConfigPrefix + "invalid_destination_node.json");
Austin Schuh217a9782019-12-21 23:02:50 -0800266 },
267 "destination_nodes");
268
269 EXPECT_DEATH(
270 {
271 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800272 ReadConfig(kConfigPrefix + "self_forward.json");
Austin Schuh217a9782019-12-21 23:02:50 -0800273 },
274 "forwarding data to itself");
275}
276
277// Tests that our node writeable helpers work as intended.
278TEST_F(ConfigurationTest, ChannelIsSendableOnNode) {
279 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800280 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800281 "name": "/test",
282 "type": "aos.examples.Ping",
283 "source_node": "foo"
284})channel",
285 Channel::MiniReflectTypeTable()));
286
287 FlatbufferDetachedBuffer<Channel> bad_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800288 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800289 "name": "/test",
290 "type": "aos.examples.Ping",
291 "source_node": "bar"
292})channel",
293 Channel::MiniReflectTypeTable()));
294
295 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800296 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800297 "name": "foo"
298})node",
299 Node::MiniReflectTypeTable()));
300
301 EXPECT_TRUE(
302 ChannelIsSendableOnNode(&good_channel.message(), &node.message()));
303 EXPECT_FALSE(
304 ChannelIsSendableOnNode(&bad_channel.message(), &node.message()));
305}
306
307// Tests that our node readable and writeable helpers work as intended.
308TEST_F(ConfigurationTest, ChannelIsReadableOnNode) {
309 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800310 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800311 "name": "/test",
312 "type": "aos.examples.Ping",
313 "source_node": "bar",
314 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800315 {
316 "name": "baz"
317 },
318 {
319 "name": "foo"
320 }
Austin Schuh217a9782019-12-21 23:02:50 -0800321 ]
322})channel",
323 Channel::MiniReflectTypeTable()));
324
325 FlatbufferDetachedBuffer<Channel> bad_channel1(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800326 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800327 "name": "/test",
328 "type": "aos.examples.Ping",
329 "source_node": "bar"
330})channel",
331 Channel::MiniReflectTypeTable()));
332
333 FlatbufferDetachedBuffer<Channel> bad_channel2(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800334 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800335 "name": "/test",
336 "type": "aos.examples.Ping",
337 "source_node": "bar",
338 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800339 {
340 "name": "baz"
341 }
Austin Schuh217a9782019-12-21 23:02:50 -0800342 ]
343})channel",
344 Channel::MiniReflectTypeTable()));
345
346 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800347 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800348 "name": "foo"
349})node",
350 Node::MiniReflectTypeTable()));
351
352 EXPECT_TRUE(
353 ChannelIsReadableOnNode(&good_channel.message(), &node.message()));
354 EXPECT_FALSE(
355 ChannelIsReadableOnNode(&bad_channel1.message(), &node.message()));
356 EXPECT_FALSE(
357 ChannelIsReadableOnNode(&bad_channel2.message(), &node.message()));
358}
359
Austin Schuh719946b2019-12-28 14:51:01 -0800360// Tests that our node message is logged helpers work as intended.
361TEST_F(ConfigurationTest, ChannelMessageIsLoggedOnNode) {
362 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
363 R"channel({
364 "name": "/test",
365 "type": "aos.examples.Ping",
366 "source_node": "bar",
367 "destination_nodes": [
368 {
369 "name": "baz"
370 }
371 ]
372})channel",
373 Channel::MiniReflectTypeTable()));
Austin Schuh217a9782019-12-21 23:02:50 -0800374
Austin Schuh719946b2019-12-28 14:51:01 -0800375 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
376 R"channel({
377 "name": "/test",
378 "type": "aos.examples.Ping",
379 "source_node": "bar",
380 "logger": "NOT_LOGGED",
381 "destination_nodes": [
382 {
383 "name": "baz",
384 "timestamp_logger": "LOCAL_LOGGER"
385 }
386 ]
387})channel",
388 Channel::MiniReflectTypeTable()));
389
390 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
391 R"channel({
392 "name": "/test",
393 "type": "aos.examples.Ping",
394 "source_node": "bar",
395 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700396 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800397 "destination_nodes": [
398 {
399 "name": "baz"
400 }
401 ]
402})channel",
403 Channel::MiniReflectTypeTable()));
404
405 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
406 JsonToFlatbuffer(
407 R"channel({
408 "name": "/test",
409 "type": "aos.examples.Ping",
410 "source_node": "bar",
411 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700412 "logger_nodes": ["foo"],
Austin Schuh719946b2019-12-28 14:51:01 -0800413 "destination_nodes": [
414 {
415 "name": "baz"
416 }
417 ]
418})channel",
419 Channel::MiniReflectTypeTable()));
420
Ravago Jonescf453ab2020-05-06 21:14:53 -0700421 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
422 R"channel({
Austin Schuh719946b2019-12-28 14:51:01 -0800423 "name": "/test",
424 "type": "aos.examples.Ping",
425 "source_node": "bar",
426 "logger": "LOCAL_AND_REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700427 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800428 "destination_nodes": [
429 {
430 "name": "baz"
431 }
432 ]
433})channel",
Ravago Jonescf453ab2020-05-06 21:14:53 -0700434 Channel::MiniReflectTypeTable()));
Austin Schuh719946b2019-12-28 14:51:01 -0800435
436 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
437 R"node({
438 "name": "foo"
439})node",
440 Node::MiniReflectTypeTable()));
441
442 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
443 R"node({
444 "name": "bar"
445})node",
446 Node::MiniReflectTypeTable()));
447
448 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
449 R"node({
450 "name": "baz"
451})node",
452 Node::MiniReflectTypeTable()));
453
454 // Local logger.
455 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
456 &foo_node.message()));
457 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
458 &bar_node.message()));
459 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
460 &baz_node.message()));
461
462 // No logger.
463 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
464 &foo_node.message()));
465 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
Ravago Jonescf453ab2020-05-06 21:14:53 -0700466 &bar_node.message()));
Austin Schuh719946b2019-12-28 14:51:01 -0800467 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
468 &baz_node.message()));
469
470 // Remote logger.
471 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
472 &foo_node.message()));
473 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
474 &bar_node.message()));
475 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
476 &baz_node.message()));
477
478 // Separate logger.
479 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(
480 &logged_on_separate_logger_node_channel.message(), &foo_node.message()));
481 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
482 &logged_on_separate_logger_node_channel.message(), &bar_node.message()));
483 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
484 &logged_on_separate_logger_node_channel.message(), &baz_node.message()));
485
486 // Logged in multiple places.
487 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
488 &foo_node.message()));
489 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
490 &bar_node.message()));
491 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
492 &baz_node.message()));
493}
494
495// Tests that our forwarding timestamps are logged helpers work as intended.
496TEST_F(ConfigurationTest, ConnectionDeliveryTimeIsLoggedOnNode) {
497 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
498 R"channel({
499 "name": "/test",
500 "type": "aos.examples.Ping",
501 "source_node": "bar",
502 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700503 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800504 "destination_nodes": [
505 {
506 "name": "baz"
507 }
508 ]
509})channel",
510 Channel::MiniReflectTypeTable()));
511
512 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
513 R"channel({
514 "name": "/test",
515 "type": "aos.examples.Ping",
516 "source_node": "bar",
517 "logger": "NOT_LOGGED",
518 "destination_nodes": [
519 {
520 "name": "baz",
521 "timestamp_logger": "NOT_LOGGED"
522 }
523 ]
524})channel",
525 Channel::MiniReflectTypeTable()));
526
527 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
528 R"channel({
529 "name": "/test",
530 "type": "aos.examples.Ping",
531 "source_node": "bar",
532 "destination_nodes": [
533 {
534 "name": "baz",
535 "timestamp_logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700536 "timestamp_logger_nodes": ["bar"]
Austin Schuh719946b2019-12-28 14:51:01 -0800537 }
538 ]
539})channel",
540 Channel::MiniReflectTypeTable()));
541
542 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
543 JsonToFlatbuffer(
544 R"channel({
545 "name": "/test",
546 "type": "aos.examples.Ping",
547 "source_node": "bar",
548 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700549 "logger_nodes": ["foo"],
Austin Schuh719946b2019-12-28 14:51:01 -0800550 "destination_nodes": [
551 {
552 "name": "baz",
553 "timestamp_logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700554 "timestamp_logger_nodes": ["foo"]
Austin Schuh719946b2019-12-28 14:51:01 -0800555 }
556 ]
557})channel",
558 Channel::MiniReflectTypeTable()));
559
Ravago Jonescf453ab2020-05-06 21:14:53 -0700560 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
561 R"channel({
Austin Schuh719946b2019-12-28 14:51:01 -0800562 "name": "/test",
563 "type": "aos.examples.Ping",
564 "source_node": "bar",
565 "destination_nodes": [
566 {
567 "name": "baz",
568 "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700569 "timestamp_logger_nodes": ["bar"]
Austin Schuh719946b2019-12-28 14:51:01 -0800570 }
571 ]
572})channel",
Ravago Jonescf453ab2020-05-06 21:14:53 -0700573 Channel::MiniReflectTypeTable()));
Austin Schuh719946b2019-12-28 14:51:01 -0800574
575 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
576 R"node({
577 "name": "foo"
578})node",
579 Node::MiniReflectTypeTable()));
580
581 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
582 R"node({
583 "name": "bar"
584})node",
585 Node::MiniReflectTypeTable()));
586
587 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
588 R"node({
589 "name": "baz"
590})node",
591 Node::MiniReflectTypeTable()));
592
593 // Local logger.
594 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
595 &logged_on_self_channel.message(), &baz_node.message(),
596 &foo_node.message()));
597 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
598 &logged_on_self_channel.message(), &baz_node.message(),
599 &bar_node.message()));
600 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
601 &logged_on_self_channel.message(), &baz_node.message(),
602 &baz_node.message()));
603
604 // No logger means.
605 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
606 &not_logged_channel.message(), &baz_node.message(), &foo_node.message()));
607 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
608 &not_logged_channel.message(), &baz_node.message(), &bar_node.message()));
609 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
610 &not_logged_channel.message(), &baz_node.message(), &baz_node.message()));
611
612 // Remote logger.
613 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
614 &logged_on_remote_channel.message(), &baz_node.message(),
615 &foo_node.message()));
616 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
617 &logged_on_remote_channel.message(), &baz_node.message(),
618 &bar_node.message()));
619 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
620 &logged_on_remote_channel.message(), &baz_node.message(),
621 &baz_node.message()));
622
623 // Separate logger.
624 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
625 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
626 &foo_node.message()));
627 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
628 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
629 &bar_node.message()));
630 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
631 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
632 &baz_node.message()));
633
634 // Logged on both the node and a remote node.
635 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
636 &logged_on_both_channel.message(), &baz_node.message(),
637 &foo_node.message()));
638 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
639 &logged_on_both_channel.message(), &baz_node.message(),
640 &bar_node.message()));
641 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
642 &logged_on_both_channel.message(), &baz_node.message(),
643 &baz_node.message()));
644}
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800645
646// Tests that we can deduce source nodes from a multinode config.
647TEST_F(ConfigurationTest, SourceNodeNames) {
648 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800649 ReadConfig(kConfigPrefix + "config1_multinode.json");
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800650
651 // This is a bit simplistic in that it doesn't test deduplication, but it does
652 // exercise a lot of the logic.
653 EXPECT_THAT(
654 SourceNodeNames(&config.message(), config.message().nodes()->Get(0)),
655 ::testing::ElementsAreArray({"pi2"}));
656 EXPECT_THAT(
657 SourceNodeNames(&config.message(), config.message().nodes()->Get(1)),
658 ::testing::ElementsAreArray({"pi1"}));
659}
660
661// Tests that we can deduce destination nodes from a multinode config.
662TEST_F(ConfigurationTest, DestinationNodeNames) {
663 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800664 ReadConfig(kConfigPrefix + "config1_multinode.json");
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800665
666 // This is a bit simplistic in that it doesn't test deduplication, but it does
667 // exercise a lot of the logic.
668 EXPECT_THAT(
669 DestinationNodeNames(&config.message(), config.message().nodes()->Get(0)),
670 ::testing::ElementsAreArray({"pi2"}));
671 EXPECT_THAT(
672 DestinationNodeNames(&config.message(), config.message().nodes()->Get(1)),
673 ::testing::ElementsAreArray({"pi1"}));
674}
675
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800676// Tests that we can pull out all the nodes.
677TEST_F(ConfigurationTest, GetNodes) {
678 {
679 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800680 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800681 const Node *pi1 = GetNode(&config.message(), "pi1");
682 const Node *pi2 = GetNode(&config.message(), "pi2");
683
684 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(pi1, pi2));
685 }
686
687 {
688 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800689 ReadConfig(kConfigPrefix + "config1.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800690 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(nullptr));
691 }
692}
693
Austin Schuh65465332020-11-05 17:36:53 -0800694// Tests that we can pull out all the nodes with a tag.
695TEST_F(ConfigurationTest, GetNodesWithTag) {
696 {
697 FlatbufferDetachedBuffer<Configuration> config =
698 ReadConfig(kConfigPrefix + "good_multinode.json");
699 const Node *pi1 = GetNode(&config.message(), "pi1");
700 const Node *pi2 = GetNode(&config.message(), "pi2");
701
702 EXPECT_THAT(GetNodesWithTag(&config.message(), "a"),
703 ::testing::ElementsAre(pi1));
704 EXPECT_THAT(GetNodesWithTag(&config.message(), "b"),
705 ::testing::ElementsAre(pi2));
706 EXPECT_THAT(GetNodesWithTag(&config.message(), "c"),
707 ::testing::ElementsAre(pi1, pi2));
708 }
709
710 {
711 FlatbufferDetachedBuffer<Configuration> config =
712 ReadConfig(kConfigPrefix + "config1.json");
713 EXPECT_THAT(GetNodesWithTag(&config.message(), "arglfish"),
714 ::testing::ElementsAre(nullptr));
715 }
716}
717
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800718// Tests that we can extract a node index from a config.
719TEST_F(ConfigurationTest, GetNodeIndex) {
720 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800721 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuh04408fc2020-02-16 21:48:54 -0800722 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh66602132020-02-28 13:38:37 -0800723 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800724 const Node *pi1 = GetNode(&config.message(), "pi1");
725 const Node *pi2 = GetNode(&config.message(), "pi2");
726
Austin Schuh04408fc2020-02-16 21:48:54 -0800727 // Try the normal case.
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800728 EXPECT_EQ(GetNodeIndex(&config.message(), pi1), 0);
729 EXPECT_EQ(GetNodeIndex(&config.message(), pi2), 1);
Austin Schuh04408fc2020-02-16 21:48:54 -0800730
731 // Now try if we have node pointers from a different message.
732 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1), 0);
733 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2), 1);
734
735 // And now try string names.
736 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1->name()->string_view()), 0);
737 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2->name()->string_view()), 1);
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800738}
739
740// Tests that GetNodeOrDie handles both single and multi-node worlds and returns
741// valid nodes.
742TEST_F(ConfigurationDeathTest, GetNodeOrDie) {
743 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800744 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800745 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh66602132020-02-28 13:38:37 -0800746 ReadConfig(kConfigPrefix + "good_multinode.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800747 {
748 // Simple case, nullptr -> nullptr
749 FlatbufferDetachedBuffer<Configuration> single_node_config =
Austin Schuh66602132020-02-28 13:38:37 -0800750 ReadConfig(kConfigPrefix + "config1.json");
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800751 EXPECT_EQ(nullptr, GetNodeOrDie(&single_node_config.message(), nullptr));
752
753 // Confirm that we die when a node is passed in.
754 EXPECT_DEATH(
755 {
756 GetNodeOrDie(&single_node_config.message(),
757 config.message().nodes()->Get(0));
758 },
759 "Provided a node in a single node world.");
760 }
761
762 const Node *pi1 = GetNode(&config.message(), "pi1");
763 // Now try a lookup using a node from a different instance of the config.
764 EXPECT_EQ(pi1,
765 GetNodeOrDie(&config.message(), config2.message().nodes()->Get(0)));
766}
767
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800768TEST_F(ConfigurationTest, GetNodeFromHostname) {
769 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800770 ReadConfig(kConfigPrefix + "good_multinode.json");
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800771 EXPECT_EQ("pi1",
772 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
773 ->name()
774 ->string_view());
775 EXPECT_EQ("pi2", CHECK_NOTNULL(
776 GetNodeFromHostname(&config.message(), "raspberrypi2"))
777 ->name()
778 ->string_view());
779 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi3"));
780 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
781 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
782}
783
784TEST_F(ConfigurationTest, GetNodeFromHostnames) {
785 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh66602132020-02-28 13:38:37 -0800786 ReadConfig(kConfigPrefix + "good_multinode_hostnames.json");
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800787 EXPECT_EQ("pi1",
788 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
789 ->name()
790 ->string_view());
791 EXPECT_EQ("pi2", CHECK_NOTNULL(
792 GetNodeFromHostname(&config.message(), "raspberrypi2"))
793 ->name()
794 ->string_view());
795 EXPECT_EQ("pi2", CHECK_NOTNULL(
796 GetNodeFromHostname(&config.message(), "raspberrypi3"))
797 ->name()
798 ->string_view());
Ravago Jonescf453ab2020-05-06 21:14:53 -0700799 EXPECT_EQ("pi2",
800 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "other"))
801 ->name()
802 ->string_view());
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800803 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi4"));
804 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
805 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
806}
807
Austin Schuhcb108412019-10-13 16:09:54 -0700808} // namespace testing
809} // namespace configuration
810} // namespace aos