blob: d35192a68a01b5f20ee61f6e87bb27bef2c465c9 [file] [log] [blame]
Philipp Schrader790cb542023-07-05 21:06:52 -07001#include "glog/logging.h"
2#include "gtest/gtest.h"
3
Austin Schuh6b9c4152019-11-29 12:45:24 -08004#include "aos/events/ping_lib.h"
5#include "aos/events/pong_lib.h"
6#include "aos/events/simulated_event_loop.h"
7#include "aos/json_to_flatbuffer.h"
Austin Schuh373f1762021-06-02 21:07:09 -07008#include "aos/testing/path.h"
Austin Schuh6b9c4152019-11-29 12:45:24 -08009
10namespace aos {
11namespace testing {
12
Austin Schuh373f1762021-06-02 21:07:09 -070013using aos::testing::ArtifactPath;
14
Austin Schuh6b9c4152019-11-29 12:45:24 -080015namespace chrono = std::chrono;
16
17class PingPongTest : public ::testing::Test {
18 public:
19 PingPongTest()
Austin Schuh373f1762021-06-02 21:07:09 -070020 : config_(aos::configuration::ReadConfig(
21 ArtifactPath("aos/events/pingpong_config.json"))),
Austin Schuh6b9c4152019-11-29 12:45:24 -080022 event_loop_factory_(&config_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080023 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
Austin Schuh6b9c4152019-11-29 12:45:24 -080024 ping_(ping_event_loop_.get()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080025 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong")),
Austin Schuh6b9c4152019-11-29 12:45:24 -080026 pong_(pong_event_loop_.get()) {}
27
28 // Config and factory.
29 // The factory is a factory for connected event loops. Each application needs
30 // a separate event loop (because you can't send a message to yourself in a
31 // single event loop). The created event loops can then send messages to each
32 // other and trigger callbacks to be called, or fetchers to receive data.
33 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
34 SimulatedEventLoopFactory event_loop_factory_;
35
36 // Event loop and app for Ping
37 std::unique_ptr<EventLoop> ping_event_loop_;
38 Ping ping_;
39
40 // Event loop and app for Pong
41 std::unique_ptr<EventLoop> pong_event_loop_;
42 Pong pong_;
43};
44
45// Tests that we can startup at all. This confirms that the channels are all in
46// the config.
47TEST_F(PingPongTest, Starts) {
48 // RunFor lives in the factory because all the loops need to run together, and
49 // the factory is the only object that conceptually knows about all of the
50 // loops at once.
51 event_loop_factory_.RunFor(chrono::seconds(10));
52}
53
54// Tests that the number of pong messages matches the number of ping messages.
55TEST_F(PingPongTest, AlwaysReplies) {
56 std::unique_ptr<EventLoop> test_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080057 event_loop_factory_.MakeEventLoop("test");
Austin Schuh6b9c4152019-11-29 12:45:24 -080058
59 int ping_count = 0;
60 int pong_count = 0;
61
62 // Confirm that the ping value matches.
63 test_event_loop->MakeWatcher("/test",
64 [&ping_count](const examples::Ping &ping) {
65 EXPECT_EQ(ping.value(), ping_count + 1);
66 ++ping_count;
67 });
68 // Confirm that the ping and pong counts both match, and the value also
69 // matches.
70 test_event_loop->MakeWatcher(
71 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
72 EXPECT_EQ(pong.value(), pong_count + 1);
73 ++pong_count;
74 EXPECT_EQ(ping_count, pong_count);
75 });
76
77 event_loop_factory_.RunFor(chrono::seconds(10));
78
79 // We run at t=0 and t=10 seconds, which means we run 1 extra time.
80 EXPECT_EQ(ping_count, 1001);
81}
82
Austin Schuh0afe7242021-07-21 15:42:29 -070083// Multi-node ping pong test. This test carefully mirrors the structure of the
84// single node test above to help highlight the similarities and differences.
85class MultiNodePingPongTest : public ::testing::Test {
86 public:
87 MultiNodePingPongTest()
88 : config_(aos::configuration::ReadConfig(ArtifactPath(
89 "aos/events/multinode_pingpong_test_split_config.json"))),
90 event_loop_factory_(&config_.message()),
91 pi1_(
92 configuration::GetNode(event_loop_factory_.configuration(), "pi1")),
93 pi2_(
94 configuration::GetNode(event_loop_factory_.configuration(), "pi2")),
95 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping", pi1_)),
96 ping_(ping_event_loop_.get()),
97 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong", pi2_)),
98 pong_(pong_event_loop_.get()) {}
99
100 // Config and factory.
101 // The factory is a factory for connected event loops. Each application needs
102 // a separate event loop (because you can't send a message to yourself in a
103 // single event loop). The created event loops can then send messages to each
104 // other and trigger callbacks to be called, or fetchers to receive data.
105 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
106 SimulatedEventLoopFactory event_loop_factory_;
107
108 // Convenience pointers for each Node.
109 const Node *pi1_;
110 const Node *pi2_;
111
112 // Event loop and app for Ping
113 std::unique_ptr<EventLoop> ping_event_loop_;
114 Ping ping_;
115
116 // Event loop and app for Pong
117 std::unique_ptr<EventLoop> pong_event_loop_;
118 Pong pong_;
119};
120
121// Tests that the number of pong messages matches the number of ping messages
122// (on both nodes this time)
123TEST_F(MultiNodePingPongTest, AlwaysReplies) {
124 // For grins, test that ping and pong appear on both nodes and match.
125 std::unique_ptr<EventLoop> pi1_test_event_loop =
126 event_loop_factory_.MakeEventLoop("test", pi1_);
127 std::unique_ptr<EventLoop> pi2_test_event_loop =
128 event_loop_factory_.MakeEventLoop("test", pi2_);
129
130 int pi1_ping_count = 0;
131 int pi2_ping_count = 0;
132 int pi1_pong_count = 0;
133 int pi2_pong_count = 0;
134
135 // Confirm that the ping value matches on both nodes.
136 pi1_test_event_loop->MakeWatcher(
137 "/test", [&pi1_ping_count](const examples::Ping &ping) {
138 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
139 ++pi1_ping_count;
140 });
141 pi2_test_event_loop->MakeWatcher(
142 "/test", [&pi2_ping_count](const examples::Ping &ping) {
143 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
144 ++pi2_ping_count;
145 });
146
147 // Confirm that the ping and pong counts both match, and the value also
148 // matches.
149 pi2_test_event_loop->MakeWatcher(
150 "/test", [&pi2_pong_count, &pi2_ping_count](const examples::Pong &pong) {
151 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
152 ++pi2_pong_count;
153 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
154 });
155 pi1_test_event_loop->MakeWatcher(
156 "/test", [&pi1_pong_count, &pi1_ping_count](const examples::Pong &pong) {
157 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
158 ++pi1_pong_count;
159 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
160 });
161
162 // Since forwarding takes "time", we need to run a bit longer to let pong
163 // finish the last cycle.
164 event_loop_factory_.RunFor(chrono::seconds(10) + chrono::milliseconds(5));
165
166 // We run at t=0 and t=10 seconds, which means we run 1 extra time.
167 EXPECT_EQ(pi1_ping_count, 1001);
168 EXPECT_EQ(pi2_ping_count, 1001);
169}
170
Austin Schuh6b9c4152019-11-29 12:45:24 -0800171} // namespace testing
172} // namespace aos