1 /* Copyright 2016, Ableton AG, Berlin. All rights reserved.
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * If you would like to incorporate Link into a proprietary software application,
17 * please contact <link-devs@ableton.com>.
18 */
19
20 #include <ableton/discovery/PeerGateway.hpp>
21 #include <ableton/test/CatchWrapper.hpp>
22 #include <ableton/test/serial_io/Fixture.hpp>
23 #include <ableton/util/Log.hpp>
24
25 namespace ableton
26 {
27 namespace discovery
28 {
29 namespace
30 {
31
32 struct TestNodeState : std::tuple<std::string, double>
33 {
TestNodeStateableton::discovery::__anon12e1acf50111::TestNodeState34 TestNodeState(std::string ident, double tempo)
35 : std::tuple<std::string, double>(std::move(ident), std::move(tempo))
36 {
37 }
38
identableton::discovery::__anon12e1acf50111::TestNodeState39 std::string ident() const
40 {
41 return std::get<0>(*this);
42 }
43 };
44
45 struct TestMessenger
46 {
47 template <typename Handler>
receiveableton::discovery::__anon12e1acf50111::TestMessenger48 void receive(Handler handler)
49 {
50 receivePeerState = [handler](const PeerState<TestNodeState>& msg) { handler(msg); };
51
52 receiveByeBye = [handler](const ByeBye<std::string>& msg) { handler(msg); };
53 }
54
55 std::function<void(const PeerState<TestNodeState>&)> receivePeerState;
56 std::function<void(const ByeBye<std::string>&)> receiveByeBye;
57 };
58
59 struct TestObserver
60 {
61 using GatewayObserverNodeState = TestNodeState;
62 using GatewayObserverNodeId = std::string;
63
sawPeer(TestObserver & observer,const GatewayObserverNodeState & peer)64 friend void sawPeer(TestObserver& observer, const GatewayObserverNodeState& peer)
65 {
66 observer.mPeersSeen.push_back(peer);
67 }
68
peerLeft(TestObserver & observer,const GatewayObserverNodeId & id)69 friend void peerLeft(TestObserver& observer, const GatewayObserverNodeId& id)
70 {
71 observer.mPeersLeft.push_back(id);
72 }
73
peerTimedOut(TestObserver & observer,const GatewayObserverNodeId & id)74 friend void peerTimedOut(TestObserver& observer, const GatewayObserverNodeId& id)
75 {
76 observer.mPeersTimedOut.push_back(id);
77 }
78
79 std::vector<GatewayObserverNodeState> mPeersSeen;
80 std::vector<GatewayObserverNodeId> mPeersLeft;
81 std::vector<GatewayObserverNodeId> mPeersTimedOut;
82 };
83
expectPeersSeen(std::vector<TestNodeState> expected,const TestObserver & observer)84 void expectPeersSeen(std::vector<TestNodeState> expected, const TestObserver& observer)
85 {
86 CHECK(expected == observer.mPeersSeen);
87 }
88
expectPeersLeft(std::vector<std::string> expected,const TestObserver & observer)89 void expectPeersLeft(std::vector<std::string> expected, const TestObserver& observer)
90 {
91 CHECK(expected == observer.mPeersLeft);
92 }
93
expectPeersTimedOut(std::vector<std::string> expected,const TestObserver & observer)94 void expectPeersTimedOut(std::vector<std::string> expected, const TestObserver& observer)
95 {
96 CHECK(expected == observer.mPeersTimedOut);
97 }
98
99 // Test peers
100 const auto peerA = TestNodeState{"peerA", 120};
101 const auto peerB = TestNodeState{"peerB", 150};
102
103 } // anonymous namespace
104
105 TEST_CASE("PeerGateway | NoActivity", "[PeerGateway]")
106 {
107 test::serial_io::Fixture io;
108 TestObserver observer;
109 auto listener = makePeerGateway(util::injectVal(TestMessenger{}),
110 util::injectRef(observer), util::injectVal(io.makeIoContext()));
111 io.advanceTime(std::chrono::seconds(10));
112
113 // Without any outside interaction but the passage of time, our
114 // listener should not have seen any peers.
115 CHECK(observer.mPeersSeen.empty());
116 CHECK(observer.mPeersLeft.empty());
117 CHECK(observer.mPeersTimedOut.empty());
118 }
119
120 TEST_CASE("PeerGateway | ReceivedPeerState", "[PeerGateway]")
121 {
122 test::serial_io::Fixture io;
123 TestObserver observer;
124 TestMessenger messenger;
125 auto listener = makePeerGateway(util::injectRef(messenger), util::injectRef(observer),
126 util::injectVal(io.makeIoContext()));
127
128 messenger.receivePeerState({peerA, 5});
129 io.flush();
130
131 expectPeersSeen({peerA}, observer);
132 }
133
134 TEST_CASE("PeerGateway | TwoPeersOneLeaves", "[PeerGateway]")
135 {
136 test::serial_io::Fixture io;
137 TestObserver observer;
138 TestMessenger messenger;
139 auto listener = makePeerGateway(util::injectRef(messenger), util::injectRef(observer),
140 util::injectVal(io.makeIoContext()));
141
142 messenger.receivePeerState({peerA, 5});
143 messenger.receivePeerState({peerB, 5});
144 messenger.receiveByeBye({peerA.ident()});
145 io.flush();
146
147 expectPeersSeen({peerA, peerB}, observer);
148 expectPeersLeft({peerA.ident()}, observer);
149 }
150
151 TEST_CASE("PeerGateway | TwoPeersOneTimesOut", "[PeerGateway]")
152 {
153 test::serial_io::Fixture io;
154 TestObserver observer;
155 TestMessenger messenger;
156 auto listener = makePeerGateway(util::injectRef(messenger), util::injectRef(observer),
157 util::injectVal(io.makeIoContext()));
158
159 messenger.receivePeerState({peerA, 5});
160 messenger.receivePeerState({peerB, 10});
161
162 io.advanceTime(std::chrono::seconds(3));
163 expectPeersTimedOut({}, observer);
164 io.advanceTime(std::chrono::seconds(4));
165 expectPeersTimedOut({peerA.ident()}, observer);
166 }
167
168 TEST_CASE("PeerGateway | PeerTimesOutAndIsSeenAgain", "[PeerGateway]")
169 {
170 test::serial_io::Fixture io;
171 TestObserver observer;
172 TestMessenger messenger;
173 auto listener = makePeerGateway(util::injectRef(messenger), util::injectRef(observer),
174 util::injectVal(io.makeIoContext()));
175
176 messenger.receivePeerState({peerA, 5});
177 io.advanceTime(std::chrono::seconds(7));
178
179 expectPeersTimedOut({peerA.ident()}, observer);
180
181 messenger.receivePeerState({peerA, 5});
182 io.advanceTime(std::chrono::seconds(3));
183
184 expectPeersSeen({peerA, peerA}, observer);
185 expectPeersTimedOut({peerA.ident()}, observer);
186 }
187
188 } // namespace discovery
189 } // namespace ableton
190