blob: 823f43c1a2137cdf1d5b428d5695cb4b41034895 [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");
139}
140
Austin Schuh8d6cea82020-02-28 12:17:16 -0800141// Tests that we can modify a config with a json snippet.
142TEST_F(ConfigurationTest, MergeWithConfig) {
143 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700144 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Ravago Jonescf453ab2020-05-06 21:14:53 -0700145 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuh8d6cea82020-02-28 12:17:16 -0800146
147 FlatbufferDetachedBuffer<Configuration> updated_config =
148 MergeWithConfig(&config.message(),
149 R"channel({
150 "channels": [
151 {
152 "name": "/foo",
153 "type": ".aos.bar",
154 "max_size": 100
155 }
156 ]
157})channel");
158
Austin Schuh373f1762021-06-02 21:07:09 -0700159 EXPECT_EQ(absl::StripSuffix(util::ReadFileToStringOrDie(ArtifactPath(
160 "aos/testdata/expected_merge_with.json")),
Ravago Jonescf453ab2020-05-06 21:14:53 -0700161 "\n"),
162 FlatbufferToJson(updated_config, {.multi_line = true}));
Austin Schuh8d6cea82020-02-28 12:17:16 -0800163}
164
Austin Schuhcb108412019-10-13 16:09:54 -0700165// Tests that we can lookup a location, complete with maps, from a merged
166// config.
Austin Schuh40485ed2019-10-26 21:51:44 -0700167TEST_F(ConfigurationTest, GetChannel) {
168 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700169 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhcb108412019-10-13 16:09:54 -0700170
171 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800172 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", nullptr),
173 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700174
175 // Test that an invalid name results in nullptr back.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800176 EXPECT_EQ(GetChannel(config, "/invalid_name", ".aos.bar", "app1", nullptr),
177 nullptr);
Austin Schuhcb108412019-10-13 16:09:54 -0700178
179 // Tests that a root map/rename works. And that they get processed from the
180 // bottom up.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800181 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", nullptr),
182 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700183
184 // And then test that an application specific map/rename works.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800185 EXPECT_THAT(GetChannel(config, "/bar", ".aos.bar", "app1", nullptr),
186 aos::testing::FlatbufferEq(ExpectedLocation()));
187 EXPECT_THAT(GetChannel(config, "/baz", ".aos.bar", "app2", nullptr),
188 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700189
190 // And then test that an invalid application name gets properly ignored.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800191 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app3", nullptr),
192 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800193}
194
James Kuszmaulc8503f32022-06-25 16:17:12 -0700195// Tests that we can do reverse-lookups of channel names.
196TEST_F(ConfigurationTest, GetChannelAliases) {
197 FlatbufferDetachedBuffer<Configuration> config =
198 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
199
200 // Test a basic lookup first.
201 EXPECT_THAT(
202 GetChannelAliases(&config.message(), "/foo", ".aos.bar", "app1", nullptr),
203 ::testing::UnorderedElementsAre("/foo", "/batman", "/bar"));
204 EXPECT_THAT(
205 GetChannelAliases(&config.message(), "/bar", ".aos.bar", "app1", nullptr),
206 ::testing::UnorderedElementsAre("/batman", "/bar"));
207 EXPECT_THAT(GetChannelAliases(&config.message(), "/batman", ".aos.bar",
208 "app1", nullptr),
209 ::testing::UnorderedElementsAre("/batman"));
210 // /bar (deliberately) does not get included because of the ordering in the
211 // map.
212 EXPECT_THAT(
213 GetChannelAliases(&config.message(), "/foo", ".aos.bar", "", nullptr),
214 ::testing::UnorderedElementsAre("/foo", "/batman"));
215 EXPECT_THAT(
216 GetChannelAliases(&config.message(), "/foo", ".aos.bar", "app2", nullptr),
217 ::testing::UnorderedElementsAre("/foo", "/batman", "/baz"));
218}
219
Austin Schuhbca6cf02019-12-22 17:28:34 -0800220// Tests that we can lookup a location with node specific maps.
221TEST_F(ConfigurationTest, GetChannelMultinode) {
222 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700223 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800224 const Node *pi1 = GetNode(&config.message(), "pi1");
225 const Node *pi2 = GetNode(&config.message(), "pi2");
226
227 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800228 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", pi1),
229 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
230 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", pi2),
231 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800232
233 // Tests that a root map/rename works with a node specific map.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800234 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", pi1),
235 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800236
237 // Tests that a root map/rename fails with a node specific map for the wrong
238 // node.
239 EXPECT_EQ(GetChannel(config, "/batman", ".aos.bar", "app1", pi2), nullptr);
240
241 // And then test that an application specific map/rename works.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800242 EXPECT_THAT(GetChannel(config, "/batman2", ".aos.bar", "app1", pi1),
243 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
244 EXPECT_THAT(GetChannel(config, "/batman3", ".aos.bar", "app1", pi1),
245 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800246
247 // And then that it fails when the node changes.
248 EXPECT_EQ(GetChannel(config, "/batman3", ".aos.bar", "app1", pi2), nullptr);
249}
250
James Kuszmaulc8503f32022-06-25 16:17:12 -0700251// Tests that reverse channel lookup on a multi-node config (including with
252// wildcards) works.
253TEST_F(ConfigurationTest, GetChannelAliasesMultinode) {
254 FlatbufferDetachedBuffer<Configuration> config =
255 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
256
257 const Node *pi1 = GetNode(&config.message(), "pi1");
258 const Node *pi2 = GetNode(&config.message(), "pi2");
259
260 EXPECT_THAT(
261 GetChannelAliases(&config.message(), "/foo", ".aos.bar", "app1", pi1),
262 ::testing::UnorderedElementsAre("/foo", "/batman", "/batman2", "/batman3",
263 "/magic/string"));
264
265 EXPECT_THAT(
266 GetChannelAliases(&config.message(), "/foo", ".aos.baz", "app1", pi1),
267 ::testing::UnorderedElementsAre("/foo", "/batman3", "/magic/string"));
268
269 EXPECT_THAT(
270 GetChannelAliases(&config.message(), "/foo/testing", ".aos.bar", "", pi1),
271 ::testing::UnorderedElementsAre("/foo/testing", "/magic/string/testing"));
272
273 EXPECT_THAT(
274 GetChannelAliases(&config.message(), "/foo/testing", ".aos.bar", "app1",
275 pi2),
276 ::testing::UnorderedElementsAre("/foo/testing", "/magic/string/testing"));
277}
278
Austin Schuhbca6cf02019-12-22 17:28:34 -0800279// Tests that we can lookup a location with type specific maps.
280TEST_F(ConfigurationTest, GetChannelTypedMultinode) {
281 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700282 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800283 const Node *pi1 = GetNode(&config.message(), "pi1");
284
285 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800286 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", pi1),
287 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800288
289 // Now confirm that a second message on the same name doesn't get remapped.
290 const char *kExpectedBazMultinodeLocation =
291 "{ \"name\": \"/batman\", \"type\": \".aos.baz\", \"max_size\": 5, "
292 "\"source_node\": \"pi1\" }";
293 EXPECT_EQ(
294 FlatbufferToJson(GetChannel(config, "/batman", ".aos.baz", "app1", pi1)),
295 kExpectedBazMultinodeLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700296}
297
Austin Schuhf1fff282020-03-28 16:57:32 -0700298// Tests that we can lookup a location with a glob
299TEST_F(ConfigurationTest, GetChannelGlob) {
300 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700301 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700302 const Node *pi1 = GetNode(&config.message(), "pi1");
303
304 // Confirm that a glob with nothing after it matches.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800305 EXPECT_THAT(GetChannel(config, "/magic/string", ".aos.bar", "app7", pi1),
306 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhf1fff282020-03-28 16:57:32 -0700307
308 // Now confirm that glob with something following it matches and renames
309 // correctly.
310 const char *kExpectedSubfolderMultinodeLocation =
311 "{ \"name\": \"/foo/subfolder\", \"type\": \".aos.bar\", \"max_size\": "
312 "5, \"source_node\": \"pi1\" }";
313 EXPECT_EQ(FlatbufferToJson(GetChannel(config, "/magic/string/subfolder",
314 ".aos.bar", "app7", pi1)),
315 kExpectedSubfolderMultinodeLocation);
316}
317
Austin Schuh217a9782019-12-21 23:02:50 -0800318// Tests that we reject a configuration which has a nodes list, but has channels
319// withoout source_node filled out.
320TEST_F(ConfigurationDeathTest, InvalidSourceNode) {
321 EXPECT_DEATH(
322 {
323 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700324 ReadConfig(ArtifactPath("aos/testdata/invalid_nodes.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800325 },
326 "source_node");
327
328 EXPECT_DEATH(
329 {
330 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700331 ReadConfig(ArtifactPath("aos/testdata/invalid_source_node.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800332 },
333 "source_node");
334
335 EXPECT_DEATH(
336 {
Austin Schuh373f1762021-06-02 21:07:09 -0700337 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
338 ArtifactPath("aos/testdata/invalid_destination_node.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800339 },
340 "destination_nodes");
341
342 EXPECT_DEATH(
343 {
344 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700345 ReadConfig(ArtifactPath("aos/testdata/self_forward.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800346 },
347 "forwarding data to itself");
348}
349
350// Tests that our node writeable helpers work as intended.
351TEST_F(ConfigurationTest, ChannelIsSendableOnNode) {
352 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800353 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800354 "name": "/test",
355 "type": "aos.examples.Ping",
356 "source_node": "foo"
357})channel",
358 Channel::MiniReflectTypeTable()));
359
360 FlatbufferDetachedBuffer<Channel> bad_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800361 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800362 "name": "/test",
363 "type": "aos.examples.Ping",
364 "source_node": "bar"
365})channel",
366 Channel::MiniReflectTypeTable()));
367
368 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800369 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800370 "name": "foo"
371})node",
372 Node::MiniReflectTypeTable()));
373
374 EXPECT_TRUE(
375 ChannelIsSendableOnNode(&good_channel.message(), &node.message()));
376 EXPECT_FALSE(
377 ChannelIsSendableOnNode(&bad_channel.message(), &node.message()));
378}
379
380// Tests that our node readable and writeable helpers work as intended.
381TEST_F(ConfigurationTest, ChannelIsReadableOnNode) {
382 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800383 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800384 "name": "/test",
385 "type": "aos.examples.Ping",
386 "source_node": "bar",
387 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800388 {
389 "name": "baz"
390 },
391 {
392 "name": "foo"
393 }
Austin Schuh217a9782019-12-21 23:02:50 -0800394 ]
395})channel",
396 Channel::MiniReflectTypeTable()));
397
398 FlatbufferDetachedBuffer<Channel> bad_channel1(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800399 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800400 "name": "/test",
401 "type": "aos.examples.Ping",
402 "source_node": "bar"
403})channel",
404 Channel::MiniReflectTypeTable()));
405
406 FlatbufferDetachedBuffer<Channel> bad_channel2(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800407 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800408 "name": "/test",
409 "type": "aos.examples.Ping",
410 "source_node": "bar",
411 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800412 {
413 "name": "baz"
414 }
Austin Schuh217a9782019-12-21 23:02:50 -0800415 ]
416})channel",
417 Channel::MiniReflectTypeTable()));
418
419 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800420 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800421 "name": "foo"
422})node",
423 Node::MiniReflectTypeTable()));
424
425 EXPECT_TRUE(
426 ChannelIsReadableOnNode(&good_channel.message(), &node.message()));
427 EXPECT_FALSE(
428 ChannelIsReadableOnNode(&bad_channel1.message(), &node.message()));
429 EXPECT_FALSE(
430 ChannelIsReadableOnNode(&bad_channel2.message(), &node.message()));
431}
432
Austin Schuh719946b2019-12-28 14:51:01 -0800433// Tests that our node message is logged helpers work as intended.
434TEST_F(ConfigurationTest, ChannelMessageIsLoggedOnNode) {
435 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
436 R"channel({
437 "name": "/test",
438 "type": "aos.examples.Ping",
439 "source_node": "bar",
440 "destination_nodes": [
441 {
442 "name": "baz"
443 }
444 ]
445})channel",
446 Channel::MiniReflectTypeTable()));
Austin Schuh217a9782019-12-21 23:02:50 -0800447
Austin Schuh719946b2019-12-28 14:51:01 -0800448 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
449 R"channel({
450 "name": "/test",
451 "type": "aos.examples.Ping",
452 "source_node": "bar",
453 "logger": "NOT_LOGGED",
454 "destination_nodes": [
455 {
456 "name": "baz",
457 "timestamp_logger": "LOCAL_LOGGER"
458 }
459 ]
460})channel",
461 Channel::MiniReflectTypeTable()));
462
463 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
464 R"channel({
465 "name": "/test",
466 "type": "aos.examples.Ping",
467 "source_node": "bar",
468 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700469 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800470 "destination_nodes": [
471 {
472 "name": "baz"
473 }
474 ]
475})channel",
476 Channel::MiniReflectTypeTable()));
477
478 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
479 JsonToFlatbuffer(
480 R"channel({
481 "name": "/test",
482 "type": "aos.examples.Ping",
483 "source_node": "bar",
484 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700485 "logger_nodes": ["foo"],
Austin Schuh719946b2019-12-28 14:51:01 -0800486 "destination_nodes": [
487 {
488 "name": "baz"
489 }
490 ]
491})channel",
492 Channel::MiniReflectTypeTable()));
493
Ravago Jonescf453ab2020-05-06 21:14:53 -0700494 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
495 R"channel({
Austin Schuh719946b2019-12-28 14:51:01 -0800496 "name": "/test",
497 "type": "aos.examples.Ping",
498 "source_node": "bar",
499 "logger": "LOCAL_AND_REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700500 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800501 "destination_nodes": [
502 {
503 "name": "baz"
504 }
505 ]
506})channel",
Ravago Jonescf453ab2020-05-06 21:14:53 -0700507 Channel::MiniReflectTypeTable()));
Austin Schuh719946b2019-12-28 14:51:01 -0800508
509 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
510 R"node({
511 "name": "foo"
512})node",
513 Node::MiniReflectTypeTable()));
514
515 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
516 R"node({
517 "name": "bar"
518})node",
519 Node::MiniReflectTypeTable()));
520
521 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
522 R"node({
523 "name": "baz"
524})node",
525 Node::MiniReflectTypeTable()));
526
527 // Local logger.
528 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
529 &foo_node.message()));
530 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
531 &bar_node.message()));
532 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
533 &baz_node.message()));
Austin Schuh48e94502021-06-18 18:35:53 -0700534 EXPECT_TRUE(
535 ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(), nullptr));
Austin Schuh719946b2019-12-28 14:51:01 -0800536
537 // No logger.
538 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
539 &foo_node.message()));
540 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
Ravago Jonescf453ab2020-05-06 21:14:53 -0700541 &bar_node.message()));
Austin Schuh719946b2019-12-28 14:51:01 -0800542 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
543 &baz_node.message()));
Austin Schuh48e94502021-06-18 18:35:53 -0700544 EXPECT_FALSE(
545 ChannelMessageIsLoggedOnNode(&not_logged_channel.message(), nullptr));
Austin Schuh719946b2019-12-28 14:51:01 -0800546
547 // Remote logger.
548 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
549 &foo_node.message()));
550 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
551 &bar_node.message()));
552 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
553 &baz_node.message()));
554
555 // Separate logger.
556 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(
557 &logged_on_separate_logger_node_channel.message(), &foo_node.message()));
558 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
559 &logged_on_separate_logger_node_channel.message(), &bar_node.message()));
560 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
561 &logged_on_separate_logger_node_channel.message(), &baz_node.message()));
562
563 // Logged in multiple places.
564 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
565 &foo_node.message()));
566 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
567 &bar_node.message()));
568 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
569 &baz_node.message()));
570}
571
Austin Schuh48e94502021-06-18 18:35:53 -0700572// Tests that our node message is logged helpers work as intended.
573TEST_F(ConfigurationDeathTest, ChannelMessageIsLoggedOnNode) {
574 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
575 R"channel({
576 "name": "/test",
577 "type": "aos.examples.Ping",
578 "source_node": "bar",
579 "logger": "LOCAL_AND_REMOTE_LOGGER",
580 "logger_nodes": ["baz"],
581 "destination_nodes": [
582 {
583 "name": "baz"
584 }
585 ]
586})channel",
587 Channel::MiniReflectTypeTable()));
588
589 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
590 JsonToFlatbuffer(
591 R"channel({
592 "name": "/test",
593 "type": "aos.examples.Ping",
594 "source_node": "bar",
595 "logger": "REMOTE_LOGGER",
596 "logger_nodes": ["foo"],
597 "destination_nodes": [
598 {
599 "name": "baz"
600 }
601 ]
602})channel",
603 Channel::MiniReflectTypeTable()));
604
605 EXPECT_DEATH(
606 {
607 ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
608 nullptr);
609 },
610 "Unsupported logging configuration in a single node world");
611 EXPECT_DEATH(
612 {
613 ChannelMessageIsLoggedOnNode(
614 &logged_on_separate_logger_node_channel.message(), nullptr);
615 },
616 "Unsupported logging configuration in a single node world");
617}
618
Austin Schuh719946b2019-12-28 14:51:01 -0800619// Tests that our forwarding timestamps are logged helpers work as intended.
620TEST_F(ConfigurationTest, ConnectionDeliveryTimeIsLoggedOnNode) {
621 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
622 R"channel({
623 "name": "/test",
624 "type": "aos.examples.Ping",
625 "source_node": "bar",
626 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700627 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800628 "destination_nodes": [
629 {
630 "name": "baz"
631 }
632 ]
633})channel",
634 Channel::MiniReflectTypeTable()));
635
636 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
637 R"channel({
638 "name": "/test",
639 "type": "aos.examples.Ping",
640 "source_node": "bar",
641 "logger": "NOT_LOGGED",
642 "destination_nodes": [
643 {
644 "name": "baz",
645 "timestamp_logger": "NOT_LOGGED"
646 }
647 ]
648})channel",
649 Channel::MiniReflectTypeTable()));
650
651 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
652 R"channel({
653 "name": "/test",
654 "type": "aos.examples.Ping",
655 "source_node": "bar",
656 "destination_nodes": [
657 {
658 "name": "baz",
659 "timestamp_logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700660 "timestamp_logger_nodes": ["bar"]
Austin Schuh719946b2019-12-28 14:51:01 -0800661 }
662 ]
663})channel",
664 Channel::MiniReflectTypeTable()));
665
666 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
667 JsonToFlatbuffer(
668 R"channel({
669 "name": "/test",
670 "type": "aos.examples.Ping",
671 "source_node": "bar",
672 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700673 "logger_nodes": ["foo"],
Austin Schuh719946b2019-12-28 14:51:01 -0800674 "destination_nodes": [
675 {
676 "name": "baz",
677 "timestamp_logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700678 "timestamp_logger_nodes": ["foo"]
Austin Schuh719946b2019-12-28 14:51:01 -0800679 }
680 ]
681})channel",
682 Channel::MiniReflectTypeTable()));
683
Ravago Jonescf453ab2020-05-06 21:14:53 -0700684 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
685 R"channel({
Austin Schuh719946b2019-12-28 14:51:01 -0800686 "name": "/test",
687 "type": "aos.examples.Ping",
688 "source_node": "bar",
689 "destination_nodes": [
690 {
691 "name": "baz",
692 "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700693 "timestamp_logger_nodes": ["bar"]
Austin Schuh719946b2019-12-28 14:51:01 -0800694 }
695 ]
696})channel",
Ravago Jonescf453ab2020-05-06 21:14:53 -0700697 Channel::MiniReflectTypeTable()));
Austin Schuh719946b2019-12-28 14:51:01 -0800698
699 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
700 R"node({
701 "name": "foo"
702})node",
703 Node::MiniReflectTypeTable()));
704
705 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
706 R"node({
707 "name": "bar"
708})node",
709 Node::MiniReflectTypeTable()));
710
711 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
712 R"node({
713 "name": "baz"
714})node",
715 Node::MiniReflectTypeTable()));
716
717 // Local logger.
718 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
719 &logged_on_self_channel.message(), &baz_node.message(),
720 &foo_node.message()));
721 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
722 &logged_on_self_channel.message(), &baz_node.message(),
723 &bar_node.message()));
724 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
725 &logged_on_self_channel.message(), &baz_node.message(),
726 &baz_node.message()));
727
728 // No logger means.
729 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
730 &not_logged_channel.message(), &baz_node.message(), &foo_node.message()));
731 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
732 &not_logged_channel.message(), &baz_node.message(), &bar_node.message()));
733 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
734 &not_logged_channel.message(), &baz_node.message(), &baz_node.message()));
735
736 // Remote logger.
737 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
738 &logged_on_remote_channel.message(), &baz_node.message(),
739 &foo_node.message()));
740 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
741 &logged_on_remote_channel.message(), &baz_node.message(),
742 &bar_node.message()));
743 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
744 &logged_on_remote_channel.message(), &baz_node.message(),
745 &baz_node.message()));
746
747 // Separate logger.
748 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
749 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
750 &foo_node.message()));
751 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
752 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
753 &bar_node.message()));
754 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
755 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
756 &baz_node.message()));
757
758 // Logged on both the node and a remote node.
759 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
760 &logged_on_both_channel.message(), &baz_node.message(),
761 &foo_node.message()));
762 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
763 &logged_on_both_channel.message(), &baz_node.message(),
764 &bar_node.message()));
765 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
766 &logged_on_both_channel.message(), &baz_node.message(),
767 &baz_node.message()));
768}
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800769
770// Tests that we can deduce source nodes from a multinode config.
771TEST_F(ConfigurationTest, SourceNodeNames) {
772 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700773 ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800774
775 // This is a bit simplistic in that it doesn't test deduplication, but it does
776 // exercise a lot of the logic.
777 EXPECT_THAT(
778 SourceNodeNames(&config.message(), config.message().nodes()->Get(0)),
779 ::testing::ElementsAreArray({"pi2"}));
780 EXPECT_THAT(
781 SourceNodeNames(&config.message(), config.message().nodes()->Get(1)),
782 ::testing::ElementsAreArray({"pi1"}));
783}
784
785// Tests that we can deduce destination nodes from a multinode config.
786TEST_F(ConfigurationTest, DestinationNodeNames) {
787 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700788 ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800789
790 // This is a bit simplistic in that it doesn't test deduplication, but it does
791 // exercise a lot of the logic.
792 EXPECT_THAT(
793 DestinationNodeNames(&config.message(), config.message().nodes()->Get(0)),
794 ::testing::ElementsAreArray({"pi2"}));
795 EXPECT_THAT(
796 DestinationNodeNames(&config.message(), config.message().nodes()->Get(1)),
797 ::testing::ElementsAreArray({"pi1"}));
798}
799
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800800// Tests that we can pull out all the nodes.
801TEST_F(ConfigurationTest, GetNodes) {
802 {
803 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700804 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800805 const Node *pi1 = GetNode(&config.message(), "pi1");
806 const Node *pi2 = GetNode(&config.message(), "pi2");
807
808 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(pi1, pi2));
809 }
810
811 {
812 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700813 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800814 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(nullptr));
815 }
816}
817
Austin Schuh65465332020-11-05 17:36:53 -0800818// Tests that we can pull out all the nodes with a tag.
819TEST_F(ConfigurationTest, GetNodesWithTag) {
820 {
821 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700822 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuh65465332020-11-05 17:36:53 -0800823 const Node *pi1 = GetNode(&config.message(), "pi1");
824 const Node *pi2 = GetNode(&config.message(), "pi2");
825
826 EXPECT_THAT(GetNodesWithTag(&config.message(), "a"),
827 ::testing::ElementsAre(pi1));
828 EXPECT_THAT(GetNodesWithTag(&config.message(), "b"),
829 ::testing::ElementsAre(pi2));
830 EXPECT_THAT(GetNodesWithTag(&config.message(), "c"),
831 ::testing::ElementsAre(pi1, pi2));
832 }
833
834 {
835 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700836 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuh65465332020-11-05 17:36:53 -0800837 EXPECT_THAT(GetNodesWithTag(&config.message(), "arglfish"),
838 ::testing::ElementsAre(nullptr));
839 }
840}
841
Brian Silverman631b6262021-11-10 12:25:08 -0800842// Tests that we can check if a node has a tag.
843TEST_F(ConfigurationTest, NodeHasTag) {
844 {
845 FlatbufferDetachedBuffer<Configuration> config =
846 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
847 const Node *pi1 = GetNode(&config.message(), "pi1");
848 const Node *pi2 = GetNode(&config.message(), "pi2");
849
850 EXPECT_TRUE(NodeHasTag(pi1, "a"));
851 EXPECT_FALSE(NodeHasTag(pi2, "a"));
852 EXPECT_FALSE(NodeHasTag(pi1, "b"));
853 EXPECT_TRUE(NodeHasTag(pi2, "b"));
854 EXPECT_TRUE(NodeHasTag(pi1, "c"));
855 EXPECT_TRUE(NodeHasTag(pi2, "c"));
856 EXPECT_FALSE(NodeHasTag(pi1, "nope"));
857 EXPECT_FALSE(NodeHasTag(pi2, "nope"));
858 }
859
860 EXPECT_TRUE(NodeHasTag(nullptr, "arglfish"));
861}
862
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800863// Tests that we can extract a node index from a config.
864TEST_F(ConfigurationTest, GetNodeIndex) {
865 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700866 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuh04408fc2020-02-16 21:48:54 -0800867 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh373f1762021-06-02 21:07:09 -0700868 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800869 const Node *pi1 = GetNode(&config.message(), "pi1");
870 const Node *pi2 = GetNode(&config.message(), "pi2");
871
Austin Schuh04408fc2020-02-16 21:48:54 -0800872 // Try the normal case.
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800873 EXPECT_EQ(GetNodeIndex(&config.message(), pi1), 0);
874 EXPECT_EQ(GetNodeIndex(&config.message(), pi2), 1);
Austin Schuh04408fc2020-02-16 21:48:54 -0800875
876 // Now try if we have node pointers from a different message.
877 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1), 0);
878 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2), 1);
879
880 // And now try string names.
881 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1->name()->string_view()), 0);
882 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2->name()->string_view()), 1);
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800883}
884
885// Tests that GetNodeOrDie handles both single and multi-node worlds and returns
886// valid nodes.
887TEST_F(ConfigurationDeathTest, GetNodeOrDie) {
888 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700889 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800890 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh373f1762021-06-02 21:07:09 -0700891 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800892 {
893 // Simple case, nullptr -> nullptr
894 FlatbufferDetachedBuffer<Configuration> single_node_config =
Austin Schuh373f1762021-06-02 21:07:09 -0700895 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800896 EXPECT_EQ(nullptr, GetNodeOrDie(&single_node_config.message(), nullptr));
897
898 // Confirm that we die when a node is passed in.
899 EXPECT_DEATH(
900 {
901 GetNodeOrDie(&single_node_config.message(),
902 config.message().nodes()->Get(0));
903 },
904 "Provided a node in a single node world.");
905 }
906
907 const Node *pi1 = GetNode(&config.message(), "pi1");
908 // Now try a lookup using a node from a different instance of the config.
909 EXPECT_EQ(pi1,
910 GetNodeOrDie(&config.message(), config2.message().nodes()->Get(0)));
911}
912
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800913TEST_F(ConfigurationTest, GetNodeFromHostname) {
914 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700915 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800916 EXPECT_EQ("pi1",
917 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
918 ->name()
919 ->string_view());
920 EXPECT_EQ("pi2", CHECK_NOTNULL(
921 GetNodeFromHostname(&config.message(), "raspberrypi2"))
922 ->name()
923 ->string_view());
924 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi3"));
925 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
926 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
927}
928
929TEST_F(ConfigurationTest, GetNodeFromHostnames) {
930 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700931 ReadConfig(ArtifactPath("aos/testdata/good_multinode_hostnames.json"));
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800932 EXPECT_EQ("pi1",
933 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
934 ->name()
935 ->string_view());
936 EXPECT_EQ("pi2", CHECK_NOTNULL(
937 GetNodeFromHostname(&config.message(), "raspberrypi2"))
938 ->name()
939 ->string_view());
940 EXPECT_EQ("pi2", CHECK_NOTNULL(
941 GetNodeFromHostname(&config.message(), "raspberrypi3"))
942 ->name()
943 ->string_view());
Ravago Jonescf453ab2020-05-06 21:14:53 -0700944 EXPECT_EQ("pi2",
945 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "other"))
946 ->name()
947 ->string_view());
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800948 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi4"));
949 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
950 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
951}
952
Austin Schuhfc7b6a02021-07-12 21:19:07 -0700953// Tests that SourceNodeIndex reasonably handles a multi-node log file.
954TEST_F(ConfigurationTest, SourceNodeIndex) {
955 FlatbufferDetachedBuffer<Configuration> config =
956 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
957 std::vector<size_t> result = SourceNodeIndex(&config.message());
958
959 EXPECT_THAT(result, ::testing::ElementsAreArray({0, 1, 0, 0}));
960}
961
Austin Schuh5e95bd62021-10-11 18:40:22 -0700962// Tests that we reject invalid logging configurations.
963TEST_F(ConfigurationDeathTest, InvalidLoggerConfig) {
964 EXPECT_DEATH(
965 {
Milind Upadhyay17098ba2022-04-15 22:18:50 -0700966 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
967 ArtifactPath("aos/testdata/invalid_logging_configuration.json"));
Austin Schuh5e95bd62021-10-11 18:40:22 -0700968 },
969 "Logging timestamps without data");
970}
971
Austin Schuha156fb22021-10-11 19:23:21 -0700972// Tests that we reject duplicate timestamp destination node configurations.
973TEST_F(ConfigurationDeathTest, DuplicateTimestampDestinationNodes) {
974 EXPECT_DEATH(
975 {
976 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
977 ArtifactPath("aos/testdata/duplicate_destination_nodes.json"));
978 },
979 "Found duplicate timestamp_logger_nodes in");
980}
981
982// Tests that we reject duplicate logger node configurations for a channel's
983// data.
984TEST_F(ConfigurationDeathTest, DuplicateLoggerNodes) {
985 EXPECT_DEATH(
986 {
987 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
988 ArtifactPath("aos/testdata/duplicate_logger_nodes.json"));
989 },
990 "Found duplicate logger_nodes in");
991}
992
Austin Schuhfb37c612022-08-11 15:24:51 -0700993// Tests that we properly compute the queue size for the provided duration.
994TEST_F(ConfigurationTest, QueueSize) {
995 EXPECT_EQ(QueueSize(100, chrono::seconds(2)), 200);
996 EXPECT_EQ(QueueSize(200, chrono::seconds(2)), 400);
997 EXPECT_EQ(QueueSize(100, chrono::seconds(6)), 600);
998 EXPECT_EQ(QueueSize(100, chrono::milliseconds(10)), 1);
999 EXPECT_EQ(QueueSize(100, chrono::milliseconds(10) - chrono::nanoseconds(1)),
1000 1);
1001 EXPECT_EQ(QueueSize(100, chrono::milliseconds(10) - chrono::nanoseconds(2)),
1002 1);
1003}
1004
1005// Tests that we compute scratch buffer size correctly too.
1006TEST_F(ConfigurationTest, QueueScratchBufferSize) {
1007 const aos::FlatbufferDetachedBuffer<Channel> channel =
1008 JsonToFlatbuffer<Channel>(
1009 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"num_readers\": 5, "
1010 "\"num_senders\": 10 }");
Austin Schuhfb37c612022-08-11 15:24:51 -07001011 EXPECT_EQ(QueueScratchBufferSize(&channel.message()), 15);
1012}
1013
Nathan Leong307c9692022-10-08 15:25:03 -07001014// Tests that GetSchema returns schema of specified type
1015TEST_F(ConfigurationTest, GetSchema) {
1016 FlatbufferDetachedBuffer<Configuration> config =
1017 ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
1018 FlatbufferVector<reflection::Schema> expected_schema =
1019 FileToFlatbuffer<reflection::Schema>(
1020 ArtifactPath("aos/events/ping.bfbs"));
1021 EXPECT_EQ(FlatbufferToJson(GetSchema(&config.message(), "aos.examples.Ping")),
1022 FlatbufferToJson(expected_schema));
1023 EXPECT_EQ(GetSchema(&config.message(), "invalid_name"), nullptr);
1024}
1025
1026// Tests that GetSchema template returns schema of specified type
1027TEST_F(ConfigurationTest, GetSchemaTemplate) {
1028 FlatbufferDetachedBuffer<Configuration> config =
1029 ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
1030 FlatbufferVector<reflection::Schema> expected_schema =
1031 FileToFlatbuffer<reflection::Schema>(
1032 ArtifactPath("aos/events/ping.bfbs"));
1033 EXPECT_EQ(FlatbufferToJson(GetSchema<aos::examples::Ping>(&config.message())),
1034 FlatbufferToJson(expected_schema));
1035}
1036
1037// Tests that GetSchemaDetachedBuffer returns detached buffer of specified type
1038TEST_F(ConfigurationTest, GetSchemaDetachedBuffer) {
1039 FlatbufferDetachedBuffer<Configuration> config =
1040 ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
1041 FlatbufferVector<reflection::Schema> expected_schema =
1042 FileToFlatbuffer<reflection::Schema>(
1043 ArtifactPath("aos/events/ping.bfbs"));
1044 EXPECT_EQ(FlatbufferToJson(
1045 GetSchemaDetachedBuffer(&config.message(), "aos.examples.Ping")
1046 .value()),
1047 FlatbufferToJson(expected_schema));
1048 EXPECT_EQ(GetSchemaDetachedBuffer(&config.message(), "invalid_name"),
1049 std::nullopt);
1050}
1051
James Kuszmaul741a4d02023-01-05 14:59:21 -08001052// Tests that we can use a utility to add individual channels to a single-node
1053// config.
1054TEST_F(ConfigurationTest, AddChannelToConfigSingleNode) {
1055 FlatbufferDetachedBuffer<Configuration> base_config =
1056 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
1057
1058 FlatbufferVector<reflection::Schema> schema =
1059 FileToFlatbuffer<reflection::Schema>(
1060 ArtifactPath("aos/events/ping.bfbs"));
1061
1062 FlatbufferDetachedBuffer<Configuration> new_config =
1063 AddChannelToConfiguration(&base_config.message(), "/new", schema);
1064
1065 ASSERT_EQ(new_config.message().channels()->size(),
1066 base_config.message().channels()->size() + 1);
1067
1068 const Channel *channel =
1069 GetChannel(new_config, "/new", "aos.examples.Ping", "", nullptr);
1070 ASSERT_TRUE(channel != nullptr);
1071 ASSERT_TRUE(channel->has_schema());
1072 // Check that we don't populate channel settings that we don't override the
1073 // defaults of.
1074 ASSERT_FALSE(channel->has_frequency());
1075}
1076
1077// Tests that we can use a utility to add individual channels to a multi-node
1078// config.
1079TEST_F(ConfigurationTest, AddChannelToConfigMultiNode) {
1080 FlatbufferDetachedBuffer<Configuration> base_config =
1081 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
1082
1083 FlatbufferVector<reflection::Schema> schema =
1084 FileToFlatbuffer<reflection::Schema>(
1085 ArtifactPath("aos/events/ping.bfbs"));
1086
1087 aos::ChannelT channel_overrides;
1088 channel_overrides.frequency = 971;
1089 FlatbufferDetachedBuffer<Configuration> new_config =
1090 AddChannelToConfiguration(&base_config.message(), "/new", schema,
1091 GetNode(&base_config.message(), "pi1"),
1092 channel_overrides);
1093
1094 ASSERT_EQ(new_config.message().channels()->size(),
1095 base_config.message().channels()->size() + 1);
1096
1097 const Channel *channel =
1098 GetChannel(new_config, "/new", "aos.examples.Ping", "", nullptr);
1099 ASSERT_TRUE(channel != nullptr);
1100 ASSERT_TRUE(channel->has_schema());
1101 ASSERT_TRUE(channel->has_source_node());
1102 ASSERT_EQ("pi1", channel->source_node()->string_view());
1103 ASSERT_EQ(971, channel->frequency());
1104}
1105
Austin Schuhcb108412019-10-13 16:09:54 -07001106} // namespace testing
1107} // namespace configuration
1108} // namespace aos