blob: cb44f1b4ab0a871e2bff96d4cabd0a6cc2cacf65 [file] [log] [blame]
Austin Schuhcb108412019-10-13 16:09:54 -07001#include "aos/configuration.h"
2
3#include "absl/strings/strip.h"
Nathan Leong307c9692022-10-08 15:25:03 -07004#include "aos/events/ping_generated.h"
Austin Schuhcb108412019-10-13 16:09:54 -07005#include "aos/json_to_flatbuffer.h"
Austin Schuh1ef01ef2021-02-07 20:40:36 -08006#include "aos/testing/flatbuffer_eq.h"
Austin Schuh373f1762021-06-02 21:07:09 -07007#include "aos/testing/path.h"
Austin Schuhcb108412019-10-13 16:09:54 -07008#include "aos/testing/test_logging.h"
9#include "aos/util/file.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070010#include "flatbuffers/reflection.h"
11#include "glog/logging.h"
Austin Schuhe84c3ed2019-12-14 15:29:48 -080012#include "gmock/gmock.h"
Austin Schuh1ef01ef2021-02-07 20:40:36 -080013#include "gtest/gtest.h"
Austin Schuhcb108412019-10-13 16:09:54 -070014
15namespace aos {
16namespace configuration {
17namespace testing {
18
Austin Schuh373f1762021-06-02 21:07:09 -070019using aos::testing::ArtifactPath;
Austin Schuhfb37c612022-08-11 15:24:51 -070020namespace chrono = std::chrono;
Austin Schuh66602132020-02-28 13:38:37 -080021
Austin Schuhcb108412019-10-13 16:09:54 -070022class ConfigurationTest : public ::testing::Test {
23 public:
24 ConfigurationTest() { ::aos::testing::EnableTestLogging(); }
25};
26
27typedef ConfigurationTest ConfigurationDeathTest;
28
29// *the* expected location for all working tests.
Austin Schuh1ef01ef2021-02-07 20:40:36 -080030aos::FlatbufferDetachedBuffer<Channel> ExpectedLocation() {
31 return JsonToFlatbuffer<Channel>(
32 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5 }");
33}
34
Austin Schuhbca6cf02019-12-22 17:28:34 -080035// And for multinode setups
Austin Schuh1ef01ef2021-02-07 20:40:36 -080036aos::FlatbufferDetachedBuffer<Channel> ExpectedMultinodeLocation() {
37 return JsonToFlatbuffer<Channel>(
38 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5, "
39 "\"source_node\": \"pi1\" }");
40}
Austin Schuhcb108412019-10-13 16:09:54 -070041
42// Tests that we can read and merge a configuration.
43TEST_F(ConfigurationTest, ConfigMerge) {
Austin Schuh40485ed2019-10-26 21:51:44 -070044 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070045 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Ravago Jonescf453ab2020-05-06 21:14:53 -070046 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuhcb108412019-10-13 16:09:54 -070047
Austin Schuh373f1762021-06-02 21:07:09 -070048 EXPECT_EQ(absl::StripSuffix(util::ReadFileToStringOrDie(
49 ArtifactPath("aos/testdata/expected.json")),
50 "\n"),
51 FlatbufferToJson(config, {.multi_line = true}));
Austin Schuhcb108412019-10-13 16:09:54 -070052}
53
Austin Schuhc9e10ec2020-01-26 16:08:28 -080054// Tests that we can get back a ChannelIndex.
55TEST_F(ConfigurationTest, ChannelIndex) {
56 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070057 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -080058
59 EXPECT_EQ(
60 ChannelIndex(&config.message(), config.message().channels()->Get(1u)),
61 1u);
62}
63
Austin Schuh217a9782019-12-21 23:02:50 -080064// Tests that we can read and merge a multinode configuration.
65TEST_F(ConfigurationTest, ConfigMergeMultinode) {
66 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070067 ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
Ravago Jonescf453ab2020-05-06 21:14:53 -070068 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuh217a9782019-12-21 23:02:50 -080069
Ravago Jonescf453ab2020-05-06 21:14:53 -070070 EXPECT_EQ(std::string(absl::StripSuffix(
Austin Schuh373f1762021-06-02 21:07:09 -070071 util::ReadFileToStringOrDie(
72 ArtifactPath("aos/testdata/expected_multinode.json")),
Ravago Jonescf453ab2020-05-06 21:14:53 -070073 "\n")),
74 FlatbufferToJson(config, {.multi_line = true}));
Austin Schuh217a9782019-12-21 23:02:50 -080075}
76
Alex Perrycb7da4b2019-08-28 19:35:56 -070077// Tests that we sort the entries in a config so we can look entries up.
78TEST_F(ConfigurationTest, UnsortedConfig) {
79 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070080 ReadConfig(ArtifactPath("aos/testdata/backwards.json"));
Alex Perrycb7da4b2019-08-28 19:35:56 -070081
Ravago Jonescf453ab2020-05-06 21:14:53 -070082 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Alex Perrycb7da4b2019-08-28 19:35:56 -070083
Austin Schuhf1fff282020-03-28 16:57:32 -070084 EXPECT_EQ(FlatbufferToJson(GetChannel(config, "/aos/robot_state",
Austin Schuhbca6cf02019-12-22 17:28:34 -080085 "aos.RobotState", "app1", nullptr)),
Austin Schuhf1fff282020-03-28 16:57:32 -070086 "{ \"name\": \"/aos/robot_state\", \"type\": \"aos.RobotState\", "
Alex Perrycb7da4b2019-08-28 19:35:56 -070087 "\"max_size\": 5 }");
88}
89
Austin Schuhcb108412019-10-13 16:09:54 -070090// Tests that we die when a file is imported twice.
91TEST_F(ConfigurationDeathTest, DuplicateFile) {
92 EXPECT_DEATH(
93 {
Austin Schuh40485ed2019-10-26 21:51:44 -070094 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070095 ReadConfig(ArtifactPath("aos/testdata/config1_bad.json"));
Austin Schuhcb108412019-10-13 16:09:54 -070096 },
Austin Schuh373f1762021-06-02 21:07:09 -070097 "aos/testdata/config1_bad.json");
Austin Schuhcb108412019-10-13 16:09:54 -070098}
99
Milind Upadhyay17098ba2022-04-15 22:18:50 -0700100// Tests that we die when we give an invalid path.
101TEST_F(ConfigurationDeathTest, NonexistentFile) {
102 EXPECT_DEATH(
103 {
104 FlatbufferDetachedBuffer<Configuration> config =
105 ReadConfig("nonexistent/config.json");
106 },
107 "above error");
108}
109
110// Tests that we return std::nullopt when we give an invalid path.
111TEST_F(ConfigurationTest, NonexistentFileOptional) {
112 std::optional<FlatbufferDetachedBuffer<Configuration>> config =
113 MaybeReadConfig("nonexistent/config.json");
114 EXPECT_FALSE(config.has_value());
115}
116
Austin Schuhf1fff282020-03-28 16:57:32 -0700117// Tests that we reject invalid channel names. This means any channels with //
118// in their name, a trailing /, or regex characters.
119TEST_F(ConfigurationDeathTest, InvalidChannelName) {
120 EXPECT_DEATH(
121 {
122 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700123 ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name1.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700124 },
125 "Channel names can't end with '/'");
126 EXPECT_DEATH(
127 {
128 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700129 ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name2.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700130 },
131 "Invalid channel name");
132 EXPECT_DEATH(
133 {
134 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700135 ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name3.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700136 LOG(FATAL) << "Foo";
137 },
138 "Invalid channel name");
Austin Schuh47e382e2023-05-28 11:20:56 -0700139 EXPECT_DEATH(
140 {
141 FlatbufferDetachedBuffer<Configuration> config =
142 ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name4.json"));
143 LOG(FATAL) << "Foo";
144 },
145 "Channel names must start with '/'");
Austin Schuhf1fff282020-03-28 16:57:32 -0700146}
147
Austin Schuh8d6cea82020-02-28 12:17:16 -0800148// Tests that we can modify a config with a json snippet.
149TEST_F(ConfigurationTest, MergeWithConfig) {
150 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700151 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Ravago Jonescf453ab2020-05-06 21:14:53 -0700152 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuh8d6cea82020-02-28 12:17:16 -0800153
154 FlatbufferDetachedBuffer<Configuration> updated_config =
155 MergeWithConfig(&config.message(),
156 R"channel({
157 "channels": [
158 {
159 "name": "/foo",
160 "type": ".aos.bar",
161 "max_size": 100
162 }
163 ]
164})channel");
165
Austin Schuh373f1762021-06-02 21:07:09 -0700166 EXPECT_EQ(absl::StripSuffix(util::ReadFileToStringOrDie(ArtifactPath(
167 "aos/testdata/expected_merge_with.json")),
Ravago Jonescf453ab2020-05-06 21:14:53 -0700168 "\n"),
169 FlatbufferToJson(updated_config, {.multi_line = true}));
Austin Schuh8d6cea82020-02-28 12:17:16 -0800170}
171
Austin Schuhcb108412019-10-13 16:09:54 -0700172// Tests that we can lookup a location, complete with maps, from a merged
173// config.
Austin Schuh40485ed2019-10-26 21:51:44 -0700174TEST_F(ConfigurationTest, GetChannel) {
175 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700176 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhcb108412019-10-13 16:09:54 -0700177
178 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800179 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", nullptr),
180 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700181
182 // Test that an invalid name results in nullptr back.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800183 EXPECT_EQ(GetChannel(config, "/invalid_name", ".aos.bar", "app1", nullptr),
184 nullptr);
Austin Schuhcb108412019-10-13 16:09:54 -0700185
186 // Tests that a root map/rename works. And that they get processed from the
187 // bottom up.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800188 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", nullptr),
189 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700190
191 // And then test that an application specific map/rename works.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800192 EXPECT_THAT(GetChannel(config, "/bar", ".aos.bar", "app1", nullptr),
193 aos::testing::FlatbufferEq(ExpectedLocation()));
194 EXPECT_THAT(GetChannel(config, "/baz", ".aos.bar", "app2", nullptr),
195 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700196
197 // And then test that an invalid application name gets properly ignored.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800198 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app3", nullptr),
199 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800200}
201
James Kuszmaulc8503f32022-06-25 16:17:12 -0700202// Tests that we can do reverse-lookups of channel names.
203TEST_F(ConfigurationTest, GetChannelAliases) {
204 FlatbufferDetachedBuffer<Configuration> config =
205 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
206
207 // Test a basic lookup first.
208 EXPECT_THAT(
209 GetChannelAliases(&config.message(), "/foo", ".aos.bar", "app1", nullptr),
210 ::testing::UnorderedElementsAre("/foo", "/batman", "/bar"));
211 EXPECT_THAT(
212 GetChannelAliases(&config.message(), "/bar", ".aos.bar", "app1", nullptr),
213 ::testing::UnorderedElementsAre("/batman", "/bar"));
214 EXPECT_THAT(GetChannelAliases(&config.message(), "/batman", ".aos.bar",
215 "app1", nullptr),
216 ::testing::UnorderedElementsAre("/batman"));
217 // /bar (deliberately) does not get included because of the ordering in the
218 // map.
219 EXPECT_THAT(
220 GetChannelAliases(&config.message(), "/foo", ".aos.bar", "", nullptr),
221 ::testing::UnorderedElementsAre("/foo", "/batman"));
222 EXPECT_THAT(
223 GetChannelAliases(&config.message(), "/foo", ".aos.bar", "app2", nullptr),
224 ::testing::UnorderedElementsAre("/foo", "/batman", "/baz"));
225}
226
Austin Schuhbca6cf02019-12-22 17:28:34 -0800227// Tests that we can lookup a location with node specific maps.
228TEST_F(ConfigurationTest, GetChannelMultinode) {
229 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700230 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800231 const Node *pi1 = GetNode(&config.message(), "pi1");
232 const Node *pi2 = GetNode(&config.message(), "pi2");
233
234 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800235 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", pi1),
236 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
237 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", pi2),
238 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800239
240 // Tests that a root map/rename works with a node specific map.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800241 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", pi1),
242 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800243
244 // Tests that a root map/rename fails with a node specific map for the wrong
245 // node.
246 EXPECT_EQ(GetChannel(config, "/batman", ".aos.bar", "app1", pi2), nullptr);
247
248 // And then test that an application specific map/rename works.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800249 EXPECT_THAT(GetChannel(config, "/batman2", ".aos.bar", "app1", pi1),
250 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
251 EXPECT_THAT(GetChannel(config, "/batman3", ".aos.bar", "app1", pi1),
252 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800253
254 // And then that it fails when the node changes.
255 EXPECT_EQ(GetChannel(config, "/batman3", ".aos.bar", "app1", pi2), nullptr);
256}
257
James Kuszmaulc8503f32022-06-25 16:17:12 -0700258// Tests that reverse channel lookup on a multi-node config (including with
259// wildcards) works.
260TEST_F(ConfigurationTest, GetChannelAliasesMultinode) {
261 FlatbufferDetachedBuffer<Configuration> config =
262 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
263
264 const Node *pi1 = GetNode(&config.message(), "pi1");
265 const Node *pi2 = GetNode(&config.message(), "pi2");
266
267 EXPECT_THAT(
268 GetChannelAliases(&config.message(), "/foo", ".aos.bar", "app1", pi1),
269 ::testing::UnorderedElementsAre("/foo", "/batman", "/batman2", "/batman3",
270 "/magic/string"));
271
272 EXPECT_THAT(
273 GetChannelAliases(&config.message(), "/foo", ".aos.baz", "app1", pi1),
274 ::testing::UnorderedElementsAre("/foo", "/batman3", "/magic/string"));
275
276 EXPECT_THAT(
277 GetChannelAliases(&config.message(), "/foo/testing", ".aos.bar", "", pi1),
278 ::testing::UnorderedElementsAre("/foo/testing", "/magic/string/testing"));
279
280 EXPECT_THAT(
281 GetChannelAliases(&config.message(), "/foo/testing", ".aos.bar", "app1",
282 pi2),
283 ::testing::UnorderedElementsAre("/foo/testing", "/magic/string/testing"));
284}
285
Austin Schuhbca6cf02019-12-22 17:28:34 -0800286// Tests that we can lookup a location with type specific maps.
287TEST_F(ConfigurationTest, GetChannelTypedMultinode) {
288 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700289 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800290 const Node *pi1 = GetNode(&config.message(), "pi1");
291
292 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800293 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", pi1),
294 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800295
296 // Now confirm that a second message on the same name doesn't get remapped.
297 const char *kExpectedBazMultinodeLocation =
298 "{ \"name\": \"/batman\", \"type\": \".aos.baz\", \"max_size\": 5, "
299 "\"source_node\": \"pi1\" }";
300 EXPECT_EQ(
301 FlatbufferToJson(GetChannel(config, "/batman", ".aos.baz", "app1", pi1)),
302 kExpectedBazMultinodeLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700303}
304
Austin Schuhf1fff282020-03-28 16:57:32 -0700305// Tests that we can lookup a location with a glob
306TEST_F(ConfigurationTest, GetChannelGlob) {
307 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700308 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700309 const Node *pi1 = GetNode(&config.message(), "pi1");
310
311 // Confirm that a glob with nothing after it matches.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800312 EXPECT_THAT(GetChannel(config, "/magic/string", ".aos.bar", "app7", pi1),
313 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhf1fff282020-03-28 16:57:32 -0700314
315 // Now confirm that glob with something following it matches and renames
316 // correctly.
317 const char *kExpectedSubfolderMultinodeLocation =
318 "{ \"name\": \"/foo/subfolder\", \"type\": \".aos.bar\", \"max_size\": "
319 "5, \"source_node\": \"pi1\" }";
320 EXPECT_EQ(FlatbufferToJson(GetChannel(config, "/magic/string/subfolder",
321 ".aos.bar", "app7", pi1)),
322 kExpectedSubfolderMultinodeLocation);
323}
324
Austin Schuh217a9782019-12-21 23:02:50 -0800325// Tests that we reject a configuration which has a nodes list, but has channels
326// withoout source_node filled out.
327TEST_F(ConfigurationDeathTest, InvalidSourceNode) {
328 EXPECT_DEATH(
329 {
330 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700331 ReadConfig(ArtifactPath("aos/testdata/invalid_nodes.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800332 },
333 "source_node");
334
335 EXPECT_DEATH(
336 {
337 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700338 ReadConfig(ArtifactPath("aos/testdata/invalid_source_node.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800339 },
340 "source_node");
341
342 EXPECT_DEATH(
343 {
Austin Schuh373f1762021-06-02 21:07:09 -0700344 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
345 ArtifactPath("aos/testdata/invalid_destination_node.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800346 },
347 "destination_nodes");
348
349 EXPECT_DEATH(
350 {
351 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700352 ReadConfig(ArtifactPath("aos/testdata/self_forward.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800353 },
354 "forwarding data to itself");
355}
356
357// Tests that our node writeable helpers work as intended.
358TEST_F(ConfigurationTest, ChannelIsSendableOnNode) {
359 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800360 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800361 "name": "/test",
362 "type": "aos.examples.Ping",
363 "source_node": "foo"
364})channel",
365 Channel::MiniReflectTypeTable()));
366
367 FlatbufferDetachedBuffer<Channel> bad_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800368 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800369 "name": "/test",
370 "type": "aos.examples.Ping",
371 "source_node": "bar"
372})channel",
373 Channel::MiniReflectTypeTable()));
374
375 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800376 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800377 "name": "foo"
378})node",
379 Node::MiniReflectTypeTable()));
380
381 EXPECT_TRUE(
382 ChannelIsSendableOnNode(&good_channel.message(), &node.message()));
383 EXPECT_FALSE(
384 ChannelIsSendableOnNode(&bad_channel.message(), &node.message()));
385}
386
387// Tests that our node readable and writeable helpers work as intended.
388TEST_F(ConfigurationTest, ChannelIsReadableOnNode) {
389 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800390 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800391 "name": "/test",
392 "type": "aos.examples.Ping",
393 "source_node": "bar",
394 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800395 {
396 "name": "baz"
397 },
398 {
399 "name": "foo"
400 }
Austin Schuh217a9782019-12-21 23:02:50 -0800401 ]
402})channel",
403 Channel::MiniReflectTypeTable()));
404
405 FlatbufferDetachedBuffer<Channel> bad_channel1(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800406 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800407 "name": "/test",
408 "type": "aos.examples.Ping",
409 "source_node": "bar"
410})channel",
411 Channel::MiniReflectTypeTable()));
412
413 FlatbufferDetachedBuffer<Channel> bad_channel2(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800414 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800415 "name": "/test",
416 "type": "aos.examples.Ping",
417 "source_node": "bar",
418 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800419 {
420 "name": "baz"
421 }
Austin Schuh217a9782019-12-21 23:02:50 -0800422 ]
423})channel",
424 Channel::MiniReflectTypeTable()));
425
426 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800427 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800428 "name": "foo"
429})node",
430 Node::MiniReflectTypeTable()));
431
432 EXPECT_TRUE(
433 ChannelIsReadableOnNode(&good_channel.message(), &node.message()));
434 EXPECT_FALSE(
435 ChannelIsReadableOnNode(&bad_channel1.message(), &node.message()));
436 EXPECT_FALSE(
437 ChannelIsReadableOnNode(&bad_channel2.message(), &node.message()));
438}
439
Austin Schuh719946b2019-12-28 14:51:01 -0800440// Tests that our node message is logged helpers work as intended.
441TEST_F(ConfigurationTest, ChannelMessageIsLoggedOnNode) {
442 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
443 R"channel({
444 "name": "/test",
445 "type": "aos.examples.Ping",
446 "source_node": "bar",
447 "destination_nodes": [
448 {
449 "name": "baz"
450 }
451 ]
452})channel",
453 Channel::MiniReflectTypeTable()));
Austin Schuh217a9782019-12-21 23:02:50 -0800454
Austin Schuh719946b2019-12-28 14:51:01 -0800455 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
456 R"channel({
457 "name": "/test",
458 "type": "aos.examples.Ping",
459 "source_node": "bar",
460 "logger": "NOT_LOGGED",
461 "destination_nodes": [
462 {
463 "name": "baz",
464 "timestamp_logger": "LOCAL_LOGGER"
465 }
466 ]
467})channel",
468 Channel::MiniReflectTypeTable()));
469
470 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
471 R"channel({
472 "name": "/test",
473 "type": "aos.examples.Ping",
474 "source_node": "bar",
475 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700476 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800477 "destination_nodes": [
478 {
479 "name": "baz"
480 }
481 ]
482})channel",
483 Channel::MiniReflectTypeTable()));
484
485 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
486 JsonToFlatbuffer(
487 R"channel({
488 "name": "/test",
489 "type": "aos.examples.Ping",
490 "source_node": "bar",
491 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700492 "logger_nodes": ["foo"],
Austin Schuh719946b2019-12-28 14:51:01 -0800493 "destination_nodes": [
494 {
495 "name": "baz"
496 }
497 ]
498})channel",
499 Channel::MiniReflectTypeTable()));
500
Ravago Jonescf453ab2020-05-06 21:14:53 -0700501 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
502 R"channel({
Austin Schuh719946b2019-12-28 14:51:01 -0800503 "name": "/test",
504 "type": "aos.examples.Ping",
505 "source_node": "bar",
506 "logger": "LOCAL_AND_REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700507 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800508 "destination_nodes": [
509 {
510 "name": "baz"
511 }
512 ]
513})channel",
Ravago Jonescf453ab2020-05-06 21:14:53 -0700514 Channel::MiniReflectTypeTable()));
Austin Schuh719946b2019-12-28 14:51:01 -0800515
516 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
517 R"node({
518 "name": "foo"
519})node",
520 Node::MiniReflectTypeTable()));
521
522 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
523 R"node({
524 "name": "bar"
525})node",
526 Node::MiniReflectTypeTable()));
527
528 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
529 R"node({
530 "name": "baz"
531})node",
532 Node::MiniReflectTypeTable()));
533
534 // Local logger.
535 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
536 &foo_node.message()));
537 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
538 &bar_node.message()));
539 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
540 &baz_node.message()));
Austin Schuh48e94502021-06-18 18:35:53 -0700541 EXPECT_TRUE(
542 ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(), nullptr));
Austin Schuh719946b2019-12-28 14:51:01 -0800543
544 // No logger.
545 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
546 &foo_node.message()));
547 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
Ravago Jonescf453ab2020-05-06 21:14:53 -0700548 &bar_node.message()));
Austin Schuh719946b2019-12-28 14:51:01 -0800549 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
550 &baz_node.message()));
Austin Schuh48e94502021-06-18 18:35:53 -0700551 EXPECT_FALSE(
552 ChannelMessageIsLoggedOnNode(&not_logged_channel.message(), nullptr));
Austin Schuh719946b2019-12-28 14:51:01 -0800553
554 // Remote logger.
555 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
556 &foo_node.message()));
557 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
558 &bar_node.message()));
559 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
560 &baz_node.message()));
561
562 // Separate logger.
563 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(
564 &logged_on_separate_logger_node_channel.message(), &foo_node.message()));
565 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
566 &logged_on_separate_logger_node_channel.message(), &bar_node.message()));
567 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
568 &logged_on_separate_logger_node_channel.message(), &baz_node.message()));
569
570 // Logged in multiple places.
571 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
572 &foo_node.message()));
573 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
574 &bar_node.message()));
575 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
576 &baz_node.message()));
577}
578
Austin Schuh48e94502021-06-18 18:35:53 -0700579// Tests that our node message is logged helpers work as intended.
580TEST_F(ConfigurationDeathTest, ChannelMessageIsLoggedOnNode) {
581 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
582 R"channel({
583 "name": "/test",
584 "type": "aos.examples.Ping",
585 "source_node": "bar",
586 "logger": "LOCAL_AND_REMOTE_LOGGER",
587 "logger_nodes": ["baz"],
588 "destination_nodes": [
589 {
590 "name": "baz"
591 }
592 ]
593})channel",
594 Channel::MiniReflectTypeTable()));
595
596 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
597 JsonToFlatbuffer(
598 R"channel({
599 "name": "/test",
600 "type": "aos.examples.Ping",
601 "source_node": "bar",
602 "logger": "REMOTE_LOGGER",
603 "logger_nodes": ["foo"],
604 "destination_nodes": [
605 {
606 "name": "baz"
607 }
608 ]
609})channel",
610 Channel::MiniReflectTypeTable()));
611
612 EXPECT_DEATH(
613 {
614 ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
615 nullptr);
616 },
617 "Unsupported logging configuration in a single node world");
618 EXPECT_DEATH(
619 {
620 ChannelMessageIsLoggedOnNode(
621 &logged_on_separate_logger_node_channel.message(), nullptr);
622 },
623 "Unsupported logging configuration in a single node world");
624}
625
Austin Schuh719946b2019-12-28 14:51:01 -0800626// Tests that our forwarding timestamps are logged helpers work as intended.
627TEST_F(ConfigurationTest, ConnectionDeliveryTimeIsLoggedOnNode) {
628 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
629 R"channel({
630 "name": "/test",
631 "type": "aos.examples.Ping",
632 "source_node": "bar",
633 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700634 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800635 "destination_nodes": [
636 {
637 "name": "baz"
638 }
639 ]
640})channel",
641 Channel::MiniReflectTypeTable()));
642
643 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
644 R"channel({
645 "name": "/test",
646 "type": "aos.examples.Ping",
647 "source_node": "bar",
648 "logger": "NOT_LOGGED",
649 "destination_nodes": [
650 {
651 "name": "baz",
652 "timestamp_logger": "NOT_LOGGED"
653 }
654 ]
655})channel",
656 Channel::MiniReflectTypeTable()));
657
658 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
659 R"channel({
660 "name": "/test",
661 "type": "aos.examples.Ping",
662 "source_node": "bar",
663 "destination_nodes": [
664 {
665 "name": "baz",
666 "timestamp_logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700667 "timestamp_logger_nodes": ["bar"]
Austin Schuh719946b2019-12-28 14:51:01 -0800668 }
669 ]
670})channel",
671 Channel::MiniReflectTypeTable()));
672
673 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
674 JsonToFlatbuffer(
675 R"channel({
676 "name": "/test",
677 "type": "aos.examples.Ping",
678 "source_node": "bar",
679 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700680 "logger_nodes": ["foo"],
Austin Schuh719946b2019-12-28 14:51:01 -0800681 "destination_nodes": [
682 {
683 "name": "baz",
684 "timestamp_logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700685 "timestamp_logger_nodes": ["foo"]
Austin Schuh719946b2019-12-28 14:51:01 -0800686 }
687 ]
688})channel",
689 Channel::MiniReflectTypeTable()));
690
Ravago Jonescf453ab2020-05-06 21:14:53 -0700691 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
692 R"channel({
Austin Schuh719946b2019-12-28 14:51:01 -0800693 "name": "/test",
694 "type": "aos.examples.Ping",
695 "source_node": "bar",
696 "destination_nodes": [
697 {
698 "name": "baz",
699 "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700700 "timestamp_logger_nodes": ["bar"]
Austin Schuh719946b2019-12-28 14:51:01 -0800701 }
702 ]
703})channel",
Ravago Jonescf453ab2020-05-06 21:14:53 -0700704 Channel::MiniReflectTypeTable()));
Austin Schuh719946b2019-12-28 14:51:01 -0800705
706 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
707 R"node({
708 "name": "foo"
709})node",
710 Node::MiniReflectTypeTable()));
711
712 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
713 R"node({
714 "name": "bar"
715})node",
716 Node::MiniReflectTypeTable()));
717
718 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
719 R"node({
720 "name": "baz"
721})node",
722 Node::MiniReflectTypeTable()));
723
724 // Local logger.
725 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
726 &logged_on_self_channel.message(), &baz_node.message(),
727 &foo_node.message()));
728 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
729 &logged_on_self_channel.message(), &baz_node.message(),
730 &bar_node.message()));
731 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
732 &logged_on_self_channel.message(), &baz_node.message(),
733 &baz_node.message()));
734
735 // No logger means.
736 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
737 &not_logged_channel.message(), &baz_node.message(), &foo_node.message()));
738 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
739 &not_logged_channel.message(), &baz_node.message(), &bar_node.message()));
740 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
741 &not_logged_channel.message(), &baz_node.message(), &baz_node.message()));
742
743 // Remote logger.
744 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
745 &logged_on_remote_channel.message(), &baz_node.message(),
746 &foo_node.message()));
747 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
748 &logged_on_remote_channel.message(), &baz_node.message(),
749 &bar_node.message()));
750 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
751 &logged_on_remote_channel.message(), &baz_node.message(),
752 &baz_node.message()));
753
754 // Separate logger.
755 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
756 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
757 &foo_node.message()));
758 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
759 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
760 &bar_node.message()));
761 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
762 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
763 &baz_node.message()));
764
765 // Logged on both the node and a remote node.
766 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
767 &logged_on_both_channel.message(), &baz_node.message(),
768 &foo_node.message()));
769 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
770 &logged_on_both_channel.message(), &baz_node.message(),
771 &bar_node.message()));
772 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
773 &logged_on_both_channel.message(), &baz_node.message(),
774 &baz_node.message()));
775}
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800776
777// Tests that we can deduce source nodes from a multinode config.
778TEST_F(ConfigurationTest, SourceNodeNames) {
779 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700780 ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800781
782 // This is a bit simplistic in that it doesn't test deduplication, but it does
783 // exercise a lot of the logic.
784 EXPECT_THAT(
785 SourceNodeNames(&config.message(), config.message().nodes()->Get(0)),
786 ::testing::ElementsAreArray({"pi2"}));
787 EXPECT_THAT(
788 SourceNodeNames(&config.message(), config.message().nodes()->Get(1)),
789 ::testing::ElementsAreArray({"pi1"}));
790}
791
792// Tests that we can deduce destination nodes from a multinode config.
793TEST_F(ConfigurationTest, DestinationNodeNames) {
794 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700795 ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800796
797 // This is a bit simplistic in that it doesn't test deduplication, but it does
798 // exercise a lot of the logic.
799 EXPECT_THAT(
800 DestinationNodeNames(&config.message(), config.message().nodes()->Get(0)),
801 ::testing::ElementsAreArray({"pi2"}));
802 EXPECT_THAT(
803 DestinationNodeNames(&config.message(), config.message().nodes()->Get(1)),
804 ::testing::ElementsAreArray({"pi1"}));
805}
806
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800807// Tests that we can pull out all the nodes.
808TEST_F(ConfigurationTest, GetNodes) {
809 {
810 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700811 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800812 const Node *pi1 = GetNode(&config.message(), "pi1");
813 const Node *pi2 = GetNode(&config.message(), "pi2");
814
815 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(pi1, pi2));
816 }
817
818 {
819 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700820 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800821 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(nullptr));
822 }
823}
824
Austin Schuh65465332020-11-05 17:36:53 -0800825// Tests that we can pull out all the nodes with a tag.
826TEST_F(ConfigurationTest, GetNodesWithTag) {
827 {
828 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700829 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuh65465332020-11-05 17:36:53 -0800830 const Node *pi1 = GetNode(&config.message(), "pi1");
831 const Node *pi2 = GetNode(&config.message(), "pi2");
832
833 EXPECT_THAT(GetNodesWithTag(&config.message(), "a"),
834 ::testing::ElementsAre(pi1));
835 EXPECT_THAT(GetNodesWithTag(&config.message(), "b"),
836 ::testing::ElementsAre(pi2));
837 EXPECT_THAT(GetNodesWithTag(&config.message(), "c"),
838 ::testing::ElementsAre(pi1, pi2));
839 }
840
841 {
842 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700843 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuh65465332020-11-05 17:36:53 -0800844 EXPECT_THAT(GetNodesWithTag(&config.message(), "arglfish"),
845 ::testing::ElementsAre(nullptr));
846 }
847}
848
Brian Silverman631b6262021-11-10 12:25:08 -0800849// Tests that we can check if a node has a tag.
850TEST_F(ConfigurationTest, NodeHasTag) {
851 {
852 FlatbufferDetachedBuffer<Configuration> config =
853 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
854 const Node *pi1 = GetNode(&config.message(), "pi1");
855 const Node *pi2 = GetNode(&config.message(), "pi2");
856
857 EXPECT_TRUE(NodeHasTag(pi1, "a"));
858 EXPECT_FALSE(NodeHasTag(pi2, "a"));
859 EXPECT_FALSE(NodeHasTag(pi1, "b"));
860 EXPECT_TRUE(NodeHasTag(pi2, "b"));
861 EXPECT_TRUE(NodeHasTag(pi1, "c"));
862 EXPECT_TRUE(NodeHasTag(pi2, "c"));
863 EXPECT_FALSE(NodeHasTag(pi1, "nope"));
864 EXPECT_FALSE(NodeHasTag(pi2, "nope"));
865 }
866
867 EXPECT_TRUE(NodeHasTag(nullptr, "arglfish"));
868}
869
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800870// Tests that we can extract a node index from a config.
871TEST_F(ConfigurationTest, GetNodeIndex) {
872 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700873 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuh04408fc2020-02-16 21:48:54 -0800874 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh373f1762021-06-02 21:07:09 -0700875 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800876 const Node *pi1 = GetNode(&config.message(), "pi1");
877 const Node *pi2 = GetNode(&config.message(), "pi2");
878
Austin Schuh04408fc2020-02-16 21:48:54 -0800879 // Try the normal case.
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800880 EXPECT_EQ(GetNodeIndex(&config.message(), pi1), 0);
881 EXPECT_EQ(GetNodeIndex(&config.message(), pi2), 1);
Austin Schuh04408fc2020-02-16 21:48:54 -0800882
883 // Now try if we have node pointers from a different message.
884 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1), 0);
885 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2), 1);
886
887 // And now try string names.
888 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1->name()->string_view()), 0);
889 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2->name()->string_view()), 1);
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800890}
891
892// Tests that GetNodeOrDie handles both single and multi-node worlds and returns
893// valid nodes.
894TEST_F(ConfigurationDeathTest, GetNodeOrDie) {
895 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700896 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800897 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh373f1762021-06-02 21:07:09 -0700898 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800899 {
900 // Simple case, nullptr -> nullptr
901 FlatbufferDetachedBuffer<Configuration> single_node_config =
Austin Schuh373f1762021-06-02 21:07:09 -0700902 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800903 EXPECT_EQ(nullptr, GetNodeOrDie(&single_node_config.message(), nullptr));
904
905 // Confirm that we die when a node is passed in.
906 EXPECT_DEATH(
907 {
908 GetNodeOrDie(&single_node_config.message(),
909 config.message().nodes()->Get(0));
910 },
911 "Provided a node in a single node world.");
912 }
913
914 const Node *pi1 = GetNode(&config.message(), "pi1");
915 // Now try a lookup using a node from a different instance of the config.
916 EXPECT_EQ(pi1,
917 GetNodeOrDie(&config.message(), config2.message().nodes()->Get(0)));
918}
919
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800920TEST_F(ConfigurationTest, GetNodeFromHostname) {
921 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700922 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800923 EXPECT_EQ("pi1",
924 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
925 ->name()
926 ->string_view());
927 EXPECT_EQ("pi2", CHECK_NOTNULL(
928 GetNodeFromHostname(&config.message(), "raspberrypi2"))
929 ->name()
930 ->string_view());
931 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi3"));
932 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
933 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
934}
935
936TEST_F(ConfigurationTest, GetNodeFromHostnames) {
937 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700938 ReadConfig(ArtifactPath("aos/testdata/good_multinode_hostnames.json"));
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800939 EXPECT_EQ("pi1",
940 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
941 ->name()
942 ->string_view());
943 EXPECT_EQ("pi2", CHECK_NOTNULL(
944 GetNodeFromHostname(&config.message(), "raspberrypi2"))
945 ->name()
946 ->string_view());
947 EXPECT_EQ("pi2", CHECK_NOTNULL(
948 GetNodeFromHostname(&config.message(), "raspberrypi3"))
949 ->name()
950 ->string_view());
Ravago Jonescf453ab2020-05-06 21:14:53 -0700951 EXPECT_EQ("pi2",
952 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "other"))
953 ->name()
954 ->string_view());
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800955 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi4"));
956 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
957 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
958}
959
Austin Schuhfc7b6a02021-07-12 21:19:07 -0700960// Tests that SourceNodeIndex reasonably handles a multi-node log file.
961TEST_F(ConfigurationTest, SourceNodeIndex) {
962 FlatbufferDetachedBuffer<Configuration> config =
963 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
964 std::vector<size_t> result = SourceNodeIndex(&config.message());
965
966 EXPECT_THAT(result, ::testing::ElementsAreArray({0, 1, 0, 0}));
967}
968
Austin Schuh5e95bd62021-10-11 18:40:22 -0700969// Tests that we reject invalid logging configurations.
970TEST_F(ConfigurationDeathTest, InvalidLoggerConfig) {
971 EXPECT_DEATH(
972 {
Milind Upadhyay17098ba2022-04-15 22:18:50 -0700973 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
974 ArtifactPath("aos/testdata/invalid_logging_configuration.json"));
Austin Schuh5e95bd62021-10-11 18:40:22 -0700975 },
976 "Logging timestamps without data");
977}
978
Austin Schuha156fb22021-10-11 19:23:21 -0700979// Tests that we reject duplicate timestamp destination node configurations.
980TEST_F(ConfigurationDeathTest, DuplicateTimestampDestinationNodes) {
981 EXPECT_DEATH(
982 {
983 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
984 ArtifactPath("aos/testdata/duplicate_destination_nodes.json"));
985 },
986 "Found duplicate timestamp_logger_nodes in");
987}
988
989// Tests that we reject duplicate logger node configurations for a channel's
990// data.
991TEST_F(ConfigurationDeathTest, DuplicateLoggerNodes) {
992 EXPECT_DEATH(
993 {
994 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
995 ArtifactPath("aos/testdata/duplicate_logger_nodes.json"));
996 },
997 "Found duplicate logger_nodes in");
998}
999
Austin Schuhfb37c612022-08-11 15:24:51 -07001000// Tests that we properly compute the queue size for the provided duration.
1001TEST_F(ConfigurationTest, QueueSize) {
1002 EXPECT_EQ(QueueSize(100, chrono::seconds(2)), 200);
1003 EXPECT_EQ(QueueSize(200, chrono::seconds(2)), 400);
1004 EXPECT_EQ(QueueSize(100, chrono::seconds(6)), 600);
1005 EXPECT_EQ(QueueSize(100, chrono::milliseconds(10)), 1);
1006 EXPECT_EQ(QueueSize(100, chrono::milliseconds(10) - chrono::nanoseconds(1)),
1007 1);
1008 EXPECT_EQ(QueueSize(100, chrono::milliseconds(10) - chrono::nanoseconds(2)),
1009 1);
1010}
1011
1012// Tests that we compute scratch buffer size correctly too.
1013TEST_F(ConfigurationTest, QueueScratchBufferSize) {
1014 const aos::FlatbufferDetachedBuffer<Channel> channel =
1015 JsonToFlatbuffer<Channel>(
1016 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"num_readers\": 5, "
1017 "\"num_senders\": 10 }");
Austin Schuhfb37c612022-08-11 15:24:51 -07001018 EXPECT_EQ(QueueScratchBufferSize(&channel.message()), 15);
1019}
1020
Nathan Leong307c9692022-10-08 15:25:03 -07001021// Tests that GetSchema returns schema of specified type
1022TEST_F(ConfigurationTest, GetSchema) {
1023 FlatbufferDetachedBuffer<Configuration> config =
1024 ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
1025 FlatbufferVector<reflection::Schema> expected_schema =
1026 FileToFlatbuffer<reflection::Schema>(
1027 ArtifactPath("aos/events/ping.bfbs"));
1028 EXPECT_EQ(FlatbufferToJson(GetSchema(&config.message(), "aos.examples.Ping")),
1029 FlatbufferToJson(expected_schema));
1030 EXPECT_EQ(GetSchema(&config.message(), "invalid_name"), nullptr);
1031}
1032
1033// Tests that GetSchema template returns schema of specified type
1034TEST_F(ConfigurationTest, GetSchemaTemplate) {
1035 FlatbufferDetachedBuffer<Configuration> config =
1036 ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
1037 FlatbufferVector<reflection::Schema> expected_schema =
1038 FileToFlatbuffer<reflection::Schema>(
1039 ArtifactPath("aos/events/ping.bfbs"));
1040 EXPECT_EQ(FlatbufferToJson(GetSchema<aos::examples::Ping>(&config.message())),
1041 FlatbufferToJson(expected_schema));
1042}
1043
1044// Tests that GetSchemaDetachedBuffer returns detached buffer of specified type
1045TEST_F(ConfigurationTest, GetSchemaDetachedBuffer) {
1046 FlatbufferDetachedBuffer<Configuration> config =
1047 ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
1048 FlatbufferVector<reflection::Schema> expected_schema =
1049 FileToFlatbuffer<reflection::Schema>(
1050 ArtifactPath("aos/events/ping.bfbs"));
1051 EXPECT_EQ(FlatbufferToJson(
1052 GetSchemaDetachedBuffer(&config.message(), "aos.examples.Ping")
1053 .value()),
1054 FlatbufferToJson(expected_schema));
1055 EXPECT_EQ(GetSchemaDetachedBuffer(&config.message(), "invalid_name"),
1056 std::nullopt);
1057}
1058
James Kuszmaul741a4d02023-01-05 14:59:21 -08001059// Tests that we can use a utility to add individual channels to a single-node
1060// config.
1061TEST_F(ConfigurationTest, AddChannelToConfigSingleNode) {
1062 FlatbufferDetachedBuffer<Configuration> base_config =
1063 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
1064
1065 FlatbufferVector<reflection::Schema> schema =
1066 FileToFlatbuffer<reflection::Schema>(
1067 ArtifactPath("aos/events/ping.bfbs"));
1068
1069 FlatbufferDetachedBuffer<Configuration> new_config =
1070 AddChannelToConfiguration(&base_config.message(), "/new", schema);
1071
1072 ASSERT_EQ(new_config.message().channels()->size(),
1073 base_config.message().channels()->size() + 1);
1074
1075 const Channel *channel =
1076 GetChannel(new_config, "/new", "aos.examples.Ping", "", nullptr);
1077 ASSERT_TRUE(channel != nullptr);
1078 ASSERT_TRUE(channel->has_schema());
1079 // Check that we don't populate channel settings that we don't override the
1080 // defaults of.
1081 ASSERT_FALSE(channel->has_frequency());
1082}
1083
1084// Tests that we can use a utility to add individual channels to a multi-node
1085// config.
1086TEST_F(ConfigurationTest, AddChannelToConfigMultiNode) {
1087 FlatbufferDetachedBuffer<Configuration> base_config =
1088 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
1089
1090 FlatbufferVector<reflection::Schema> schema =
1091 FileToFlatbuffer<reflection::Schema>(
1092 ArtifactPath("aos/events/ping.bfbs"));
1093
1094 aos::ChannelT channel_overrides;
1095 channel_overrides.frequency = 971;
1096 FlatbufferDetachedBuffer<Configuration> new_config =
1097 AddChannelToConfiguration(&base_config.message(), "/new", schema,
1098 GetNode(&base_config.message(), "pi1"),
1099 channel_overrides);
1100
1101 ASSERT_EQ(new_config.message().channels()->size(),
1102 base_config.message().channels()->size() + 1);
1103
1104 const Channel *channel =
1105 GetChannel(new_config, "/new", "aos.examples.Ping", "", nullptr);
1106 ASSERT_TRUE(channel != nullptr);
1107 ASSERT_TRUE(channel->has_schema());
1108 ASSERT_TRUE(channel->has_source_node());
1109 ASSERT_EQ("pi1", channel->source_node()->string_view());
1110 ASSERT_EQ(971, channel->frequency());
1111}
1112
Austin Schuhcb108412019-10-13 16:09:54 -07001113} // namespace testing
1114} // namespace configuration
1115} // namespace aos