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