blob: 891dedb531ce81ef6ac9283a7e29603c1eaacded [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 Schuh373f1762021-06-02 21:07:09 -07006#include "aos/testing/path.h"
Austin Schuhcb108412019-10-13 16:09:54 -07007#include "aos/testing/test_logging.h"
8#include "aos/util/file.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -07009#include "flatbuffers/reflection.h"
10#include "glog/logging.h"
Austin Schuhe84c3ed2019-12-14 15:29:48 -080011#include "gmock/gmock.h"
Austin Schuh1ef01ef2021-02-07 20:40:36 -080012#include "gtest/gtest.h"
Austin Schuhcb108412019-10-13 16:09:54 -070013
14namespace aos {
15namespace configuration {
16namespace testing {
17
Austin Schuh373f1762021-06-02 21:07:09 -070018using aos::testing::ArtifactPath;
Austin Schuh66602132020-02-28 13:38:37 -080019
Austin Schuhcb108412019-10-13 16:09:54 -070020class ConfigurationTest : public ::testing::Test {
21 public:
22 ConfigurationTest() { ::aos::testing::EnableTestLogging(); }
23};
24
25typedef ConfigurationTest ConfigurationDeathTest;
26
27// *the* expected location for all working tests.
Austin Schuh1ef01ef2021-02-07 20:40:36 -080028aos::FlatbufferDetachedBuffer<Channel> ExpectedLocation() {
29 return JsonToFlatbuffer<Channel>(
30 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5 }");
31}
32
Austin Schuhbca6cf02019-12-22 17:28:34 -080033// And for multinode setups
Austin Schuh1ef01ef2021-02-07 20:40:36 -080034aos::FlatbufferDetachedBuffer<Channel> ExpectedMultinodeLocation() {
35 return JsonToFlatbuffer<Channel>(
36 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5, "
37 "\"source_node\": \"pi1\" }");
38}
Austin Schuhcb108412019-10-13 16:09:54 -070039
40// Tests that we can read and merge a configuration.
41TEST_F(ConfigurationTest, ConfigMerge) {
Austin Schuh40485ed2019-10-26 21:51:44 -070042 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070043 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Ravago Jonescf453ab2020-05-06 21:14:53 -070044 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuhcb108412019-10-13 16:09:54 -070045
Austin Schuh373f1762021-06-02 21:07:09 -070046 EXPECT_EQ(absl::StripSuffix(util::ReadFileToStringOrDie(
47 ArtifactPath("aos/testdata/expected.json")),
48 "\n"),
49 FlatbufferToJson(config, {.multi_line = true}));
Austin Schuhcb108412019-10-13 16:09:54 -070050}
51
Austin Schuhc9e10ec2020-01-26 16:08:28 -080052// Tests that we can get back a ChannelIndex.
53TEST_F(ConfigurationTest, ChannelIndex) {
54 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070055 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -080056
57 EXPECT_EQ(
58 ChannelIndex(&config.message(), config.message().channels()->Get(1u)),
59 1u);
60}
61
Austin Schuh217a9782019-12-21 23:02:50 -080062// Tests that we can read and merge a multinode configuration.
63TEST_F(ConfigurationTest, ConfigMergeMultinode) {
64 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070065 ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
Ravago Jonescf453ab2020-05-06 21:14:53 -070066 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuh217a9782019-12-21 23:02:50 -080067
Ravago Jonescf453ab2020-05-06 21:14:53 -070068 EXPECT_EQ(std::string(absl::StripSuffix(
Austin Schuh373f1762021-06-02 21:07:09 -070069 util::ReadFileToStringOrDie(
70 ArtifactPath("aos/testdata/expected_multinode.json")),
Ravago Jonescf453ab2020-05-06 21:14:53 -070071 "\n")),
72 FlatbufferToJson(config, {.multi_line = true}));
Austin Schuh217a9782019-12-21 23:02:50 -080073}
74
Alex Perrycb7da4b2019-08-28 19:35:56 -070075// Tests that we sort the entries in a config so we can look entries up.
76TEST_F(ConfigurationTest, UnsortedConfig) {
77 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070078 ReadConfig(ArtifactPath("aos/testdata/backwards.json"));
Alex Perrycb7da4b2019-08-28 19:35:56 -070079
Ravago Jonescf453ab2020-05-06 21:14:53 -070080 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Alex Perrycb7da4b2019-08-28 19:35:56 -070081
Austin Schuhf1fff282020-03-28 16:57:32 -070082 EXPECT_EQ(FlatbufferToJson(GetChannel(config, "/aos/robot_state",
Austin Schuhbca6cf02019-12-22 17:28:34 -080083 "aos.RobotState", "app1", nullptr)),
Austin Schuhf1fff282020-03-28 16:57:32 -070084 "{ \"name\": \"/aos/robot_state\", \"type\": \"aos.RobotState\", "
Alex Perrycb7da4b2019-08-28 19:35:56 -070085 "\"max_size\": 5 }");
86}
87
Austin Schuhcb108412019-10-13 16:09:54 -070088// Tests that we die when a file is imported twice.
89TEST_F(ConfigurationDeathTest, DuplicateFile) {
90 EXPECT_DEATH(
91 {
Austin Schuh40485ed2019-10-26 21:51:44 -070092 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070093 ReadConfig(ArtifactPath("aos/testdata/config1_bad.json"));
Austin Schuhcb108412019-10-13 16:09:54 -070094 },
Austin Schuh373f1762021-06-02 21:07:09 -070095 "aos/testdata/config1_bad.json");
Austin Schuhcb108412019-10-13 16:09:54 -070096}
97
Austin Schuhf1fff282020-03-28 16:57:32 -070098// Tests that we reject invalid channel names. This means any channels with //
99// in their name, a trailing /, or regex characters.
100TEST_F(ConfigurationDeathTest, InvalidChannelName) {
101 EXPECT_DEATH(
102 {
103 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700104 ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name1.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700105 },
106 "Channel names can't end with '/'");
107 EXPECT_DEATH(
108 {
109 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700110 ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name2.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700111 },
112 "Invalid channel name");
113 EXPECT_DEATH(
114 {
115 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700116 ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name3.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700117 LOG(FATAL) << "Foo";
118 },
119 "Invalid channel name");
120}
121
Austin Schuh8d6cea82020-02-28 12:17:16 -0800122// Tests that we can modify a config with a json snippet.
123TEST_F(ConfigurationTest, MergeWithConfig) {
124 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700125 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Ravago Jonescf453ab2020-05-06 21:14:53 -0700126 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuh8d6cea82020-02-28 12:17:16 -0800127
128 FlatbufferDetachedBuffer<Configuration> updated_config =
129 MergeWithConfig(&config.message(),
130 R"channel({
131 "channels": [
132 {
133 "name": "/foo",
134 "type": ".aos.bar",
135 "max_size": 100
136 }
137 ]
138})channel");
139
Austin Schuh373f1762021-06-02 21:07:09 -0700140 EXPECT_EQ(absl::StripSuffix(util::ReadFileToStringOrDie(ArtifactPath(
141 "aos/testdata/expected_merge_with.json")),
Ravago Jonescf453ab2020-05-06 21:14:53 -0700142 "\n"),
143 FlatbufferToJson(updated_config, {.multi_line = true}));
Austin Schuh8d6cea82020-02-28 12:17:16 -0800144}
145
Austin Schuhcb108412019-10-13 16:09:54 -0700146// Tests that we can lookup a location, complete with maps, from a merged
147// config.
Austin Schuh40485ed2019-10-26 21:51:44 -0700148TEST_F(ConfigurationTest, GetChannel) {
149 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700150 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhcb108412019-10-13 16:09:54 -0700151
152 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800153 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", nullptr),
154 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700155
156 // Test that an invalid name results in nullptr back.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800157 EXPECT_EQ(GetChannel(config, "/invalid_name", ".aos.bar", "app1", nullptr),
158 nullptr);
Austin Schuhcb108412019-10-13 16:09:54 -0700159
160 // Tests that a root map/rename works. And that they get processed from the
161 // bottom up.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800162 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", nullptr),
163 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700164
165 // And then test that an application specific map/rename works.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800166 EXPECT_THAT(GetChannel(config, "/bar", ".aos.bar", "app1", nullptr),
167 aos::testing::FlatbufferEq(ExpectedLocation()));
168 EXPECT_THAT(GetChannel(config, "/baz", ".aos.bar", "app2", nullptr),
169 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700170
171 // And then test that an invalid application name gets properly ignored.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800172 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app3", nullptr),
173 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800174}
175
176// Tests that we can lookup a location with node specific maps.
177TEST_F(ConfigurationTest, GetChannelMultinode) {
178 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700179 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800180 const Node *pi1 = GetNode(&config.message(), "pi1");
181 const Node *pi2 = GetNode(&config.message(), "pi2");
182
183 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800184 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", pi1),
185 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
186 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", pi2),
187 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800188
189 // Tests that a root map/rename works with a node specific map.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800190 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", pi1),
191 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800192
193 // Tests that a root map/rename fails with a node specific map for the wrong
194 // node.
195 EXPECT_EQ(GetChannel(config, "/batman", ".aos.bar", "app1", pi2), nullptr);
196
197 // And then test that an application specific map/rename works.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800198 EXPECT_THAT(GetChannel(config, "/batman2", ".aos.bar", "app1", pi1),
199 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
200 EXPECT_THAT(GetChannel(config, "/batman3", ".aos.bar", "app1", pi1),
201 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800202
203 // And then that it fails when the node changes.
204 EXPECT_EQ(GetChannel(config, "/batman3", ".aos.bar", "app1", pi2), nullptr);
205}
206
207// Tests that we can lookup a location with type specific maps.
208TEST_F(ConfigurationTest, GetChannelTypedMultinode) {
209 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700210 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800211 const Node *pi1 = GetNode(&config.message(), "pi1");
212
213 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800214 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", pi1),
215 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800216
217 // Now confirm that a second message on the same name doesn't get remapped.
218 const char *kExpectedBazMultinodeLocation =
219 "{ \"name\": \"/batman\", \"type\": \".aos.baz\", \"max_size\": 5, "
220 "\"source_node\": \"pi1\" }";
221 EXPECT_EQ(
222 FlatbufferToJson(GetChannel(config, "/batman", ".aos.baz", "app1", pi1)),
223 kExpectedBazMultinodeLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700224}
225
Austin Schuhf1fff282020-03-28 16:57:32 -0700226// Tests that we can lookup a location with a glob
227TEST_F(ConfigurationTest, GetChannelGlob) {
228 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700229 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700230 const Node *pi1 = GetNode(&config.message(), "pi1");
231
232 // Confirm that a glob with nothing after it matches.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800233 EXPECT_THAT(GetChannel(config, "/magic/string", ".aos.bar", "app7", pi1),
234 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhf1fff282020-03-28 16:57:32 -0700235
236 // Now confirm that glob with something following it matches and renames
237 // correctly.
238 const char *kExpectedSubfolderMultinodeLocation =
239 "{ \"name\": \"/foo/subfolder\", \"type\": \".aos.bar\", \"max_size\": "
240 "5, \"source_node\": \"pi1\" }";
241 EXPECT_EQ(FlatbufferToJson(GetChannel(config, "/magic/string/subfolder",
242 ".aos.bar", "app7", pi1)),
243 kExpectedSubfolderMultinodeLocation);
244}
245
Austin Schuh217a9782019-12-21 23:02:50 -0800246// Tests that we reject a configuration which has a nodes list, but has channels
247// withoout source_node filled out.
248TEST_F(ConfigurationDeathTest, InvalidSourceNode) {
249 EXPECT_DEATH(
250 {
251 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700252 ReadConfig(ArtifactPath("aos/testdata/invalid_nodes.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800253 },
254 "source_node");
255
256 EXPECT_DEATH(
257 {
258 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700259 ReadConfig(ArtifactPath("aos/testdata/invalid_source_node.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800260 },
261 "source_node");
262
263 EXPECT_DEATH(
264 {
Austin Schuh373f1762021-06-02 21:07:09 -0700265 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
266 ArtifactPath("aos/testdata/invalid_destination_node.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800267 },
268 "destination_nodes");
269
270 EXPECT_DEATH(
271 {
272 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700273 ReadConfig(ArtifactPath("aos/testdata/self_forward.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800274 },
275 "forwarding data to itself");
276}
277
278// Tests that our node writeable helpers work as intended.
279TEST_F(ConfigurationTest, ChannelIsSendableOnNode) {
280 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800281 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800282 "name": "/test",
283 "type": "aos.examples.Ping",
284 "source_node": "foo"
285})channel",
286 Channel::MiniReflectTypeTable()));
287
288 FlatbufferDetachedBuffer<Channel> bad_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": "bar"
293})channel",
294 Channel::MiniReflectTypeTable()));
295
296 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800297 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800298 "name": "foo"
299})node",
300 Node::MiniReflectTypeTable()));
301
302 EXPECT_TRUE(
303 ChannelIsSendableOnNode(&good_channel.message(), &node.message()));
304 EXPECT_FALSE(
305 ChannelIsSendableOnNode(&bad_channel.message(), &node.message()));
306}
307
308// Tests that our node readable and writeable helpers work as intended.
309TEST_F(ConfigurationTest, ChannelIsReadableOnNode) {
310 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800311 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800312 "name": "/test",
313 "type": "aos.examples.Ping",
314 "source_node": "bar",
315 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800316 {
317 "name": "baz"
318 },
319 {
320 "name": "foo"
321 }
Austin Schuh217a9782019-12-21 23:02:50 -0800322 ]
323})channel",
324 Channel::MiniReflectTypeTable()));
325
326 FlatbufferDetachedBuffer<Channel> bad_channel1(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800327 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800328 "name": "/test",
329 "type": "aos.examples.Ping",
330 "source_node": "bar"
331})channel",
332 Channel::MiniReflectTypeTable()));
333
334 FlatbufferDetachedBuffer<Channel> bad_channel2(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 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800340 {
341 "name": "baz"
342 }
Austin Schuh217a9782019-12-21 23:02:50 -0800343 ]
344})channel",
345 Channel::MiniReflectTypeTable()));
346
347 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800348 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800349 "name": "foo"
350})node",
351 Node::MiniReflectTypeTable()));
352
353 EXPECT_TRUE(
354 ChannelIsReadableOnNode(&good_channel.message(), &node.message()));
355 EXPECT_FALSE(
356 ChannelIsReadableOnNode(&bad_channel1.message(), &node.message()));
357 EXPECT_FALSE(
358 ChannelIsReadableOnNode(&bad_channel2.message(), &node.message()));
359}
360
Austin Schuh719946b2019-12-28 14:51:01 -0800361// Tests that our node message is logged helpers work as intended.
362TEST_F(ConfigurationTest, ChannelMessageIsLoggedOnNode) {
363 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
364 R"channel({
365 "name": "/test",
366 "type": "aos.examples.Ping",
367 "source_node": "bar",
368 "destination_nodes": [
369 {
370 "name": "baz"
371 }
372 ]
373})channel",
374 Channel::MiniReflectTypeTable()));
Austin Schuh217a9782019-12-21 23:02:50 -0800375
Austin Schuh719946b2019-12-28 14:51:01 -0800376 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
377 R"channel({
378 "name": "/test",
379 "type": "aos.examples.Ping",
380 "source_node": "bar",
381 "logger": "NOT_LOGGED",
382 "destination_nodes": [
383 {
384 "name": "baz",
385 "timestamp_logger": "LOCAL_LOGGER"
386 }
387 ]
388})channel",
389 Channel::MiniReflectTypeTable()));
390
391 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
392 R"channel({
393 "name": "/test",
394 "type": "aos.examples.Ping",
395 "source_node": "bar",
396 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700397 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800398 "destination_nodes": [
399 {
400 "name": "baz"
401 }
402 ]
403})channel",
404 Channel::MiniReflectTypeTable()));
405
406 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
407 JsonToFlatbuffer(
408 R"channel({
409 "name": "/test",
410 "type": "aos.examples.Ping",
411 "source_node": "bar",
412 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700413 "logger_nodes": ["foo"],
Austin Schuh719946b2019-12-28 14:51:01 -0800414 "destination_nodes": [
415 {
416 "name": "baz"
417 }
418 ]
419})channel",
420 Channel::MiniReflectTypeTable()));
421
Ravago Jonescf453ab2020-05-06 21:14:53 -0700422 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
423 R"channel({
Austin Schuh719946b2019-12-28 14:51:01 -0800424 "name": "/test",
425 "type": "aos.examples.Ping",
426 "source_node": "bar",
427 "logger": "LOCAL_AND_REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700428 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800429 "destination_nodes": [
430 {
431 "name": "baz"
432 }
433 ]
434})channel",
Ravago Jonescf453ab2020-05-06 21:14:53 -0700435 Channel::MiniReflectTypeTable()));
Austin Schuh719946b2019-12-28 14:51:01 -0800436
437 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
438 R"node({
439 "name": "foo"
440})node",
441 Node::MiniReflectTypeTable()));
442
443 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
444 R"node({
445 "name": "bar"
446})node",
447 Node::MiniReflectTypeTable()));
448
449 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
450 R"node({
451 "name": "baz"
452})node",
453 Node::MiniReflectTypeTable()));
454
455 // Local logger.
456 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
457 &foo_node.message()));
458 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
459 &bar_node.message()));
460 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
461 &baz_node.message()));
462
463 // No logger.
464 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
465 &foo_node.message()));
466 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
Ravago Jonescf453ab2020-05-06 21:14:53 -0700467 &bar_node.message()));
Austin Schuh719946b2019-12-28 14:51:01 -0800468 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
469 &baz_node.message()));
470
471 // Remote logger.
472 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
473 &foo_node.message()));
474 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
475 &bar_node.message()));
476 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
477 &baz_node.message()));
478
479 // Separate logger.
480 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(
481 &logged_on_separate_logger_node_channel.message(), &foo_node.message()));
482 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
483 &logged_on_separate_logger_node_channel.message(), &bar_node.message()));
484 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
485 &logged_on_separate_logger_node_channel.message(), &baz_node.message()));
486
487 // Logged in multiple places.
488 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
489 &foo_node.message()));
490 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
491 &bar_node.message()));
492 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
493 &baz_node.message()));
494}
495
496// Tests that our forwarding timestamps are logged helpers work as intended.
497TEST_F(ConfigurationTest, ConnectionDeliveryTimeIsLoggedOnNode) {
498 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
499 R"channel({
500 "name": "/test",
501 "type": "aos.examples.Ping",
502 "source_node": "bar",
503 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700504 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800505 "destination_nodes": [
506 {
507 "name": "baz"
508 }
509 ]
510})channel",
511 Channel::MiniReflectTypeTable()));
512
513 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
514 R"channel({
515 "name": "/test",
516 "type": "aos.examples.Ping",
517 "source_node": "bar",
518 "logger": "NOT_LOGGED",
519 "destination_nodes": [
520 {
521 "name": "baz",
522 "timestamp_logger": "NOT_LOGGED"
523 }
524 ]
525})channel",
526 Channel::MiniReflectTypeTable()));
527
528 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
529 R"channel({
530 "name": "/test",
531 "type": "aos.examples.Ping",
532 "source_node": "bar",
533 "destination_nodes": [
534 {
535 "name": "baz",
536 "timestamp_logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700537 "timestamp_logger_nodes": ["bar"]
Austin Schuh719946b2019-12-28 14:51:01 -0800538 }
539 ]
540})channel",
541 Channel::MiniReflectTypeTable()));
542
543 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
544 JsonToFlatbuffer(
545 R"channel({
546 "name": "/test",
547 "type": "aos.examples.Ping",
548 "source_node": "bar",
549 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700550 "logger_nodes": ["foo"],
Austin Schuh719946b2019-12-28 14:51:01 -0800551 "destination_nodes": [
552 {
553 "name": "baz",
554 "timestamp_logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700555 "timestamp_logger_nodes": ["foo"]
Austin Schuh719946b2019-12-28 14:51:01 -0800556 }
557 ]
558})channel",
559 Channel::MiniReflectTypeTable()));
560
Ravago Jonescf453ab2020-05-06 21:14:53 -0700561 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
562 R"channel({
Austin Schuh719946b2019-12-28 14:51:01 -0800563 "name": "/test",
564 "type": "aos.examples.Ping",
565 "source_node": "bar",
566 "destination_nodes": [
567 {
568 "name": "baz",
569 "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700570 "timestamp_logger_nodes": ["bar"]
Austin Schuh719946b2019-12-28 14:51:01 -0800571 }
572 ]
573})channel",
Ravago Jonescf453ab2020-05-06 21:14:53 -0700574 Channel::MiniReflectTypeTable()));
Austin Schuh719946b2019-12-28 14:51:01 -0800575
576 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
577 R"node({
578 "name": "foo"
579})node",
580 Node::MiniReflectTypeTable()));
581
582 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
583 R"node({
584 "name": "bar"
585})node",
586 Node::MiniReflectTypeTable()));
587
588 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
589 R"node({
590 "name": "baz"
591})node",
592 Node::MiniReflectTypeTable()));
593
594 // Local logger.
595 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
596 &logged_on_self_channel.message(), &baz_node.message(),
597 &foo_node.message()));
598 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
599 &logged_on_self_channel.message(), &baz_node.message(),
600 &bar_node.message()));
601 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
602 &logged_on_self_channel.message(), &baz_node.message(),
603 &baz_node.message()));
604
605 // No logger means.
606 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
607 &not_logged_channel.message(), &baz_node.message(), &foo_node.message()));
608 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
609 &not_logged_channel.message(), &baz_node.message(), &bar_node.message()));
610 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
611 &not_logged_channel.message(), &baz_node.message(), &baz_node.message()));
612
613 // Remote logger.
614 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
615 &logged_on_remote_channel.message(), &baz_node.message(),
616 &foo_node.message()));
617 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
618 &logged_on_remote_channel.message(), &baz_node.message(),
619 &bar_node.message()));
620 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
621 &logged_on_remote_channel.message(), &baz_node.message(),
622 &baz_node.message()));
623
624 // Separate logger.
625 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
626 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
627 &foo_node.message()));
628 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
629 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
630 &bar_node.message()));
631 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
632 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
633 &baz_node.message()));
634
635 // Logged on both the node and a remote node.
636 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
637 &logged_on_both_channel.message(), &baz_node.message(),
638 &foo_node.message()));
639 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
640 &logged_on_both_channel.message(), &baz_node.message(),
641 &bar_node.message()));
642 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
643 &logged_on_both_channel.message(), &baz_node.message(),
644 &baz_node.message()));
645}
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800646
647// Tests that we can deduce source nodes from a multinode config.
648TEST_F(ConfigurationTest, SourceNodeNames) {
649 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700650 ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800651
652 // This is a bit simplistic in that it doesn't test deduplication, but it does
653 // exercise a lot of the logic.
654 EXPECT_THAT(
655 SourceNodeNames(&config.message(), config.message().nodes()->Get(0)),
656 ::testing::ElementsAreArray({"pi2"}));
657 EXPECT_THAT(
658 SourceNodeNames(&config.message(), config.message().nodes()->Get(1)),
659 ::testing::ElementsAreArray({"pi1"}));
660}
661
662// Tests that we can deduce destination nodes from a multinode config.
663TEST_F(ConfigurationTest, DestinationNodeNames) {
664 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700665 ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800666
667 // This is a bit simplistic in that it doesn't test deduplication, but it does
668 // exercise a lot of the logic.
669 EXPECT_THAT(
670 DestinationNodeNames(&config.message(), config.message().nodes()->Get(0)),
671 ::testing::ElementsAreArray({"pi2"}));
672 EXPECT_THAT(
673 DestinationNodeNames(&config.message(), config.message().nodes()->Get(1)),
674 ::testing::ElementsAreArray({"pi1"}));
675}
676
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800677// Tests that we can pull out all the nodes.
678TEST_F(ConfigurationTest, GetNodes) {
679 {
680 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700681 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800682 const Node *pi1 = GetNode(&config.message(), "pi1");
683 const Node *pi2 = GetNode(&config.message(), "pi2");
684
685 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(pi1, pi2));
686 }
687
688 {
689 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700690 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800691 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(nullptr));
692 }
693}
694
Austin Schuh65465332020-11-05 17:36:53 -0800695// Tests that we can pull out all the nodes with a tag.
696TEST_F(ConfigurationTest, GetNodesWithTag) {
697 {
698 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700699 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuh65465332020-11-05 17:36:53 -0800700 const Node *pi1 = GetNode(&config.message(), "pi1");
701 const Node *pi2 = GetNode(&config.message(), "pi2");
702
703 EXPECT_THAT(GetNodesWithTag(&config.message(), "a"),
704 ::testing::ElementsAre(pi1));
705 EXPECT_THAT(GetNodesWithTag(&config.message(), "b"),
706 ::testing::ElementsAre(pi2));
707 EXPECT_THAT(GetNodesWithTag(&config.message(), "c"),
708 ::testing::ElementsAre(pi1, pi2));
709 }
710
711 {
712 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700713 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuh65465332020-11-05 17:36:53 -0800714 EXPECT_THAT(GetNodesWithTag(&config.message(), "arglfish"),
715 ::testing::ElementsAre(nullptr));
716 }
717}
718
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800719// Tests that we can extract a node index from a config.
720TEST_F(ConfigurationTest, GetNodeIndex) {
721 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700722 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuh04408fc2020-02-16 21:48:54 -0800723 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh373f1762021-06-02 21:07:09 -0700724 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800725 const Node *pi1 = GetNode(&config.message(), "pi1");
726 const Node *pi2 = GetNode(&config.message(), "pi2");
727
Austin Schuh04408fc2020-02-16 21:48:54 -0800728 // Try the normal case.
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800729 EXPECT_EQ(GetNodeIndex(&config.message(), pi1), 0);
730 EXPECT_EQ(GetNodeIndex(&config.message(), pi2), 1);
Austin Schuh04408fc2020-02-16 21:48:54 -0800731
732 // Now try if we have node pointers from a different message.
733 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1), 0);
734 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2), 1);
735
736 // And now try string names.
737 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1->name()->string_view()), 0);
738 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2->name()->string_view()), 1);
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800739}
740
741// Tests that GetNodeOrDie handles both single and multi-node worlds and returns
742// valid nodes.
743TEST_F(ConfigurationDeathTest, GetNodeOrDie) {
744 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700745 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800746 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh373f1762021-06-02 21:07:09 -0700747 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800748 {
749 // Simple case, nullptr -> nullptr
750 FlatbufferDetachedBuffer<Configuration> single_node_config =
Austin Schuh373f1762021-06-02 21:07:09 -0700751 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800752 EXPECT_EQ(nullptr, GetNodeOrDie(&single_node_config.message(), nullptr));
753
754 // Confirm that we die when a node is passed in.
755 EXPECT_DEATH(
756 {
757 GetNodeOrDie(&single_node_config.message(),
758 config.message().nodes()->Get(0));
759 },
760 "Provided a node in a single node world.");
761 }
762
763 const Node *pi1 = GetNode(&config.message(), "pi1");
764 // Now try a lookup using a node from a different instance of the config.
765 EXPECT_EQ(pi1,
766 GetNodeOrDie(&config.message(), config2.message().nodes()->Get(0)));
767}
768
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800769TEST_F(ConfigurationTest, GetNodeFromHostname) {
770 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700771 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800772 EXPECT_EQ("pi1",
773 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
774 ->name()
775 ->string_view());
776 EXPECT_EQ("pi2", CHECK_NOTNULL(
777 GetNodeFromHostname(&config.message(), "raspberrypi2"))
778 ->name()
779 ->string_view());
780 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi3"));
781 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
782 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
783}
784
785TEST_F(ConfigurationTest, GetNodeFromHostnames) {
786 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700787 ReadConfig(ArtifactPath("aos/testdata/good_multinode_hostnames.json"));
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800788 EXPECT_EQ("pi1",
789 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
790 ->name()
791 ->string_view());
792 EXPECT_EQ("pi2", CHECK_NOTNULL(
793 GetNodeFromHostname(&config.message(), "raspberrypi2"))
794 ->name()
795 ->string_view());
796 EXPECT_EQ("pi2", CHECK_NOTNULL(
797 GetNodeFromHostname(&config.message(), "raspberrypi3"))
798 ->name()
799 ->string_view());
Ravago Jonescf453ab2020-05-06 21:14:53 -0700800 EXPECT_EQ("pi2",
801 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "other"))
802 ->name()
803 ->string_view());
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800804 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi4"));
805 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
806 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
807}
808
Austin Schuhcb108412019-10-13 16:09:54 -0700809} // namespace testing
810} // namespace configuration
811} // namespace aos