blob: 560e5eb972eb3f61db9a1b8304525d5bc688275b [file] [log] [blame]
Austin Schuhcb108412019-10-13 16:09:54 -07001#include "aos/configuration.h"
2
3#include "absl/strings/strip.h"
Philipp Schrader790cb542023-07-05 21:06:52 -07004#include "flatbuffers/reflection.h"
5#include "glog/logging.h"
6#include "gmock/gmock.h"
7#include "gtest/gtest.h"
8
Nathan Leong307c9692022-10-08 15:25:03 -07009#include "aos/events/ping_generated.h"
Austin Schuhcb108412019-10-13 16:09:54 -070010#include "aos/json_to_flatbuffer.h"
Austin Schuh1ef01ef2021-02-07 20:40:36 -080011#include "aos/testing/flatbuffer_eq.h"
Austin Schuh373f1762021-06-02 21:07:09 -070012#include "aos/testing/path.h"
Austin Schuhcb108412019-10-13 16:09:54 -070013#include "aos/testing/test_logging.h"
14#include "aos/util/file.h"
Austin Schuhcb108412019-10-13 16:09:54 -070015
16namespace aos {
17namespace configuration {
18namespace testing {
19
Austin Schuh373f1762021-06-02 21:07:09 -070020using aos::testing::ArtifactPath;
Austin Schuhfb37c612022-08-11 15:24:51 -070021namespace chrono = std::chrono;
Austin Schuh66602132020-02-28 13:38:37 -080022
Austin Schuhcb108412019-10-13 16:09:54 -070023class ConfigurationTest : public ::testing::Test {
24 public:
25 ConfigurationTest() { ::aos::testing::EnableTestLogging(); }
26};
27
28typedef ConfigurationTest ConfigurationDeathTest;
29
30// *the* expected location for all working tests.
Austin Schuh1ef01ef2021-02-07 20:40:36 -080031aos::FlatbufferDetachedBuffer<Channel> ExpectedLocation() {
32 return JsonToFlatbuffer<Channel>(
33 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5 }");
34}
35
Austin Schuhbca6cf02019-12-22 17:28:34 -080036// And for multinode setups
Austin Schuh1ef01ef2021-02-07 20:40:36 -080037aos::FlatbufferDetachedBuffer<Channel> ExpectedMultinodeLocation() {
38 return JsonToFlatbuffer<Channel>(
39 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5, "
40 "\"source_node\": \"pi1\" }");
41}
Austin Schuhcb108412019-10-13 16:09:54 -070042
43// Tests that we can read and merge a configuration.
44TEST_F(ConfigurationTest, ConfigMerge) {
Austin Schuh40485ed2019-10-26 21:51:44 -070045 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070046 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Ravago Jonescf453ab2020-05-06 21:14:53 -070047 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuhcb108412019-10-13 16:09:54 -070048
Austin Schuh373f1762021-06-02 21:07:09 -070049 EXPECT_EQ(absl::StripSuffix(util::ReadFileToStringOrDie(
50 ArtifactPath("aos/testdata/expected.json")),
51 "\n"),
52 FlatbufferToJson(config, {.multi_line = true}));
Austin Schuhcb108412019-10-13 16:09:54 -070053}
54
Austin Schuhc9e10ec2020-01-26 16:08:28 -080055// Tests that we can get back a ChannelIndex.
56TEST_F(ConfigurationTest, ChannelIndex) {
57 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070058 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -080059
60 EXPECT_EQ(
61 ChannelIndex(&config.message(), config.message().channels()->Get(1u)),
62 1u);
63}
64
Austin Schuh217a9782019-12-21 23:02:50 -080065// Tests that we can read and merge a multinode configuration.
66TEST_F(ConfigurationTest, ConfigMergeMultinode) {
67 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070068 ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
Ravago Jonescf453ab2020-05-06 21:14:53 -070069 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuh217a9782019-12-21 23:02:50 -080070
Ravago Jonescf453ab2020-05-06 21:14:53 -070071 EXPECT_EQ(std::string(absl::StripSuffix(
Austin Schuh373f1762021-06-02 21:07:09 -070072 util::ReadFileToStringOrDie(
73 ArtifactPath("aos/testdata/expected_multinode.json")),
Ravago Jonescf453ab2020-05-06 21:14:53 -070074 "\n")),
75 FlatbufferToJson(config, {.multi_line = true}));
Austin Schuh217a9782019-12-21 23:02:50 -080076}
77
Alex Perrycb7da4b2019-08-28 19:35:56 -070078// Tests that we sort the entries in a config so we can look entries up.
79TEST_F(ConfigurationTest, UnsortedConfig) {
80 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070081 ReadConfig(ArtifactPath("aos/testdata/backwards.json"));
Alex Perrycb7da4b2019-08-28 19:35:56 -070082
Ravago Jonescf453ab2020-05-06 21:14:53 -070083 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Alex Perrycb7da4b2019-08-28 19:35:56 -070084
Austin Schuhf1fff282020-03-28 16:57:32 -070085 EXPECT_EQ(FlatbufferToJson(GetChannel(config, "/aos/robot_state",
Austin Schuhbca6cf02019-12-22 17:28:34 -080086 "aos.RobotState", "app1", nullptr)),
Austin Schuhf1fff282020-03-28 16:57:32 -070087 "{ \"name\": \"/aos/robot_state\", \"type\": \"aos.RobotState\", "
Alex Perrycb7da4b2019-08-28 19:35:56 -070088 "\"max_size\": 5 }");
89}
90
Austin Schuhcb108412019-10-13 16:09:54 -070091// Tests that we die when a file is imported twice.
92TEST_F(ConfigurationDeathTest, DuplicateFile) {
93 EXPECT_DEATH(
94 {
Austin Schuh40485ed2019-10-26 21:51:44 -070095 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070096 ReadConfig(ArtifactPath("aos/testdata/config1_bad.json"));
Austin Schuhcb108412019-10-13 16:09:54 -070097 },
Austin Schuh373f1762021-06-02 21:07:09 -070098 "aos/testdata/config1_bad.json");
Austin Schuhcb108412019-10-13 16:09:54 -070099}
100
Milind Upadhyay17098ba2022-04-15 22:18:50 -0700101// Tests that we die when we give an invalid path.
102TEST_F(ConfigurationDeathTest, NonexistentFile) {
103 EXPECT_DEATH(
104 {
105 FlatbufferDetachedBuffer<Configuration> config =
106 ReadConfig("nonexistent/config.json");
107 },
108 "above error");
109}
110
111// Tests that we return std::nullopt when we give an invalid path.
112TEST_F(ConfigurationTest, NonexistentFileOptional) {
113 std::optional<FlatbufferDetachedBuffer<Configuration>> config =
114 MaybeReadConfig("nonexistent/config.json");
115 EXPECT_FALSE(config.has_value());
116}
117
Austin Schuhf1fff282020-03-28 16:57:32 -0700118// Tests that we reject invalid channel names. This means any channels with //
119// in their name, a trailing /, or regex characters.
120TEST_F(ConfigurationDeathTest, InvalidChannelName) {
121 EXPECT_DEATH(
122 {
123 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700124 ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name1.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700125 },
126 "Channel names can't end with '/'");
127 EXPECT_DEATH(
128 {
129 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700130 ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name2.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700131 },
132 "Invalid channel name");
133 EXPECT_DEATH(
134 {
135 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700136 ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name3.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700137 LOG(FATAL) << "Foo";
138 },
139 "Invalid channel name");
Austin Schuh47e382e2023-05-28 11:20:56 -0700140 EXPECT_DEATH(
141 {
142 FlatbufferDetachedBuffer<Configuration> config =
143 ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name4.json"));
144 LOG(FATAL) << "Foo";
145 },
146 "Channel names must start with '/'");
Austin Schuhf1fff282020-03-28 16:57:32 -0700147}
148
Austin Schuh8d6cea82020-02-28 12:17:16 -0800149// Tests that we can modify a config with a json snippet.
150TEST_F(ConfigurationTest, MergeWithConfig) {
151 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700152 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Ravago Jonescf453ab2020-05-06 21:14:53 -0700153 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuh8d6cea82020-02-28 12:17:16 -0800154
155 FlatbufferDetachedBuffer<Configuration> updated_config =
156 MergeWithConfig(&config.message(),
157 R"channel({
158 "channels": [
159 {
160 "name": "/foo",
161 "type": ".aos.bar",
162 "max_size": 100
163 }
164 ]
165})channel");
166
Austin Schuh373f1762021-06-02 21:07:09 -0700167 EXPECT_EQ(absl::StripSuffix(util::ReadFileToStringOrDie(ArtifactPath(
168 "aos/testdata/expected_merge_with.json")),
Ravago Jonescf453ab2020-05-06 21:14:53 -0700169 "\n"),
170 FlatbufferToJson(updated_config, {.multi_line = true}));
Austin Schuh8d6cea82020-02-28 12:17:16 -0800171}
172
Austin Schuhcb108412019-10-13 16:09:54 -0700173// Tests that we can lookup a location, complete with maps, from a merged
174// config.
Austin Schuh40485ed2019-10-26 21:51:44 -0700175TEST_F(ConfigurationTest, GetChannel) {
176 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700177 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhcb108412019-10-13 16:09:54 -0700178
179 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800180 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", nullptr),
181 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700182
183 // Test that an invalid name results in nullptr back.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800184 EXPECT_EQ(GetChannel(config, "/invalid_name", ".aos.bar", "app1", nullptr),
185 nullptr);
Austin Schuhcb108412019-10-13 16:09:54 -0700186
187 // Tests that a root map/rename works. And that they get processed from the
188 // bottom up.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800189 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", nullptr),
190 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700191
192 // And then test that an application specific map/rename works.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800193 EXPECT_THAT(GetChannel(config, "/bar", ".aos.bar", "app1", nullptr),
194 aos::testing::FlatbufferEq(ExpectedLocation()));
195 EXPECT_THAT(GetChannel(config, "/baz", ".aos.bar", "app2", nullptr),
196 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700197
198 // And then test that an invalid application name gets properly ignored.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800199 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app3", nullptr),
200 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800201}
202
James Kuszmaulc8503f32022-06-25 16:17:12 -0700203// Tests that we can do reverse-lookups of channel names.
204TEST_F(ConfigurationTest, GetChannelAliases) {
205 FlatbufferDetachedBuffer<Configuration> config =
206 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
207
208 // Test a basic lookup first.
209 EXPECT_THAT(
210 GetChannelAliases(&config.message(), "/foo", ".aos.bar", "app1", nullptr),
211 ::testing::UnorderedElementsAre("/foo", "/batman", "/bar"));
212 EXPECT_THAT(
213 GetChannelAliases(&config.message(), "/bar", ".aos.bar", "app1", nullptr),
214 ::testing::UnorderedElementsAre("/batman", "/bar"));
215 EXPECT_THAT(GetChannelAliases(&config.message(), "/batman", ".aos.bar",
216 "app1", nullptr),
217 ::testing::UnorderedElementsAre("/batman"));
218 // /bar (deliberately) does not get included because of the ordering in the
219 // map.
220 EXPECT_THAT(
221 GetChannelAliases(&config.message(), "/foo", ".aos.bar", "", nullptr),
222 ::testing::UnorderedElementsAre("/foo", "/batman"));
223 EXPECT_THAT(
224 GetChannelAliases(&config.message(), "/foo", ".aos.bar", "app2", nullptr),
225 ::testing::UnorderedElementsAre("/foo", "/batman", "/baz"));
226}
227
Austin Schuhbca6cf02019-12-22 17:28:34 -0800228// Tests that we can lookup a location with node specific maps.
229TEST_F(ConfigurationTest, GetChannelMultinode) {
230 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700231 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800232 const Node *pi1 = GetNode(&config.message(), "pi1");
233 const Node *pi2 = GetNode(&config.message(), "pi2");
234
235 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800236 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", pi1),
237 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
238 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", pi2),
239 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800240
241 // Tests that a root map/rename works with a node specific map.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800242 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", pi1),
243 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800244
245 // Tests that a root map/rename fails with a node specific map for the wrong
246 // node.
247 EXPECT_EQ(GetChannel(config, "/batman", ".aos.bar", "app1", pi2), nullptr);
248
249 // And then test that an application specific map/rename works.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800250 EXPECT_THAT(GetChannel(config, "/batman2", ".aos.bar", "app1", pi1),
251 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
252 EXPECT_THAT(GetChannel(config, "/batman3", ".aos.bar", "app1", pi1),
253 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800254
255 // And then that it fails when the node changes.
256 EXPECT_EQ(GetChannel(config, "/batman3", ".aos.bar", "app1", pi2), nullptr);
257}
258
James Kuszmaulc8503f32022-06-25 16:17:12 -0700259// Tests that reverse channel lookup on a multi-node config (including with
260// wildcards) works.
261TEST_F(ConfigurationTest, GetChannelAliasesMultinode) {
262 FlatbufferDetachedBuffer<Configuration> config =
263 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
264
265 const Node *pi1 = GetNode(&config.message(), "pi1");
266 const Node *pi2 = GetNode(&config.message(), "pi2");
267
268 EXPECT_THAT(
269 GetChannelAliases(&config.message(), "/foo", ".aos.bar", "app1", pi1),
270 ::testing::UnorderedElementsAre("/foo", "/batman", "/batman2", "/batman3",
271 "/magic/string"));
272
273 EXPECT_THAT(
274 GetChannelAliases(&config.message(), "/foo", ".aos.baz", "app1", pi1),
275 ::testing::UnorderedElementsAre("/foo", "/batman3", "/magic/string"));
276
277 EXPECT_THAT(
278 GetChannelAliases(&config.message(), "/foo/testing", ".aos.bar", "", pi1),
279 ::testing::UnorderedElementsAre("/foo/testing", "/magic/string/testing"));
280
281 EXPECT_THAT(
282 GetChannelAliases(&config.message(), "/foo/testing", ".aos.bar", "app1",
283 pi2),
284 ::testing::UnorderedElementsAre("/foo/testing", "/magic/string/testing"));
285}
286
Austin Schuhbca6cf02019-12-22 17:28:34 -0800287// Tests that we can lookup a location with type specific maps.
288TEST_F(ConfigurationTest, GetChannelTypedMultinode) {
289 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700290 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800291 const Node *pi1 = GetNode(&config.message(), "pi1");
292
293 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800294 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", pi1),
295 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800296
297 // Now confirm that a second message on the same name doesn't get remapped.
298 const char *kExpectedBazMultinodeLocation =
299 "{ \"name\": \"/batman\", \"type\": \".aos.baz\", \"max_size\": 5, "
300 "\"source_node\": \"pi1\" }";
301 EXPECT_EQ(
302 FlatbufferToJson(GetChannel(config, "/batman", ".aos.baz", "app1", pi1)),
303 kExpectedBazMultinodeLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700304}
305
Austin Schuhf1fff282020-03-28 16:57:32 -0700306// Tests that we can lookup a location with a glob
307TEST_F(ConfigurationTest, GetChannelGlob) {
308 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700309 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700310 const Node *pi1 = GetNode(&config.message(), "pi1");
311
312 // Confirm that a glob with nothing after it matches.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800313 EXPECT_THAT(GetChannel(config, "/magic/string", ".aos.bar", "app7", pi1),
314 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhf1fff282020-03-28 16:57:32 -0700315
316 // Now confirm that glob with something following it matches and renames
317 // correctly.
318 const char *kExpectedSubfolderMultinodeLocation =
319 "{ \"name\": \"/foo/subfolder\", \"type\": \".aos.bar\", \"max_size\": "
320 "5, \"source_node\": \"pi1\" }";
321 EXPECT_EQ(FlatbufferToJson(GetChannel(config, "/magic/string/subfolder",
322 ".aos.bar", "app7", pi1)),
323 kExpectedSubfolderMultinodeLocation);
324}
325
Austin Schuh217a9782019-12-21 23:02:50 -0800326// Tests that we reject a configuration which has a nodes list, but has channels
327// withoout source_node filled out.
328TEST_F(ConfigurationDeathTest, InvalidSourceNode) {
329 EXPECT_DEATH(
330 {
331 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700332 ReadConfig(ArtifactPath("aos/testdata/invalid_nodes.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800333 },
334 "source_node");
335
336 EXPECT_DEATH(
337 {
338 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700339 ReadConfig(ArtifactPath("aos/testdata/invalid_source_node.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800340 },
341 "source_node");
342
343 EXPECT_DEATH(
344 {
Austin Schuh373f1762021-06-02 21:07:09 -0700345 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
346 ArtifactPath("aos/testdata/invalid_destination_node.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800347 },
348 "destination_nodes");
349
350 EXPECT_DEATH(
351 {
352 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700353 ReadConfig(ArtifactPath("aos/testdata/self_forward.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800354 },
355 "forwarding data to itself");
356}
357
358// Tests that our node writeable helpers work as intended.
359TEST_F(ConfigurationTest, ChannelIsSendableOnNode) {
360 FlatbufferDetachedBuffer<Channel> good_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": "foo"
365})channel",
366 Channel::MiniReflectTypeTable()));
367
368 FlatbufferDetachedBuffer<Channel> bad_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800369 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800370 "name": "/test",
371 "type": "aos.examples.Ping",
372 "source_node": "bar"
373})channel",
374 Channel::MiniReflectTypeTable()));
375
376 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800377 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800378 "name": "foo"
379})node",
380 Node::MiniReflectTypeTable()));
381
382 EXPECT_TRUE(
383 ChannelIsSendableOnNode(&good_channel.message(), &node.message()));
384 EXPECT_FALSE(
385 ChannelIsSendableOnNode(&bad_channel.message(), &node.message()));
386}
387
388// Tests that our node readable and writeable helpers work as intended.
389TEST_F(ConfigurationTest, ChannelIsReadableOnNode) {
390 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800391 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800392 "name": "/test",
393 "type": "aos.examples.Ping",
394 "source_node": "bar",
395 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800396 {
397 "name": "baz"
398 },
399 {
400 "name": "foo"
401 }
Austin Schuh217a9782019-12-21 23:02:50 -0800402 ]
403})channel",
404 Channel::MiniReflectTypeTable()));
405
406 FlatbufferDetachedBuffer<Channel> bad_channel1(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})channel",
412 Channel::MiniReflectTypeTable()));
413
414 FlatbufferDetachedBuffer<Channel> bad_channel2(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800415 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800416 "name": "/test",
417 "type": "aos.examples.Ping",
418 "source_node": "bar",
419 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800420 {
421 "name": "baz"
422 }
Austin Schuh217a9782019-12-21 23:02:50 -0800423 ]
424})channel",
425 Channel::MiniReflectTypeTable()));
426
427 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800428 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800429 "name": "foo"
430})node",
431 Node::MiniReflectTypeTable()));
432
433 EXPECT_TRUE(
434 ChannelIsReadableOnNode(&good_channel.message(), &node.message()));
435 EXPECT_FALSE(
436 ChannelIsReadableOnNode(&bad_channel1.message(), &node.message()));
437 EXPECT_FALSE(
438 ChannelIsReadableOnNode(&bad_channel2.message(), &node.message()));
439}
440
James Kuszmaul24db2d32023-05-26 11:40:12 -0700441// Tests that our channel is forwarded helpers work as intended.
442TEST_F(ConfigurationTest, ChannelIsForwardedFromNode) {
443 FlatbufferDetachedBuffer<Channel> forwarded_channel(JsonToFlatbuffer(
444 R"channel({
445 "name": "/test",
446 "type": "aos.examples.Ping",
447 "source_node": "bar",
448 "destination_nodes": [
449 {
450 "name": "baz"
451 },
452 {
453 "name": "foo"
454 }
455 ]
456})channel",
457 Channel::MiniReflectTypeTable()));
458
459 FlatbufferDetachedBuffer<Channel> single_node_channel(JsonToFlatbuffer(
460 R"channel({
461 "name": "/test",
462 "type": "aos.examples.Ping"
463})channel",
464 Channel::MiniReflectTypeTable()));
465
466 FlatbufferDetachedBuffer<Channel> zero_length_vector_channel(JsonToFlatbuffer(
467 R"channel({
468 "name": "/test",
469 "type": "aos.examples.Ping",
470 "source_node": "bar",
471 "destination_nodes": [
472 ]
473})channel",
474 Channel::MiniReflectTypeTable()));
475
476 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
477 R"node({
478 "name": "bar"
479})node",
480 Node::MiniReflectTypeTable()));
481
482 FlatbufferDetachedBuffer<Node> readable_node(JsonToFlatbuffer(
483 R"node({
484 "name": "foo"
485})node",
486 Node::MiniReflectTypeTable()));
487
488 EXPECT_TRUE(ChannelIsForwardedFromNode(&forwarded_channel.message(),
489 &node.message()));
490 EXPECT_FALSE(ChannelIsForwardedFromNode(&forwarded_channel.message(),
491 &readable_node.message()));
492 EXPECT_FALSE(
493 ChannelIsForwardedFromNode(&single_node_channel.message(), nullptr));
494 EXPECT_FALSE(ChannelIsForwardedFromNode(&zero_length_vector_channel.message(),
495 &node.message()));
496}
497
Austin Schuh719946b2019-12-28 14:51:01 -0800498// Tests that our node message is logged helpers work as intended.
499TEST_F(ConfigurationTest, ChannelMessageIsLoggedOnNode) {
500 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
501 R"channel({
502 "name": "/test",
503 "type": "aos.examples.Ping",
504 "source_node": "bar",
505 "destination_nodes": [
506 {
507 "name": "baz"
508 }
509 ]
510})channel",
511 Channel::MiniReflectTypeTable()));
Austin Schuh217a9782019-12-21 23:02:50 -0800512
Austin Schuh719946b2019-12-28 14:51:01 -0800513 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
514 R"channel({
515 "name": "/test",
516 "type": "aos.examples.Ping",
517 "source_node": "bar",
518 "logger": "NOT_LOGGED",
519 "destination_nodes": [
520 {
521 "name": "baz",
522 "timestamp_logger": "LOCAL_LOGGER"
523 }
524 ]
525})channel",
526 Channel::MiniReflectTypeTable()));
527
528 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
529 R"channel({
530 "name": "/test",
531 "type": "aos.examples.Ping",
532 "source_node": "bar",
533 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700534 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800535 "destination_nodes": [
536 {
537 "name": "baz"
538 }
539 ]
540})channel",
541 Channel::MiniReflectTypeTable()));
542
543 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
544 JsonToFlatbuffer(
545 R"channel({
546 "name": "/test",
547 "type": "aos.examples.Ping",
548 "source_node": "bar",
549 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700550 "logger_nodes": ["foo"],
Austin Schuh719946b2019-12-28 14:51:01 -0800551 "destination_nodes": [
552 {
553 "name": "baz"
554 }
555 ]
556})channel",
557 Channel::MiniReflectTypeTable()));
558
Ravago Jonescf453ab2020-05-06 21:14:53 -0700559 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
560 R"channel({
Austin Schuh719946b2019-12-28 14:51:01 -0800561 "name": "/test",
562 "type": "aos.examples.Ping",
563 "source_node": "bar",
564 "logger": "LOCAL_AND_REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700565 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800566 "destination_nodes": [
567 {
568 "name": "baz"
569 }
570 ]
571})channel",
Ravago Jonescf453ab2020-05-06 21:14:53 -0700572 Channel::MiniReflectTypeTable()));
Austin Schuh719946b2019-12-28 14:51:01 -0800573
574 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
575 R"node({
576 "name": "foo"
577})node",
578 Node::MiniReflectTypeTable()));
579
580 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
581 R"node({
582 "name": "bar"
583})node",
584 Node::MiniReflectTypeTable()));
585
586 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
587 R"node({
588 "name": "baz"
589})node",
590 Node::MiniReflectTypeTable()));
591
592 // Local logger.
593 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
594 &foo_node.message()));
595 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
596 &bar_node.message()));
597 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
598 &baz_node.message()));
Austin Schuh48e94502021-06-18 18:35:53 -0700599 EXPECT_TRUE(
600 ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(), nullptr));
Austin Schuh719946b2019-12-28 14:51:01 -0800601
602 // No logger.
603 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
604 &foo_node.message()));
605 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
Ravago Jonescf453ab2020-05-06 21:14:53 -0700606 &bar_node.message()));
Austin Schuh719946b2019-12-28 14:51:01 -0800607 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
608 &baz_node.message()));
Austin Schuh48e94502021-06-18 18:35:53 -0700609 EXPECT_FALSE(
610 ChannelMessageIsLoggedOnNode(&not_logged_channel.message(), nullptr));
Austin Schuh719946b2019-12-28 14:51:01 -0800611
612 // Remote logger.
613 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
614 &foo_node.message()));
615 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
616 &bar_node.message()));
617 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
618 &baz_node.message()));
619
620 // Separate logger.
621 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(
622 &logged_on_separate_logger_node_channel.message(), &foo_node.message()));
623 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
624 &logged_on_separate_logger_node_channel.message(), &bar_node.message()));
625 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
626 &logged_on_separate_logger_node_channel.message(), &baz_node.message()));
627
628 // Logged in multiple places.
629 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
630 &foo_node.message()));
631 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
632 &bar_node.message()));
633 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
634 &baz_node.message()));
635}
636
Austin Schuh48e94502021-06-18 18:35:53 -0700637// Tests that our node message is logged helpers work as intended.
638TEST_F(ConfigurationDeathTest, ChannelMessageIsLoggedOnNode) {
639 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
640 R"channel({
641 "name": "/test",
642 "type": "aos.examples.Ping",
643 "source_node": "bar",
644 "logger": "LOCAL_AND_REMOTE_LOGGER",
645 "logger_nodes": ["baz"],
646 "destination_nodes": [
647 {
648 "name": "baz"
649 }
650 ]
651})channel",
652 Channel::MiniReflectTypeTable()));
653
654 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
655 JsonToFlatbuffer(
656 R"channel({
657 "name": "/test",
658 "type": "aos.examples.Ping",
659 "source_node": "bar",
660 "logger": "REMOTE_LOGGER",
661 "logger_nodes": ["foo"],
662 "destination_nodes": [
663 {
664 "name": "baz"
665 }
666 ]
667})channel",
668 Channel::MiniReflectTypeTable()));
669
670 EXPECT_DEATH(
671 {
672 ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
673 nullptr);
674 },
675 "Unsupported logging configuration in a single node world");
676 EXPECT_DEATH(
677 {
678 ChannelMessageIsLoggedOnNode(
679 &logged_on_separate_logger_node_channel.message(), nullptr);
680 },
681 "Unsupported logging configuration in a single node world");
682}
683
Austin Schuh719946b2019-12-28 14:51:01 -0800684// Tests that our forwarding timestamps are logged helpers work as intended.
685TEST_F(ConfigurationTest, ConnectionDeliveryTimeIsLoggedOnNode) {
686 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
687 R"channel({
688 "name": "/test",
689 "type": "aos.examples.Ping",
690 "source_node": "bar",
691 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700692 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800693 "destination_nodes": [
694 {
695 "name": "baz"
696 }
697 ]
698})channel",
699 Channel::MiniReflectTypeTable()));
700
701 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
702 R"channel({
703 "name": "/test",
704 "type": "aos.examples.Ping",
705 "source_node": "bar",
706 "logger": "NOT_LOGGED",
707 "destination_nodes": [
708 {
709 "name": "baz",
710 "timestamp_logger": "NOT_LOGGED"
711 }
712 ]
713})channel",
714 Channel::MiniReflectTypeTable()));
715
716 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
717 R"channel({
718 "name": "/test",
719 "type": "aos.examples.Ping",
720 "source_node": "bar",
721 "destination_nodes": [
722 {
723 "name": "baz",
724 "timestamp_logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700725 "timestamp_logger_nodes": ["bar"]
Austin Schuh719946b2019-12-28 14:51:01 -0800726 }
727 ]
728})channel",
729 Channel::MiniReflectTypeTable()));
730
731 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
732 JsonToFlatbuffer(
733 R"channel({
734 "name": "/test",
735 "type": "aos.examples.Ping",
736 "source_node": "bar",
737 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700738 "logger_nodes": ["foo"],
Austin Schuh719946b2019-12-28 14:51:01 -0800739 "destination_nodes": [
740 {
741 "name": "baz",
742 "timestamp_logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700743 "timestamp_logger_nodes": ["foo"]
Austin Schuh719946b2019-12-28 14:51:01 -0800744 }
745 ]
746})channel",
747 Channel::MiniReflectTypeTable()));
748
Ravago Jonescf453ab2020-05-06 21:14:53 -0700749 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
750 R"channel({
Austin Schuh719946b2019-12-28 14:51:01 -0800751 "name": "/test",
752 "type": "aos.examples.Ping",
753 "source_node": "bar",
754 "destination_nodes": [
755 {
756 "name": "baz",
757 "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700758 "timestamp_logger_nodes": ["bar"]
Austin Schuh719946b2019-12-28 14:51:01 -0800759 }
760 ]
761})channel",
Ravago Jonescf453ab2020-05-06 21:14:53 -0700762 Channel::MiniReflectTypeTable()));
Austin Schuh719946b2019-12-28 14:51:01 -0800763
764 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
765 R"node({
766 "name": "foo"
767})node",
768 Node::MiniReflectTypeTable()));
769
770 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
771 R"node({
772 "name": "bar"
773})node",
774 Node::MiniReflectTypeTable()));
775
776 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
777 R"node({
778 "name": "baz"
779})node",
780 Node::MiniReflectTypeTable()));
781
782 // Local logger.
783 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
784 &logged_on_self_channel.message(), &baz_node.message(),
785 &foo_node.message()));
786 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
787 &logged_on_self_channel.message(), &baz_node.message(),
788 &bar_node.message()));
789 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
790 &logged_on_self_channel.message(), &baz_node.message(),
791 &baz_node.message()));
792
793 // No logger means.
794 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
795 &not_logged_channel.message(), &baz_node.message(), &foo_node.message()));
796 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
797 &not_logged_channel.message(), &baz_node.message(), &bar_node.message()));
798 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
799 &not_logged_channel.message(), &baz_node.message(), &baz_node.message()));
800
801 // Remote logger.
802 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
803 &logged_on_remote_channel.message(), &baz_node.message(),
804 &foo_node.message()));
805 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
806 &logged_on_remote_channel.message(), &baz_node.message(),
807 &bar_node.message()));
808 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
809 &logged_on_remote_channel.message(), &baz_node.message(),
810 &baz_node.message()));
811
812 // Separate logger.
813 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
814 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
815 &foo_node.message()));
816 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
817 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
818 &bar_node.message()));
819 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
820 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
821 &baz_node.message()));
822
823 // Logged on both the node and a remote node.
824 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
825 &logged_on_both_channel.message(), &baz_node.message(),
826 &foo_node.message()));
827 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
828 &logged_on_both_channel.message(), &baz_node.message(),
829 &bar_node.message()));
830 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
831 &logged_on_both_channel.message(), &baz_node.message(),
832 &baz_node.message()));
833}
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800834
835// Tests that we can deduce source nodes from a multinode config.
836TEST_F(ConfigurationTest, SourceNodeNames) {
837 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700838 ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800839
840 // This is a bit simplistic in that it doesn't test deduplication, but it does
841 // exercise a lot of the logic.
842 EXPECT_THAT(
843 SourceNodeNames(&config.message(), config.message().nodes()->Get(0)),
844 ::testing::ElementsAreArray({"pi2"}));
845 EXPECT_THAT(
846 SourceNodeNames(&config.message(), config.message().nodes()->Get(1)),
847 ::testing::ElementsAreArray({"pi1"}));
848}
849
850// Tests that we can deduce destination nodes from a multinode config.
851TEST_F(ConfigurationTest, DestinationNodeNames) {
852 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700853 ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800854
855 // This is a bit simplistic in that it doesn't test deduplication, but it does
856 // exercise a lot of the logic.
857 EXPECT_THAT(
858 DestinationNodeNames(&config.message(), config.message().nodes()->Get(0)),
859 ::testing::ElementsAreArray({"pi2"}));
860 EXPECT_THAT(
861 DestinationNodeNames(&config.message(), config.message().nodes()->Get(1)),
862 ::testing::ElementsAreArray({"pi1"}));
863}
864
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800865// Tests that we can pull out all the nodes.
866TEST_F(ConfigurationTest, GetNodes) {
867 {
868 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700869 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800870 const Node *pi1 = GetNode(&config.message(), "pi1");
871 const Node *pi2 = GetNode(&config.message(), "pi2");
872
873 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(pi1, pi2));
874 }
875
876 {
877 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700878 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800879 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(nullptr));
880 }
881}
882
Austin Schuh65465332020-11-05 17:36:53 -0800883// Tests that we can pull out all the nodes with a tag.
884TEST_F(ConfigurationTest, GetNodesWithTag) {
885 {
886 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700887 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuh65465332020-11-05 17:36:53 -0800888 const Node *pi1 = GetNode(&config.message(), "pi1");
889 const Node *pi2 = GetNode(&config.message(), "pi2");
890
891 EXPECT_THAT(GetNodesWithTag(&config.message(), "a"),
892 ::testing::ElementsAre(pi1));
893 EXPECT_THAT(GetNodesWithTag(&config.message(), "b"),
894 ::testing::ElementsAre(pi2));
895 EXPECT_THAT(GetNodesWithTag(&config.message(), "c"),
896 ::testing::ElementsAre(pi1, pi2));
897 }
898
899 {
900 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700901 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuh65465332020-11-05 17:36:53 -0800902 EXPECT_THAT(GetNodesWithTag(&config.message(), "arglfish"),
903 ::testing::ElementsAre(nullptr));
904 }
905}
906
Brian Silverman631b6262021-11-10 12:25:08 -0800907// Tests that we can check if a node has a tag.
908TEST_F(ConfigurationTest, NodeHasTag) {
909 {
910 FlatbufferDetachedBuffer<Configuration> config =
911 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
912 const Node *pi1 = GetNode(&config.message(), "pi1");
913 const Node *pi2 = GetNode(&config.message(), "pi2");
914
915 EXPECT_TRUE(NodeHasTag(pi1, "a"));
916 EXPECT_FALSE(NodeHasTag(pi2, "a"));
917 EXPECT_FALSE(NodeHasTag(pi1, "b"));
918 EXPECT_TRUE(NodeHasTag(pi2, "b"));
919 EXPECT_TRUE(NodeHasTag(pi1, "c"));
920 EXPECT_TRUE(NodeHasTag(pi2, "c"));
921 EXPECT_FALSE(NodeHasTag(pi1, "nope"));
922 EXPECT_FALSE(NodeHasTag(pi2, "nope"));
923 }
924
925 EXPECT_TRUE(NodeHasTag(nullptr, "arglfish"));
926}
927
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800928// Tests that we can extract a node index from a config.
929TEST_F(ConfigurationTest, GetNodeIndex) {
930 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700931 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuh04408fc2020-02-16 21:48:54 -0800932 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh373f1762021-06-02 21:07:09 -0700933 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800934 const Node *pi1 = GetNode(&config.message(), "pi1");
935 const Node *pi2 = GetNode(&config.message(), "pi2");
936
Austin Schuh04408fc2020-02-16 21:48:54 -0800937 // Try the normal case.
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800938 EXPECT_EQ(GetNodeIndex(&config.message(), pi1), 0);
939 EXPECT_EQ(GetNodeIndex(&config.message(), pi2), 1);
Austin Schuh04408fc2020-02-16 21:48:54 -0800940
941 // Now try if we have node pointers from a different message.
942 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1), 0);
943 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2), 1);
944
945 // And now try string names.
946 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1->name()->string_view()), 0);
947 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2->name()->string_view()), 1);
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800948}
949
950// Tests that GetNodeOrDie handles both single and multi-node worlds and returns
951// valid nodes.
952TEST_F(ConfigurationDeathTest, GetNodeOrDie) {
953 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700954 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800955 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh373f1762021-06-02 21:07:09 -0700956 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800957 {
958 // Simple case, nullptr -> nullptr
959 FlatbufferDetachedBuffer<Configuration> single_node_config =
Austin Schuh373f1762021-06-02 21:07:09 -0700960 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800961 EXPECT_EQ(nullptr, GetNodeOrDie(&single_node_config.message(), nullptr));
962
963 // Confirm that we die when a node is passed in.
964 EXPECT_DEATH(
965 {
966 GetNodeOrDie(&single_node_config.message(),
967 config.message().nodes()->Get(0));
968 },
969 "Provided a node in a single node world.");
970 }
971
972 const Node *pi1 = GetNode(&config.message(), "pi1");
973 // Now try a lookup using a node from a different instance of the config.
974 EXPECT_EQ(pi1,
975 GetNodeOrDie(&config.message(), config2.message().nodes()->Get(0)));
976}
977
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800978TEST_F(ConfigurationTest, GetNodeFromHostname) {
979 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700980 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800981 EXPECT_EQ("pi1",
982 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
983 ->name()
984 ->string_view());
985 EXPECT_EQ("pi2", CHECK_NOTNULL(
986 GetNodeFromHostname(&config.message(), "raspberrypi2"))
987 ->name()
988 ->string_view());
989 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi3"));
990 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
991 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
992}
993
994TEST_F(ConfigurationTest, GetNodeFromHostnames) {
995 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700996 ReadConfig(ArtifactPath("aos/testdata/good_multinode_hostnames.json"));
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800997 EXPECT_EQ("pi1",
998 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
999 ->name()
1000 ->string_view());
1001 EXPECT_EQ("pi2", CHECK_NOTNULL(
1002 GetNodeFromHostname(&config.message(), "raspberrypi2"))
1003 ->name()
1004 ->string_view());
1005 EXPECT_EQ("pi2", CHECK_NOTNULL(
1006 GetNodeFromHostname(&config.message(), "raspberrypi3"))
1007 ->name()
1008 ->string_view());
Ravago Jonescf453ab2020-05-06 21:14:53 -07001009 EXPECT_EQ("pi2",
1010 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "other"))
1011 ->name()
1012 ->string_view());
Brian Silvermanaa2633f2020-02-17 21:04:14 -08001013 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi4"));
1014 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
1015 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
1016}
1017
Austin Schuhfc7b6a02021-07-12 21:19:07 -07001018// Tests that SourceNodeIndex reasonably handles a multi-node log file.
1019TEST_F(ConfigurationTest, SourceNodeIndex) {
1020 FlatbufferDetachedBuffer<Configuration> config =
1021 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
1022 std::vector<size_t> result = SourceNodeIndex(&config.message());
1023
1024 EXPECT_THAT(result, ::testing::ElementsAreArray({0, 1, 0, 0}));
1025}
1026
Austin Schuh5e95bd62021-10-11 18:40:22 -07001027// Tests that we reject invalid logging configurations.
1028TEST_F(ConfigurationDeathTest, InvalidLoggerConfig) {
1029 EXPECT_DEATH(
1030 {
Milind Upadhyay17098ba2022-04-15 22:18:50 -07001031 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
1032 ArtifactPath("aos/testdata/invalid_logging_configuration.json"));
Austin Schuh5e95bd62021-10-11 18:40:22 -07001033 },
1034 "Logging timestamps without data");
1035}
1036
Austin Schuha156fb22021-10-11 19:23:21 -07001037// Tests that we reject duplicate timestamp destination node configurations.
1038TEST_F(ConfigurationDeathTest, DuplicateTimestampDestinationNodes) {
1039 EXPECT_DEATH(
1040 {
1041 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
1042 ArtifactPath("aos/testdata/duplicate_destination_nodes.json"));
1043 },
1044 "Found duplicate timestamp_logger_nodes in");
1045}
1046
1047// Tests that we reject duplicate logger node configurations for a channel's
1048// data.
1049TEST_F(ConfigurationDeathTest, DuplicateLoggerNodes) {
1050 EXPECT_DEATH(
1051 {
1052 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
1053 ArtifactPath("aos/testdata/duplicate_logger_nodes.json"));
1054 },
1055 "Found duplicate logger_nodes in");
1056}
1057
Austin Schuhfb37c612022-08-11 15:24:51 -07001058// Tests that we properly compute the queue size for the provided duration.
1059TEST_F(ConfigurationTest, QueueSize) {
1060 EXPECT_EQ(QueueSize(100, chrono::seconds(2)), 200);
1061 EXPECT_EQ(QueueSize(200, chrono::seconds(2)), 400);
1062 EXPECT_EQ(QueueSize(100, chrono::seconds(6)), 600);
1063 EXPECT_EQ(QueueSize(100, chrono::milliseconds(10)), 1);
1064 EXPECT_EQ(QueueSize(100, chrono::milliseconds(10) - chrono::nanoseconds(1)),
1065 1);
1066 EXPECT_EQ(QueueSize(100, chrono::milliseconds(10) - chrono::nanoseconds(2)),
1067 1);
1068}
1069
1070// Tests that we compute scratch buffer size correctly too.
1071TEST_F(ConfigurationTest, QueueScratchBufferSize) {
1072 const aos::FlatbufferDetachedBuffer<Channel> channel =
1073 JsonToFlatbuffer<Channel>(
1074 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"num_readers\": 5, "
1075 "\"num_senders\": 10 }");
Austin Schuhfb37c612022-08-11 15:24:51 -07001076 EXPECT_EQ(QueueScratchBufferSize(&channel.message()), 15);
1077}
1078
Nathan Leong307c9692022-10-08 15:25:03 -07001079// Tests that GetSchema returns schema of specified type
1080TEST_F(ConfigurationTest, GetSchema) {
1081 FlatbufferDetachedBuffer<Configuration> config =
1082 ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
1083 FlatbufferVector<reflection::Schema> expected_schema =
1084 FileToFlatbuffer<reflection::Schema>(
1085 ArtifactPath("aos/events/ping.bfbs"));
1086 EXPECT_EQ(FlatbufferToJson(GetSchema(&config.message(), "aos.examples.Ping")),
1087 FlatbufferToJson(expected_schema));
1088 EXPECT_EQ(GetSchema(&config.message(), "invalid_name"), nullptr);
1089}
1090
1091// Tests that GetSchema template returns schema of specified type
1092TEST_F(ConfigurationTest, GetSchemaTemplate) {
1093 FlatbufferDetachedBuffer<Configuration> config =
1094 ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
1095 FlatbufferVector<reflection::Schema> expected_schema =
1096 FileToFlatbuffer<reflection::Schema>(
1097 ArtifactPath("aos/events/ping.bfbs"));
1098 EXPECT_EQ(FlatbufferToJson(GetSchema<aos::examples::Ping>(&config.message())),
1099 FlatbufferToJson(expected_schema));
1100}
1101
1102// Tests that GetSchemaDetachedBuffer returns detached buffer of specified type
1103TEST_F(ConfigurationTest, GetSchemaDetachedBuffer) {
1104 FlatbufferDetachedBuffer<Configuration> config =
1105 ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
1106 FlatbufferVector<reflection::Schema> expected_schema =
1107 FileToFlatbuffer<reflection::Schema>(
1108 ArtifactPath("aos/events/ping.bfbs"));
1109 EXPECT_EQ(FlatbufferToJson(
1110 GetSchemaDetachedBuffer(&config.message(), "aos.examples.Ping")
1111 .value()),
1112 FlatbufferToJson(expected_schema));
1113 EXPECT_EQ(GetSchemaDetachedBuffer(&config.message(), "invalid_name"),
1114 std::nullopt);
1115}
1116
James Kuszmaul741a4d02023-01-05 14:59:21 -08001117// Tests that we can use a utility to add individual channels to a single-node
1118// config.
1119TEST_F(ConfigurationTest, AddChannelToConfigSingleNode) {
1120 FlatbufferDetachedBuffer<Configuration> base_config =
1121 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
1122
1123 FlatbufferVector<reflection::Schema> schema =
1124 FileToFlatbuffer<reflection::Schema>(
1125 ArtifactPath("aos/events/ping.bfbs"));
1126
1127 FlatbufferDetachedBuffer<Configuration> new_config =
1128 AddChannelToConfiguration(&base_config.message(), "/new", schema);
1129
1130 ASSERT_EQ(new_config.message().channels()->size(),
1131 base_config.message().channels()->size() + 1);
1132
1133 const Channel *channel =
1134 GetChannel(new_config, "/new", "aos.examples.Ping", "", nullptr);
1135 ASSERT_TRUE(channel != nullptr);
1136 ASSERT_TRUE(channel->has_schema());
1137 // Check that we don't populate channel settings that we don't override the
1138 // defaults of.
1139 ASSERT_FALSE(channel->has_frequency());
1140}
1141
1142// Tests that we can use a utility to add individual channels to a multi-node
1143// config.
1144TEST_F(ConfigurationTest, AddChannelToConfigMultiNode) {
1145 FlatbufferDetachedBuffer<Configuration> base_config =
1146 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
1147
1148 FlatbufferVector<reflection::Schema> schema =
1149 FileToFlatbuffer<reflection::Schema>(
1150 ArtifactPath("aos/events/ping.bfbs"));
1151
1152 aos::ChannelT channel_overrides;
1153 channel_overrides.frequency = 971;
1154 FlatbufferDetachedBuffer<Configuration> new_config =
1155 AddChannelToConfiguration(&base_config.message(), "/new", schema,
1156 GetNode(&base_config.message(), "pi1"),
1157 channel_overrides);
1158
1159 ASSERT_EQ(new_config.message().channels()->size(),
1160 base_config.message().channels()->size() + 1);
1161
1162 const Channel *channel =
1163 GetChannel(new_config, "/new", "aos.examples.Ping", "", nullptr);
1164 ASSERT_TRUE(channel != nullptr);
1165 ASSERT_TRUE(channel->has_schema());
1166 ASSERT_TRUE(channel->has_source_node());
1167 ASSERT_EQ("pi1", channel->source_node()->string_view());
1168 ASSERT_EQ(971, channel->frequency());
1169}
1170
Austin Schuhcb108412019-10-13 16:09:54 -07001171} // namespace testing
1172} // namespace configuration
1173} // namespace aos