blob: e5fe3034d0cc33df2f1bada17189971ae23b4c33 [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
Stephan Pleinesf63bde82024-01-13 15:59:33 -080016namespace aos::configuration::testing {
Austin Schuhcb108412019-10-13 16:09:54 -070017
Austin Schuh373f1762021-06-02 21:07:09 -070018using aos::testing::ArtifactPath;
Austin Schuhfb37c612022-08-11 15:24:51 -070019namespace chrono = std::chrono;
Austin Schuh66602132020-02-28 13:38:37 -080020
Austin Schuhcb108412019-10-13 16:09:54 -070021class ConfigurationTest : public ::testing::Test {
22 public:
23 ConfigurationTest() { ::aos::testing::EnableTestLogging(); }
24};
25
26typedef ConfigurationTest ConfigurationDeathTest;
27
28// *the* expected location for all working tests.
Austin Schuh1ef01ef2021-02-07 20:40:36 -080029aos::FlatbufferDetachedBuffer<Channel> ExpectedLocation() {
30 return JsonToFlatbuffer<Channel>(
31 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5 }");
32}
33
Austin Schuhbca6cf02019-12-22 17:28:34 -080034// And for multinode setups
Austin Schuh1ef01ef2021-02-07 20:40:36 -080035aos::FlatbufferDetachedBuffer<Channel> ExpectedMultinodeLocation() {
36 return JsonToFlatbuffer<Channel>(
37 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"max_size\": 5, "
38 "\"source_node\": \"pi1\" }");
39}
Austin Schuhcb108412019-10-13 16:09:54 -070040
41// Tests that we can read and merge a configuration.
42TEST_F(ConfigurationTest, ConfigMerge) {
Austin Schuh40485ed2019-10-26 21:51:44 -070043 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070044 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Ravago Jonescf453ab2020-05-06 21:14:53 -070045 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuhcb108412019-10-13 16:09:54 -070046
Austin Schuh373f1762021-06-02 21:07:09 -070047 EXPECT_EQ(absl::StripSuffix(util::ReadFileToStringOrDie(
48 ArtifactPath("aos/testdata/expected.json")),
49 "\n"),
50 FlatbufferToJson(config, {.multi_line = true}));
Austin Schuhcb108412019-10-13 16:09:54 -070051}
52
Austin Schuhc9e10ec2020-01-26 16:08:28 -080053// Tests that we can get back a ChannelIndex.
54TEST_F(ConfigurationTest, ChannelIndex) {
55 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070056 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -080057
58 EXPECT_EQ(
59 ChannelIndex(&config.message(), config.message().channels()->Get(1u)),
60 1u);
61}
62
Austin Schuh217a9782019-12-21 23:02:50 -080063// Tests that we can read and merge a multinode configuration.
64TEST_F(ConfigurationTest, ConfigMergeMultinode) {
65 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070066 ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
Ravago Jonescf453ab2020-05-06 21:14:53 -070067 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuh217a9782019-12-21 23:02:50 -080068
Ravago Jonescf453ab2020-05-06 21:14:53 -070069 EXPECT_EQ(std::string(absl::StripSuffix(
Austin Schuh373f1762021-06-02 21:07:09 -070070 util::ReadFileToStringOrDie(
71 ArtifactPath("aos/testdata/expected_multinode.json")),
Ravago Jonescf453ab2020-05-06 21:14:53 -070072 "\n")),
73 FlatbufferToJson(config, {.multi_line = true}));
Austin Schuh217a9782019-12-21 23:02:50 -080074}
75
Alex Perrycb7da4b2019-08-28 19:35:56 -070076// Tests that we sort the entries in a config so we can look entries up.
77TEST_F(ConfigurationTest, UnsortedConfig) {
78 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070079 ReadConfig(ArtifactPath("aos/testdata/backwards.json"));
Alex Perrycb7da4b2019-08-28 19:35:56 -070080
Ravago Jonescf453ab2020-05-06 21:14:53 -070081 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Alex Perrycb7da4b2019-08-28 19:35:56 -070082
Austin Schuhf1fff282020-03-28 16:57:32 -070083 EXPECT_EQ(FlatbufferToJson(GetChannel(config, "/aos/robot_state",
Austin Schuhbca6cf02019-12-22 17:28:34 -080084 "aos.RobotState", "app1", nullptr)),
Austin Schuhf1fff282020-03-28 16:57:32 -070085 "{ \"name\": \"/aos/robot_state\", \"type\": \"aos.RobotState\", "
Alex Perrycb7da4b2019-08-28 19:35:56 -070086 "\"max_size\": 5 }");
87}
88
Austin Schuhcb108412019-10-13 16:09:54 -070089// Tests that we die when a file is imported twice.
90TEST_F(ConfigurationDeathTest, DuplicateFile) {
91 EXPECT_DEATH(
92 {
Austin Schuh40485ed2019-10-26 21:51:44 -070093 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -070094 ReadConfig(ArtifactPath("aos/testdata/config1_bad.json"));
Austin Schuhcb108412019-10-13 16:09:54 -070095 },
Austin Schuh373f1762021-06-02 21:07:09 -070096 "aos/testdata/config1_bad.json");
Austin Schuhcb108412019-10-13 16:09:54 -070097}
98
Milind Upadhyay17098ba2022-04-15 22:18:50 -070099// Tests that we die when we give an invalid path.
100TEST_F(ConfigurationDeathTest, NonexistentFile) {
101 EXPECT_DEATH(
102 {
103 FlatbufferDetachedBuffer<Configuration> config =
104 ReadConfig("nonexistent/config.json");
105 },
106 "above error");
107}
108
109// Tests that we return std::nullopt when we give an invalid path.
110TEST_F(ConfigurationTest, NonexistentFileOptional) {
111 std::optional<FlatbufferDetachedBuffer<Configuration>> config =
112 MaybeReadConfig("nonexistent/config.json");
113 EXPECT_FALSE(config.has_value());
114}
115
Austin Schuhf1fff282020-03-28 16:57:32 -0700116// Tests that we reject invalid channel names. This means any channels with //
117// in their name, a trailing /, or regex characters.
118TEST_F(ConfigurationDeathTest, InvalidChannelName) {
119 EXPECT_DEATH(
120 {
121 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700122 ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name1.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700123 },
124 "Channel names can't end with '/'");
125 EXPECT_DEATH(
126 {
127 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700128 ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name2.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700129 },
130 "Invalid channel name");
131 EXPECT_DEATH(
132 {
133 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700134 ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name3.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700135 LOG(FATAL) << "Foo";
136 },
137 "Invalid channel name");
Austin Schuh47e382e2023-05-28 11:20:56 -0700138 EXPECT_DEATH(
139 {
140 FlatbufferDetachedBuffer<Configuration> config =
141 ReadConfig(ArtifactPath("aos/testdata/invalid_channel_name4.json"));
142 LOG(FATAL) << "Foo";
143 },
144 "Channel names must start with '/'");
Austin Schuhf1fff282020-03-28 16:57:32 -0700145}
146
Austin Schuh8d6cea82020-02-28 12:17:16 -0800147// Tests that we can modify a config with a json snippet.
148TEST_F(ConfigurationTest, MergeWithConfig) {
149 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700150 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Ravago Jonescf453ab2020-05-06 21:14:53 -0700151 LOG(INFO) << "Read: " << FlatbufferToJson(config, {.multi_line = true});
Austin Schuh8d6cea82020-02-28 12:17:16 -0800152
153 FlatbufferDetachedBuffer<Configuration> updated_config =
154 MergeWithConfig(&config.message(),
155 R"channel({
156 "channels": [
157 {
158 "name": "/foo",
159 "type": ".aos.bar",
160 "max_size": 100
161 }
162 ]
163})channel");
164
Austin Schuh373f1762021-06-02 21:07:09 -0700165 EXPECT_EQ(absl::StripSuffix(util::ReadFileToStringOrDie(ArtifactPath(
166 "aos/testdata/expected_merge_with.json")),
Ravago Jonescf453ab2020-05-06 21:14:53 -0700167 "\n"),
168 FlatbufferToJson(updated_config, {.multi_line = true}));
Austin Schuh8d6cea82020-02-28 12:17:16 -0800169}
170
Austin Schuhcb108412019-10-13 16:09:54 -0700171// Tests that we can lookup a location, complete with maps, from a merged
172// config.
Austin Schuh40485ed2019-10-26 21:51:44 -0700173TEST_F(ConfigurationTest, GetChannel) {
174 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700175 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhcb108412019-10-13 16:09:54 -0700176
177 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800178 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", nullptr),
179 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700180
181 // Test that an invalid name results in nullptr back.
Austin Schuhbca6cf02019-12-22 17:28:34 -0800182 EXPECT_EQ(GetChannel(config, "/invalid_name", ".aos.bar", "app1", nullptr),
183 nullptr);
Austin Schuhcb108412019-10-13 16:09:54 -0700184
185 // Tests that a root map/rename works. And that they get processed from the
186 // bottom up.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800187 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", nullptr),
188 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700189
190 // And then test that an application specific map/rename works.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800191 EXPECT_THAT(GetChannel(config, "/bar", ".aos.bar", "app1", nullptr),
192 aos::testing::FlatbufferEq(ExpectedLocation()));
193 EXPECT_THAT(GetChannel(config, "/baz", ".aos.bar", "app2", nullptr),
194 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhcb108412019-10-13 16:09:54 -0700195
196 // And then test that an invalid application name gets properly ignored.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800197 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app3", nullptr),
198 aos::testing::FlatbufferEq(ExpectedLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800199}
200
James Kuszmaulc8503f32022-06-25 16:17:12 -0700201// Tests that we can do reverse-lookups of channel names.
202TEST_F(ConfigurationTest, GetChannelAliases) {
203 FlatbufferDetachedBuffer<Configuration> config =
204 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
205
206 // Test a basic lookup first.
207 EXPECT_THAT(
208 GetChannelAliases(&config.message(), "/foo", ".aos.bar", "app1", nullptr),
209 ::testing::UnorderedElementsAre("/foo", "/batman", "/bar"));
210 EXPECT_THAT(
211 GetChannelAliases(&config.message(), "/bar", ".aos.bar", "app1", nullptr),
212 ::testing::UnorderedElementsAre("/batman", "/bar"));
213 EXPECT_THAT(GetChannelAliases(&config.message(), "/batman", ".aos.bar",
214 "app1", nullptr),
215 ::testing::UnorderedElementsAre("/batman"));
216 // /bar (deliberately) does not get included because of the ordering in the
217 // map.
218 EXPECT_THAT(
219 GetChannelAliases(&config.message(), "/foo", ".aos.bar", "", nullptr),
220 ::testing::UnorderedElementsAre("/foo", "/batman"));
221 EXPECT_THAT(
222 GetChannelAliases(&config.message(), "/foo", ".aos.bar", "app2", nullptr),
223 ::testing::UnorderedElementsAre("/foo", "/batman", "/baz"));
224}
225
Austin Schuhbca6cf02019-12-22 17:28:34 -0800226// Tests that we can lookup a location with node specific maps.
227TEST_F(ConfigurationTest, GetChannelMultinode) {
228 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700229 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800230 const Node *pi1 = GetNode(&config.message(), "pi1");
231 const Node *pi2 = GetNode(&config.message(), "pi2");
232
233 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800234 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", pi1),
235 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
236 EXPECT_THAT(GetChannel(config, "/foo", ".aos.bar", "app1", pi2),
237 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800238
239 // Tests that a root map/rename works with a node specific map.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800240 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", pi1),
241 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800242
243 // Tests that a root map/rename fails with a node specific map for the wrong
244 // node.
245 EXPECT_EQ(GetChannel(config, "/batman", ".aos.bar", "app1", pi2), nullptr);
246
247 // And then test that an application specific map/rename works.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800248 EXPECT_THAT(GetChannel(config, "/batman2", ".aos.bar", "app1", pi1),
249 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
250 EXPECT_THAT(GetChannel(config, "/batman3", ".aos.bar", "app1", pi1),
251 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800252
253 // And then that it fails when the node changes.
254 EXPECT_EQ(GetChannel(config, "/batman3", ".aos.bar", "app1", pi2), nullptr);
255}
256
James Kuszmaulc8503f32022-06-25 16:17:12 -0700257// Tests that reverse channel lookup on a multi-node config (including with
258// wildcards) works.
259TEST_F(ConfigurationTest, GetChannelAliasesMultinode) {
260 FlatbufferDetachedBuffer<Configuration> config =
261 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
262
263 const Node *pi1 = GetNode(&config.message(), "pi1");
264 const Node *pi2 = GetNode(&config.message(), "pi2");
265
266 EXPECT_THAT(
267 GetChannelAliases(&config.message(), "/foo", ".aos.bar", "app1", pi1),
268 ::testing::UnorderedElementsAre("/foo", "/batman", "/batman2", "/batman3",
269 "/magic/string"));
270
271 EXPECT_THAT(
272 GetChannelAliases(&config.message(), "/foo", ".aos.baz", "app1", pi1),
273 ::testing::UnorderedElementsAre("/foo", "/batman3", "/magic/string"));
274
275 EXPECT_THAT(
276 GetChannelAliases(&config.message(), "/foo/testing", ".aos.bar", "", pi1),
277 ::testing::UnorderedElementsAre("/foo/testing", "/magic/string/testing"));
278
279 EXPECT_THAT(
280 GetChannelAliases(&config.message(), "/foo/testing", ".aos.bar", "app1",
281 pi2),
282 ::testing::UnorderedElementsAre("/foo/testing", "/magic/string/testing"));
283}
284
Austin Schuhbca6cf02019-12-22 17:28:34 -0800285// Tests that we can lookup a location with type specific maps.
286TEST_F(ConfigurationTest, GetChannelTypedMultinode) {
287 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700288 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800289 const Node *pi1 = GetNode(&config.message(), "pi1");
290
291 // Test a basic lookup first.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800292 EXPECT_THAT(GetChannel(config, "/batman", ".aos.bar", "app1", pi1),
293 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhbca6cf02019-12-22 17:28:34 -0800294
295 // Now confirm that a second message on the same name doesn't get remapped.
296 const char *kExpectedBazMultinodeLocation =
297 "{ \"name\": \"/batman\", \"type\": \".aos.baz\", \"max_size\": 5, "
298 "\"source_node\": \"pi1\" }";
299 EXPECT_EQ(
300 FlatbufferToJson(GetChannel(config, "/batman", ".aos.baz", "app1", pi1)),
301 kExpectedBazMultinodeLocation);
Austin Schuhcb108412019-10-13 16:09:54 -0700302}
303
Austin Schuhf1fff282020-03-28 16:57:32 -0700304// Tests that we can lookup a location with a glob
305TEST_F(ConfigurationTest, GetChannelGlob) {
306 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700307 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhf1fff282020-03-28 16:57:32 -0700308 const Node *pi1 = GetNode(&config.message(), "pi1");
309
310 // Confirm that a glob with nothing after it matches.
Austin Schuh1ef01ef2021-02-07 20:40:36 -0800311 EXPECT_THAT(GetChannel(config, "/magic/string", ".aos.bar", "app7", pi1),
312 aos::testing::FlatbufferEq(ExpectedMultinodeLocation()));
Austin Schuhf1fff282020-03-28 16:57:32 -0700313
314 // Now confirm that glob with something following it matches and renames
315 // correctly.
316 const char *kExpectedSubfolderMultinodeLocation =
317 "{ \"name\": \"/foo/subfolder\", \"type\": \".aos.bar\", \"max_size\": "
318 "5, \"source_node\": \"pi1\" }";
319 EXPECT_EQ(FlatbufferToJson(GetChannel(config, "/magic/string/subfolder",
320 ".aos.bar", "app7", pi1)),
321 kExpectedSubfolderMultinodeLocation);
322}
323
Austin Schuh217a9782019-12-21 23:02:50 -0800324// Tests that we reject a configuration which has a nodes list, but has channels
325// withoout source_node filled out.
326TEST_F(ConfigurationDeathTest, InvalidSourceNode) {
327 EXPECT_DEATH(
328 {
329 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700330 ReadConfig(ArtifactPath("aos/testdata/invalid_nodes.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800331 },
332 "source_node");
333
334 EXPECT_DEATH(
335 {
336 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700337 ReadConfig(ArtifactPath("aos/testdata/invalid_source_node.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800338 },
339 "source_node");
340
341 EXPECT_DEATH(
342 {
Austin Schuh373f1762021-06-02 21:07:09 -0700343 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
344 ArtifactPath("aos/testdata/invalid_destination_node.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800345 },
346 "destination_nodes");
347
348 EXPECT_DEATH(
349 {
350 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700351 ReadConfig(ArtifactPath("aos/testdata/self_forward.json"));
Austin Schuh217a9782019-12-21 23:02:50 -0800352 },
353 "forwarding data to itself");
354}
355
356// Tests that our node writeable helpers work as intended.
357TEST_F(ConfigurationTest, ChannelIsSendableOnNode) {
358 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800359 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800360 "name": "/test",
361 "type": "aos.examples.Ping",
362 "source_node": "foo"
363})channel",
364 Channel::MiniReflectTypeTable()));
365
366 FlatbufferDetachedBuffer<Channel> bad_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800367 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800368 "name": "/test",
369 "type": "aos.examples.Ping",
370 "source_node": "bar"
371})channel",
372 Channel::MiniReflectTypeTable()));
373
374 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800375 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800376 "name": "foo"
377})node",
378 Node::MiniReflectTypeTable()));
379
380 EXPECT_TRUE(
381 ChannelIsSendableOnNode(&good_channel.message(), &node.message()));
382 EXPECT_FALSE(
383 ChannelIsSendableOnNode(&bad_channel.message(), &node.message()));
384}
385
386// Tests that our node readable and writeable helpers work as intended.
387TEST_F(ConfigurationTest, ChannelIsReadableOnNode) {
388 FlatbufferDetachedBuffer<Channel> good_channel(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800389 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800390 "name": "/test",
391 "type": "aos.examples.Ping",
392 "source_node": "bar",
393 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800394 {
395 "name": "baz"
396 },
397 {
398 "name": "foo"
399 }
Austin Schuh217a9782019-12-21 23:02:50 -0800400 ]
401})channel",
402 Channel::MiniReflectTypeTable()));
403
404 FlatbufferDetachedBuffer<Channel> bad_channel1(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800405 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800406 "name": "/test",
407 "type": "aos.examples.Ping",
408 "source_node": "bar"
409})channel",
410 Channel::MiniReflectTypeTable()));
411
412 FlatbufferDetachedBuffer<Channel> bad_channel2(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800413 R"channel({
Austin Schuh217a9782019-12-21 23:02:50 -0800414 "name": "/test",
415 "type": "aos.examples.Ping",
416 "source_node": "bar",
417 "destination_nodes": [
Austin Schuh719946b2019-12-28 14:51:01 -0800418 {
419 "name": "baz"
420 }
Austin Schuh217a9782019-12-21 23:02:50 -0800421 ]
422})channel",
423 Channel::MiniReflectTypeTable()));
424
425 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
Austin Schuh719946b2019-12-28 14:51:01 -0800426 R"node({
Austin Schuh217a9782019-12-21 23:02:50 -0800427 "name": "foo"
428})node",
429 Node::MiniReflectTypeTable()));
430
431 EXPECT_TRUE(
432 ChannelIsReadableOnNode(&good_channel.message(), &node.message()));
433 EXPECT_FALSE(
434 ChannelIsReadableOnNode(&bad_channel1.message(), &node.message()));
435 EXPECT_FALSE(
436 ChannelIsReadableOnNode(&bad_channel2.message(), &node.message()));
437}
438
James Kuszmaul24db2d32023-05-26 11:40:12 -0700439// Tests that our channel is forwarded helpers work as intended.
440TEST_F(ConfigurationTest, ChannelIsForwardedFromNode) {
441 FlatbufferDetachedBuffer<Channel> forwarded_channel(JsonToFlatbuffer(
442 R"channel({
443 "name": "/test",
444 "type": "aos.examples.Ping",
445 "source_node": "bar",
446 "destination_nodes": [
447 {
448 "name": "baz"
449 },
450 {
451 "name": "foo"
452 }
453 ]
454})channel",
455 Channel::MiniReflectTypeTable()));
456
457 FlatbufferDetachedBuffer<Channel> single_node_channel(JsonToFlatbuffer(
458 R"channel({
459 "name": "/test",
460 "type": "aos.examples.Ping"
461})channel",
462 Channel::MiniReflectTypeTable()));
463
464 FlatbufferDetachedBuffer<Channel> zero_length_vector_channel(JsonToFlatbuffer(
465 R"channel({
466 "name": "/test",
467 "type": "aos.examples.Ping",
468 "source_node": "bar",
469 "destination_nodes": [
470 ]
471})channel",
472 Channel::MiniReflectTypeTable()));
473
474 FlatbufferDetachedBuffer<Node> node(JsonToFlatbuffer(
475 R"node({
476 "name": "bar"
477})node",
478 Node::MiniReflectTypeTable()));
479
480 FlatbufferDetachedBuffer<Node> readable_node(JsonToFlatbuffer(
481 R"node({
482 "name": "foo"
483})node",
484 Node::MiniReflectTypeTable()));
485
486 EXPECT_TRUE(ChannelIsForwardedFromNode(&forwarded_channel.message(),
487 &node.message()));
488 EXPECT_FALSE(ChannelIsForwardedFromNode(&forwarded_channel.message(),
489 &readable_node.message()));
490 EXPECT_FALSE(
491 ChannelIsForwardedFromNode(&single_node_channel.message(), nullptr));
492 EXPECT_FALSE(ChannelIsForwardedFromNode(&zero_length_vector_channel.message(),
493 &node.message()));
494}
495
Austin Schuh719946b2019-12-28 14:51:01 -0800496// Tests that our node message is logged helpers work as intended.
497TEST_F(ConfigurationTest, ChannelMessageIsLoggedOnNode) {
498 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
499 R"channel({
500 "name": "/test",
501 "type": "aos.examples.Ping",
502 "source_node": "bar",
503 "destination_nodes": [
504 {
505 "name": "baz"
506 }
507 ]
508})channel",
509 Channel::MiniReflectTypeTable()));
Austin Schuh217a9782019-12-21 23:02:50 -0800510
Austin Schuh719946b2019-12-28 14:51:01 -0800511 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
512 R"channel({
513 "name": "/test",
514 "type": "aos.examples.Ping",
515 "source_node": "bar",
516 "logger": "NOT_LOGGED",
517 "destination_nodes": [
518 {
519 "name": "baz",
520 "timestamp_logger": "LOCAL_LOGGER"
521 }
522 ]
523})channel",
524 Channel::MiniReflectTypeTable()));
525
526 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
527 R"channel({
528 "name": "/test",
529 "type": "aos.examples.Ping",
530 "source_node": "bar",
531 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700532 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800533 "destination_nodes": [
534 {
535 "name": "baz"
536 }
537 ]
538})channel",
539 Channel::MiniReflectTypeTable()));
540
541 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
542 JsonToFlatbuffer(
543 R"channel({
544 "name": "/test",
545 "type": "aos.examples.Ping",
546 "source_node": "bar",
547 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700548 "logger_nodes": ["foo"],
Austin Schuh719946b2019-12-28 14:51:01 -0800549 "destination_nodes": [
550 {
551 "name": "baz"
552 }
553 ]
554})channel",
555 Channel::MiniReflectTypeTable()));
556
Ravago Jonescf453ab2020-05-06 21:14:53 -0700557 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
558 R"channel({
Austin Schuh719946b2019-12-28 14:51:01 -0800559 "name": "/test",
560 "type": "aos.examples.Ping",
561 "source_node": "bar",
562 "logger": "LOCAL_AND_REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700563 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800564 "destination_nodes": [
565 {
566 "name": "baz"
567 }
568 ]
569})channel",
Ravago Jonescf453ab2020-05-06 21:14:53 -0700570 Channel::MiniReflectTypeTable()));
Austin Schuh719946b2019-12-28 14:51:01 -0800571
572 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
573 R"node({
574 "name": "foo"
575})node",
576 Node::MiniReflectTypeTable()));
577
578 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
579 R"node({
580 "name": "bar"
581})node",
582 Node::MiniReflectTypeTable()));
583
584 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
585 R"node({
586 "name": "baz"
587})node",
588 Node::MiniReflectTypeTable()));
589
590 // Local logger.
591 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
592 &foo_node.message()));
593 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
594 &bar_node.message()));
595 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(),
596 &baz_node.message()));
Austin Schuh48e94502021-06-18 18:35:53 -0700597 EXPECT_TRUE(
598 ChannelMessageIsLoggedOnNode(&logged_on_self_channel.message(), nullptr));
Austin Schuh719946b2019-12-28 14:51:01 -0800599
600 // No logger.
601 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
602 &foo_node.message()));
603 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
Ravago Jonescf453ab2020-05-06 21:14:53 -0700604 &bar_node.message()));
Austin Schuh719946b2019-12-28 14:51:01 -0800605 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&not_logged_channel.message(),
606 &baz_node.message()));
Austin Schuh48e94502021-06-18 18:35:53 -0700607 EXPECT_FALSE(
608 ChannelMessageIsLoggedOnNode(&not_logged_channel.message(), nullptr));
Austin Schuh719946b2019-12-28 14:51:01 -0800609
610 // Remote logger.
611 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
612 &foo_node.message()));
613 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
614 &bar_node.message()));
615 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_remote_channel.message(),
616 &baz_node.message()));
617
618 // Separate logger.
619 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(
620 &logged_on_separate_logger_node_channel.message(), &foo_node.message()));
621 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
622 &logged_on_separate_logger_node_channel.message(), &bar_node.message()));
623 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(
624 &logged_on_separate_logger_node_channel.message(), &baz_node.message()));
625
626 // Logged in multiple places.
627 EXPECT_FALSE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
628 &foo_node.message()));
629 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
630 &bar_node.message()));
631 EXPECT_TRUE(ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
632 &baz_node.message()));
633}
634
Austin Schuh48e94502021-06-18 18:35:53 -0700635// Tests that our node message is logged helpers work as intended.
636TEST_F(ConfigurationDeathTest, ChannelMessageIsLoggedOnNode) {
637 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
638 R"channel({
639 "name": "/test",
640 "type": "aos.examples.Ping",
641 "source_node": "bar",
642 "logger": "LOCAL_AND_REMOTE_LOGGER",
643 "logger_nodes": ["baz"],
644 "destination_nodes": [
645 {
646 "name": "baz"
647 }
648 ]
649})channel",
650 Channel::MiniReflectTypeTable()));
651
652 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
653 JsonToFlatbuffer(
654 R"channel({
655 "name": "/test",
656 "type": "aos.examples.Ping",
657 "source_node": "bar",
658 "logger": "REMOTE_LOGGER",
659 "logger_nodes": ["foo"],
660 "destination_nodes": [
661 {
662 "name": "baz"
663 }
664 ]
665})channel",
666 Channel::MiniReflectTypeTable()));
667
668 EXPECT_DEATH(
669 {
670 ChannelMessageIsLoggedOnNode(&logged_on_both_channel.message(),
671 nullptr);
672 },
673 "Unsupported logging configuration in a single node world");
674 EXPECT_DEATH(
675 {
676 ChannelMessageIsLoggedOnNode(
677 &logged_on_separate_logger_node_channel.message(), nullptr);
678 },
679 "Unsupported logging configuration in a single node world");
680}
681
Austin Schuh719946b2019-12-28 14:51:01 -0800682// Tests that our forwarding timestamps are logged helpers work as intended.
683TEST_F(ConfigurationTest, ConnectionDeliveryTimeIsLoggedOnNode) {
684 FlatbufferDetachedBuffer<Channel> logged_on_self_channel(JsonToFlatbuffer(
685 R"channel({
686 "name": "/test",
687 "type": "aos.examples.Ping",
688 "source_node": "bar",
689 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700690 "logger_nodes": ["baz"],
Austin Schuh719946b2019-12-28 14:51:01 -0800691 "destination_nodes": [
692 {
693 "name": "baz"
694 }
695 ]
696})channel",
697 Channel::MiniReflectTypeTable()));
698
699 FlatbufferDetachedBuffer<Channel> not_logged_channel(JsonToFlatbuffer(
700 R"channel({
701 "name": "/test",
702 "type": "aos.examples.Ping",
703 "source_node": "bar",
704 "logger": "NOT_LOGGED",
705 "destination_nodes": [
706 {
707 "name": "baz",
708 "timestamp_logger": "NOT_LOGGED"
709 }
710 ]
711})channel",
712 Channel::MiniReflectTypeTable()));
713
714 FlatbufferDetachedBuffer<Channel> logged_on_remote_channel(JsonToFlatbuffer(
715 R"channel({
716 "name": "/test",
717 "type": "aos.examples.Ping",
718 "source_node": "bar",
719 "destination_nodes": [
720 {
721 "name": "baz",
722 "timestamp_logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700723 "timestamp_logger_nodes": ["bar"]
Austin Schuh719946b2019-12-28 14:51:01 -0800724 }
725 ]
726})channel",
727 Channel::MiniReflectTypeTable()));
728
729 FlatbufferDetachedBuffer<Channel> logged_on_separate_logger_node_channel(
730 JsonToFlatbuffer(
731 R"channel({
732 "name": "/test",
733 "type": "aos.examples.Ping",
734 "source_node": "bar",
735 "logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700736 "logger_nodes": ["foo"],
Austin Schuh719946b2019-12-28 14:51:01 -0800737 "destination_nodes": [
738 {
739 "name": "baz",
740 "timestamp_logger": "REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700741 "timestamp_logger_nodes": ["foo"]
Austin Schuh719946b2019-12-28 14:51:01 -0800742 }
743 ]
744})channel",
745 Channel::MiniReflectTypeTable()));
746
Ravago Jonescf453ab2020-05-06 21:14:53 -0700747 FlatbufferDetachedBuffer<Channel> logged_on_both_channel(JsonToFlatbuffer(
748 R"channel({
Austin Schuh719946b2019-12-28 14:51:01 -0800749 "name": "/test",
750 "type": "aos.examples.Ping",
751 "source_node": "bar",
752 "destination_nodes": [
753 {
754 "name": "baz",
755 "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
Austin Schuhda40e472020-03-28 15:15:29 -0700756 "timestamp_logger_nodes": ["bar"]
Austin Schuh719946b2019-12-28 14:51:01 -0800757 }
758 ]
759})channel",
Ravago Jonescf453ab2020-05-06 21:14:53 -0700760 Channel::MiniReflectTypeTable()));
Austin Schuh719946b2019-12-28 14:51:01 -0800761
762 FlatbufferDetachedBuffer<Node> foo_node(JsonToFlatbuffer(
763 R"node({
764 "name": "foo"
765})node",
766 Node::MiniReflectTypeTable()));
767
768 FlatbufferDetachedBuffer<Node> bar_node(JsonToFlatbuffer(
769 R"node({
770 "name": "bar"
771})node",
772 Node::MiniReflectTypeTable()));
773
774 FlatbufferDetachedBuffer<Node> baz_node(JsonToFlatbuffer(
775 R"node({
776 "name": "baz"
777})node",
778 Node::MiniReflectTypeTable()));
779
780 // Local logger.
781 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
782 &logged_on_self_channel.message(), &baz_node.message(),
783 &foo_node.message()));
784 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
785 &logged_on_self_channel.message(), &baz_node.message(),
786 &bar_node.message()));
787 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
788 &logged_on_self_channel.message(), &baz_node.message(),
789 &baz_node.message()));
790
791 // No logger means.
792 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
793 &not_logged_channel.message(), &baz_node.message(), &foo_node.message()));
794 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
795 &not_logged_channel.message(), &baz_node.message(), &bar_node.message()));
796 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
797 &not_logged_channel.message(), &baz_node.message(), &baz_node.message()));
798
799 // Remote logger.
800 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
801 &logged_on_remote_channel.message(), &baz_node.message(),
802 &foo_node.message()));
803 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
804 &logged_on_remote_channel.message(), &baz_node.message(),
805 &bar_node.message()));
806 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
807 &logged_on_remote_channel.message(), &baz_node.message(),
808 &baz_node.message()));
809
810 // Separate logger.
811 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
812 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
813 &foo_node.message()));
814 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
815 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
816 &bar_node.message()));
817 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
818 &logged_on_separate_logger_node_channel.message(), &baz_node.message(),
819 &baz_node.message()));
820
821 // Logged on both the node and a remote node.
822 EXPECT_FALSE(ConnectionDeliveryTimeIsLoggedOnNode(
823 &logged_on_both_channel.message(), &baz_node.message(),
824 &foo_node.message()));
825 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
826 &logged_on_both_channel.message(), &baz_node.message(),
827 &bar_node.message()));
828 EXPECT_TRUE(ConnectionDeliveryTimeIsLoggedOnNode(
829 &logged_on_both_channel.message(), &baz_node.message(),
830 &baz_node.message()));
831}
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800832
833// Tests that we can deduce source nodes from a multinode config.
834TEST_F(ConfigurationTest, SourceNodeNames) {
835 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700836 ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800837
838 // This is a bit simplistic in that it doesn't test deduplication, but it does
839 // exercise a lot of the logic.
840 EXPECT_THAT(
841 SourceNodeNames(&config.message(), config.message().nodes()->Get(0)),
842 ::testing::ElementsAreArray({"pi2"}));
843 EXPECT_THAT(
844 SourceNodeNames(&config.message(), config.message().nodes()->Get(1)),
845 ::testing::ElementsAreArray({"pi1"}));
846}
847
848// Tests that we can deduce destination nodes from a multinode config.
849TEST_F(ConfigurationTest, DestinationNodeNames) {
850 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700851 ReadConfig(ArtifactPath("aos/testdata/config1_multinode.json"));
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800852
853 // This is a bit simplistic in that it doesn't test deduplication, but it does
854 // exercise a lot of the logic.
855 EXPECT_THAT(
856 DestinationNodeNames(&config.message(), config.message().nodes()->Get(0)),
857 ::testing::ElementsAreArray({"pi2"}));
858 EXPECT_THAT(
859 DestinationNodeNames(&config.message(), config.message().nodes()->Get(1)),
860 ::testing::ElementsAreArray({"pi1"}));
861}
862
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800863// Tests that we can pull out all the nodes.
864TEST_F(ConfigurationTest, GetNodes) {
865 {
866 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700867 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800868 const Node *pi1 = GetNode(&config.message(), "pi1");
869 const Node *pi2 = GetNode(&config.message(), "pi2");
870
871 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(pi1, pi2));
872 }
873
874 {
875 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700876 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800877 EXPECT_THAT(GetNodes(&config.message()), ::testing::ElementsAre(nullptr));
878 }
879}
880
Austin Schuh65465332020-11-05 17:36:53 -0800881// Tests that we can pull out all the nodes with a tag.
882TEST_F(ConfigurationTest, GetNodesWithTag) {
883 {
884 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700885 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuh65465332020-11-05 17:36:53 -0800886 const Node *pi1 = GetNode(&config.message(), "pi1");
887 const Node *pi2 = GetNode(&config.message(), "pi2");
888
889 EXPECT_THAT(GetNodesWithTag(&config.message(), "a"),
890 ::testing::ElementsAre(pi1));
891 EXPECT_THAT(GetNodesWithTag(&config.message(), "b"),
892 ::testing::ElementsAre(pi2));
893 EXPECT_THAT(GetNodesWithTag(&config.message(), "c"),
894 ::testing::ElementsAre(pi1, pi2));
895 }
896
897 {
898 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700899 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuh65465332020-11-05 17:36:53 -0800900 EXPECT_THAT(GetNodesWithTag(&config.message(), "arglfish"),
901 ::testing::ElementsAre(nullptr));
902 }
903}
904
Brian Silverman631b6262021-11-10 12:25:08 -0800905// Tests that we can check if a node has a tag.
906TEST_F(ConfigurationTest, NodeHasTag) {
907 {
908 FlatbufferDetachedBuffer<Configuration> config =
909 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
910 const Node *pi1 = GetNode(&config.message(), "pi1");
911 const Node *pi2 = GetNode(&config.message(), "pi2");
912
913 EXPECT_TRUE(NodeHasTag(pi1, "a"));
914 EXPECT_FALSE(NodeHasTag(pi2, "a"));
915 EXPECT_FALSE(NodeHasTag(pi1, "b"));
916 EXPECT_TRUE(NodeHasTag(pi2, "b"));
917 EXPECT_TRUE(NodeHasTag(pi1, "c"));
918 EXPECT_TRUE(NodeHasTag(pi2, "c"));
919 EXPECT_FALSE(NodeHasTag(pi1, "nope"));
920 EXPECT_FALSE(NodeHasTag(pi2, "nope"));
921 }
922
923 EXPECT_TRUE(NodeHasTag(nullptr, "arglfish"));
924}
925
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800926// Tests that we can extract a node index from a config.
927TEST_F(ConfigurationTest, GetNodeIndex) {
928 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700929 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuh04408fc2020-02-16 21:48:54 -0800930 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh373f1762021-06-02 21:07:09 -0700931 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800932 const Node *pi1 = GetNode(&config.message(), "pi1");
933 const Node *pi2 = GetNode(&config.message(), "pi2");
934
Austin Schuh04408fc2020-02-16 21:48:54 -0800935 // Try the normal case.
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800936 EXPECT_EQ(GetNodeIndex(&config.message(), pi1), 0);
937 EXPECT_EQ(GetNodeIndex(&config.message(), pi2), 1);
Austin Schuh04408fc2020-02-16 21:48:54 -0800938
939 // Now try if we have node pointers from a different message.
940 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1), 0);
941 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2), 1);
942
943 // And now try string names.
944 EXPECT_EQ(GetNodeIndex(&config2.message(), pi1->name()->string_view()), 0);
945 EXPECT_EQ(GetNodeIndex(&config2.message(), pi2->name()->string_view()), 1);
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800946}
947
948// Tests that GetNodeOrDie handles both single and multi-node worlds and returns
949// valid nodes.
950TEST_F(ConfigurationDeathTest, GetNodeOrDie) {
951 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700952 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800953 FlatbufferDetachedBuffer<Configuration> config2 =
Austin Schuh373f1762021-06-02 21:07:09 -0700954 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800955 {
956 // Simple case, nullptr -> nullptr
957 FlatbufferDetachedBuffer<Configuration> single_node_config =
Austin Schuh373f1762021-06-02 21:07:09 -0700958 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
Austin Schuhc9e10ec2020-01-26 16:08:28 -0800959 EXPECT_EQ(nullptr, GetNodeOrDie(&single_node_config.message(), nullptr));
960
961 // Confirm that we die when a node is passed in.
962 EXPECT_DEATH(
963 {
964 GetNodeOrDie(&single_node_config.message(),
965 config.message().nodes()->Get(0));
966 },
967 "Provided a node in a single node world.");
968 }
969
970 const Node *pi1 = GetNode(&config.message(), "pi1");
971 // Now try a lookup using a node from a different instance of the config.
972 EXPECT_EQ(pi1,
973 GetNodeOrDie(&config.message(), config2.message().nodes()->Get(0)));
974}
975
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800976TEST_F(ConfigurationTest, GetNodeFromHostname) {
977 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700978 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800979 EXPECT_EQ("pi1",
980 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
981 ->name()
982 ->string_view());
983 EXPECT_EQ("pi2", CHECK_NOTNULL(
984 GetNodeFromHostname(&config.message(), "raspberrypi2"))
985 ->name()
986 ->string_view());
987 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi3"));
988 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
989 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
990}
991
992TEST_F(ConfigurationTest, GetNodeFromHostnames) {
993 FlatbufferDetachedBuffer<Configuration> config =
Austin Schuh373f1762021-06-02 21:07:09 -0700994 ReadConfig(ArtifactPath("aos/testdata/good_multinode_hostnames.json"));
Brian Silvermanaa2633f2020-02-17 21:04:14 -0800995 EXPECT_EQ("pi1",
996 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "raspberrypi"))
997 ->name()
998 ->string_view());
999 EXPECT_EQ("pi2", CHECK_NOTNULL(
1000 GetNodeFromHostname(&config.message(), "raspberrypi2"))
1001 ->name()
1002 ->string_view());
1003 EXPECT_EQ("pi2", CHECK_NOTNULL(
1004 GetNodeFromHostname(&config.message(), "raspberrypi3"))
1005 ->name()
1006 ->string_view());
Ravago Jonescf453ab2020-05-06 21:14:53 -07001007 EXPECT_EQ("pi2",
1008 CHECK_NOTNULL(GetNodeFromHostname(&config.message(), "other"))
1009 ->name()
1010 ->string_view());
Brian Silvermanaa2633f2020-02-17 21:04:14 -08001011 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "raspberrypi4"));
1012 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "localhost"));
1013 EXPECT_EQ(nullptr, GetNodeFromHostname(&config.message(), "3"));
1014}
1015
Austin Schuhfc7b6a02021-07-12 21:19:07 -07001016// Tests that SourceNodeIndex reasonably handles a multi-node log file.
1017TEST_F(ConfigurationTest, SourceNodeIndex) {
1018 FlatbufferDetachedBuffer<Configuration> config =
1019 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
1020 std::vector<size_t> result = SourceNodeIndex(&config.message());
1021
1022 EXPECT_THAT(result, ::testing::ElementsAreArray({0, 1, 0, 0}));
1023}
1024
Austin Schuh5e95bd62021-10-11 18:40:22 -07001025// Tests that we reject invalid logging configurations.
1026TEST_F(ConfigurationDeathTest, InvalidLoggerConfig) {
1027 EXPECT_DEATH(
1028 {
Milind Upadhyay17098ba2022-04-15 22:18:50 -07001029 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
1030 ArtifactPath("aos/testdata/invalid_logging_configuration.json"));
Austin Schuh5e95bd62021-10-11 18:40:22 -07001031 },
1032 "Logging timestamps without data");
1033}
1034
Austin Schuha156fb22021-10-11 19:23:21 -07001035// Tests that we reject duplicate timestamp destination node configurations.
1036TEST_F(ConfigurationDeathTest, DuplicateTimestampDestinationNodes) {
1037 EXPECT_DEATH(
1038 {
1039 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
1040 ArtifactPath("aos/testdata/duplicate_destination_nodes.json"));
1041 },
1042 "Found duplicate timestamp_logger_nodes in");
1043}
1044
1045// Tests that we reject duplicate logger node configurations for a channel's
1046// data.
1047TEST_F(ConfigurationDeathTest, DuplicateLoggerNodes) {
1048 EXPECT_DEATH(
1049 {
1050 FlatbufferDetachedBuffer<Configuration> config = ReadConfig(
1051 ArtifactPath("aos/testdata/duplicate_logger_nodes.json"));
1052 },
1053 "Found duplicate logger_nodes in");
1054}
1055
Austin Schuhfb37c612022-08-11 15:24:51 -07001056// Tests that we properly compute the queue size for the provided duration.
1057TEST_F(ConfigurationTest, QueueSize) {
1058 EXPECT_EQ(QueueSize(100, chrono::seconds(2)), 200);
1059 EXPECT_EQ(QueueSize(200, chrono::seconds(2)), 400);
1060 EXPECT_EQ(QueueSize(100, chrono::seconds(6)), 600);
1061 EXPECT_EQ(QueueSize(100, chrono::milliseconds(10)), 1);
1062 EXPECT_EQ(QueueSize(100, chrono::milliseconds(10) - chrono::nanoseconds(1)),
1063 1);
1064 EXPECT_EQ(QueueSize(100, chrono::milliseconds(10) - chrono::nanoseconds(2)),
1065 1);
1066}
1067
1068// Tests that we compute scratch buffer size correctly too.
1069TEST_F(ConfigurationTest, QueueScratchBufferSize) {
1070 const aos::FlatbufferDetachedBuffer<Channel> channel =
1071 JsonToFlatbuffer<Channel>(
1072 "{ \"name\": \"/foo\", \"type\": \".aos.bar\", \"num_readers\": 5, "
1073 "\"num_senders\": 10 }");
Austin Schuhfb37c612022-08-11 15:24:51 -07001074 EXPECT_EQ(QueueScratchBufferSize(&channel.message()), 15);
1075}
1076
Nathan Leong307c9692022-10-08 15:25:03 -07001077// Tests that GetSchema returns schema of specified type
1078TEST_F(ConfigurationTest, GetSchema) {
1079 FlatbufferDetachedBuffer<Configuration> config =
1080 ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
1081 FlatbufferVector<reflection::Schema> expected_schema =
1082 FileToFlatbuffer<reflection::Schema>(
1083 ArtifactPath("aos/events/ping.bfbs"));
1084 EXPECT_EQ(FlatbufferToJson(GetSchema(&config.message(), "aos.examples.Ping")),
1085 FlatbufferToJson(expected_schema));
1086 EXPECT_EQ(GetSchema(&config.message(), "invalid_name"), nullptr);
1087}
1088
1089// Tests that GetSchema template returns schema of specified type
1090TEST_F(ConfigurationTest, GetSchemaTemplate) {
1091 FlatbufferDetachedBuffer<Configuration> config =
1092 ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
1093 FlatbufferVector<reflection::Schema> expected_schema =
1094 FileToFlatbuffer<reflection::Schema>(
1095 ArtifactPath("aos/events/ping.bfbs"));
1096 EXPECT_EQ(FlatbufferToJson(GetSchema<aos::examples::Ping>(&config.message())),
1097 FlatbufferToJson(expected_schema));
1098}
1099
1100// Tests that GetSchemaDetachedBuffer returns detached buffer of specified type
1101TEST_F(ConfigurationTest, GetSchemaDetachedBuffer) {
1102 FlatbufferDetachedBuffer<Configuration> config =
1103 ReadConfig(ArtifactPath("aos/events/pingpong_config.json"));
1104 FlatbufferVector<reflection::Schema> expected_schema =
1105 FileToFlatbuffer<reflection::Schema>(
1106 ArtifactPath("aos/events/ping.bfbs"));
1107 EXPECT_EQ(FlatbufferToJson(
1108 GetSchemaDetachedBuffer(&config.message(), "aos.examples.Ping")
1109 .value()),
1110 FlatbufferToJson(expected_schema));
1111 EXPECT_EQ(GetSchemaDetachedBuffer(&config.message(), "invalid_name"),
1112 std::nullopt);
1113}
1114
James Kuszmaul741a4d02023-01-05 14:59:21 -08001115// Tests that we can use a utility to add individual channels to a single-node
1116// config.
1117TEST_F(ConfigurationTest, AddChannelToConfigSingleNode) {
1118 FlatbufferDetachedBuffer<Configuration> base_config =
1119 ReadConfig(ArtifactPath("aos/testdata/config1.json"));
1120
1121 FlatbufferVector<reflection::Schema> schema =
1122 FileToFlatbuffer<reflection::Schema>(
1123 ArtifactPath("aos/events/ping.bfbs"));
1124
1125 FlatbufferDetachedBuffer<Configuration> new_config =
1126 AddChannelToConfiguration(&base_config.message(), "/new", schema);
1127
1128 ASSERT_EQ(new_config.message().channels()->size(),
1129 base_config.message().channels()->size() + 1);
1130
1131 const Channel *channel =
1132 GetChannel(new_config, "/new", "aos.examples.Ping", "", nullptr);
1133 ASSERT_TRUE(channel != nullptr);
1134 ASSERT_TRUE(channel->has_schema());
1135 // Check that we don't populate channel settings that we don't override the
1136 // defaults of.
1137 ASSERT_FALSE(channel->has_frequency());
1138}
1139
1140// Tests that we can use a utility to add individual channels to a multi-node
1141// config.
1142TEST_F(ConfigurationTest, AddChannelToConfigMultiNode) {
1143 FlatbufferDetachedBuffer<Configuration> base_config =
1144 ReadConfig(ArtifactPath("aos/testdata/good_multinode.json"));
1145
1146 FlatbufferVector<reflection::Schema> schema =
1147 FileToFlatbuffer<reflection::Schema>(
1148 ArtifactPath("aos/events/ping.bfbs"));
1149
1150 aos::ChannelT channel_overrides;
1151 channel_overrides.frequency = 971;
1152 FlatbufferDetachedBuffer<Configuration> new_config =
1153 AddChannelToConfiguration(&base_config.message(), "/new", schema,
1154 GetNode(&base_config.message(), "pi1"),
1155 channel_overrides);
1156
1157 ASSERT_EQ(new_config.message().channels()->size(),
1158 base_config.message().channels()->size() + 1);
1159
1160 const Channel *channel =
1161 GetChannel(new_config, "/new", "aos.examples.Ping", "", nullptr);
1162 ASSERT_TRUE(channel != nullptr);
1163 ASSERT_TRUE(channel->has_schema());
1164 ASSERT_TRUE(channel->has_source_node());
1165 ASSERT_EQ("pi1", channel->source_node()->string_view());
1166 ASSERT_EQ(971, channel->frequency());
1167}
1168
Stephan Pleinesf63bde82024-01-13 15:59:33 -08001169} // namespace aos::configuration::testing