Mercurial > hg > orthanc-stone
comparison UnitTestsSources/TestMessageBroker2.cpp @ 373:d6136a7e914d
making branch am-2 the new mainline
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 05 Nov 2018 10:06:18 +0100 |
parents | dbfe2e9e5020 |
children | e7a494bdd956 |
comparison
equal
deleted
inserted
replaced
371:fe4befe03935 | 373:d6136a7e914d |
---|---|
1 /** | |
2 * Stone of Orthanc | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2018 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU Affero General Public License | |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Affero General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Affero General Public License | |
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 **/ | |
20 | |
21 | |
22 #include "gtest/gtest.h" | |
23 | |
24 #include "Framework/Messages/MessageBroker.h" | |
25 #include "Framework/Messages/Promise.h" | |
26 #include "Framework/Messages/IObservable.h" | |
27 #include "Framework/Messages/IObserver.h" | |
28 #include "Framework/Messages/MessageForwarder.h" | |
29 | |
30 | |
31 int testCounter = 0; | |
32 namespace { | |
33 | |
34 using namespace OrthancStone; | |
35 | |
36 | |
37 enum CustomMessageType | |
38 { | |
39 CustomMessageType_First = MessageType_CustomMessage + 1, | |
40 | |
41 CustomMessageType_Completed, | |
42 CustomMessageType_Increment | |
43 }; | |
44 | |
45 | |
46 class MyObservable : public IObservable | |
47 { | |
48 public: | |
49 struct MyCustomMessage: public BaseMessage<CustomMessageType_Completed> | |
50 { | |
51 int payload_; | |
52 | |
53 MyCustomMessage(int payload) | |
54 : BaseMessage(), | |
55 payload_(payload) | |
56 {} | |
57 }; | |
58 | |
59 MyObservable(MessageBroker& broker) | |
60 : IObservable(broker) | |
61 {} | |
62 | |
63 }; | |
64 | |
65 class MyObserver : public IObserver | |
66 { | |
67 public: | |
68 MyObserver(MessageBroker& broker) | |
69 : IObserver(broker) | |
70 {} | |
71 | |
72 void HandleCompletedMessage(const MyObservable::MyCustomMessage& message) | |
73 { | |
74 testCounter += message.payload_; | |
75 } | |
76 | |
77 }; | |
78 | |
79 | |
80 class MyIntermediate : public IObserver, public IObservable | |
81 { | |
82 IObservable& observedObject_; | |
83 public: | |
84 MyIntermediate(MessageBroker& broker, IObservable& observedObject) | |
85 : IObserver(broker), | |
86 IObservable(broker), | |
87 observedObject_(observedObject) | |
88 { | |
89 observedObject_.RegisterObserverCallback(new MessageForwarder<MyObservable::MyCustomMessage>(broker, *this)); | |
90 } | |
91 }; | |
92 | |
93 | |
94 class MyPromiseSource : public IObservable | |
95 { | |
96 Promise* currentPromise_; | |
97 public: | |
98 struct MyPromiseMessage: public BaseMessage<MessageType_Test1> | |
99 { | |
100 int increment; | |
101 | |
102 MyPromiseMessage(int increment) | |
103 : BaseMessage(), | |
104 increment(increment) | |
105 {} | |
106 }; | |
107 | |
108 MyPromiseSource(MessageBroker& broker) | |
109 : IObservable(broker), | |
110 currentPromise_(NULL) | |
111 {} | |
112 | |
113 Promise& StartSomethingAsync() | |
114 { | |
115 currentPromise_ = new Promise(broker_); | |
116 return *currentPromise_; | |
117 } | |
118 | |
119 void CompleteSomethingAsyncWithSuccess(int payload) | |
120 { | |
121 currentPromise_->Success(MyPromiseMessage(payload)); | |
122 delete currentPromise_; | |
123 } | |
124 | |
125 void CompleteSomethingAsyncWithFailure(int payload) | |
126 { | |
127 currentPromise_->Failure(MyPromiseMessage(payload)); | |
128 delete currentPromise_; | |
129 } | |
130 }; | |
131 | |
132 | |
133 class MyPromiseTarget : public IObserver | |
134 { | |
135 public: | |
136 MyPromiseTarget(MessageBroker& broker) | |
137 : IObserver(broker) | |
138 {} | |
139 | |
140 void IncrementCounter(const MyPromiseSource::MyPromiseMessage& args) | |
141 { | |
142 testCounter += args.increment; | |
143 } | |
144 | |
145 void DecrementCounter(const MyPromiseSource::MyPromiseMessage& args) | |
146 { | |
147 testCounter -= args.increment; | |
148 } | |
149 }; | |
150 } | |
151 | |
152 | |
153 TEST(MessageBroker2, TestPermanentConnectionSimpleUseCase) | |
154 { | |
155 MessageBroker broker; | |
156 MyObservable observable(broker); | |
157 MyObserver observer(broker); | |
158 | |
159 // create a permanent connection between an observable and an observer | |
160 observable.RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(observer, &MyObserver::HandleCompletedMessage)); | |
161 | |
162 testCounter = 0; | |
163 observable.EmitMessage(MyObservable::MyCustomMessage(12)); | |
164 ASSERT_EQ(12, testCounter); | |
165 | |
166 // the connection is permanent; if we emit the same message again, the observer will be notified again | |
167 testCounter = 0; | |
168 observable.EmitMessage(MyObservable::MyCustomMessage(20)); | |
169 ASSERT_EQ(20, testCounter); | |
170 } | |
171 | |
172 TEST(MessageBroker2, TestMessageForwarderSimpleUseCase) | |
173 { | |
174 MessageBroker broker; | |
175 MyObservable observable(broker); | |
176 MyIntermediate intermediate(broker, observable); | |
177 MyObserver observer(broker); | |
178 | |
179 // let the observer observers the intermediate that is actually forwarding the messages from the observable | |
180 intermediate.RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(observer, &MyObserver::HandleCompletedMessage)); | |
181 | |
182 testCounter = 0; | |
183 observable.EmitMessage(MyObservable::MyCustomMessage(12)); | |
184 ASSERT_EQ(12, testCounter); | |
185 | |
186 // the connection is permanent; if we emit the same message again, the observer will be notified again | |
187 testCounter = 0; | |
188 observable.EmitMessage(MyObservable::MyCustomMessage(20)); | |
189 ASSERT_EQ(20, testCounter); | |
190 } | |
191 | |
192 TEST(MessageBroker2, TestPermanentConnectionDeleteObserver) | |
193 { | |
194 MessageBroker broker; | |
195 MyObservable observable(broker); | |
196 MyObserver* observer = new MyObserver(broker); | |
197 | |
198 // create a permanent connection between an observable and an observer | |
199 observable.RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(*observer, &MyObserver::HandleCompletedMessage)); | |
200 | |
201 testCounter = 0; | |
202 observable.EmitMessage(MyObservable::MyCustomMessage(12)); | |
203 ASSERT_EQ(12, testCounter); | |
204 | |
205 // delete the observer and check that the callback is not called anymore | |
206 delete observer; | |
207 | |
208 // the connection is permanent; if we emit the same message again, the observer will be notified again | |
209 testCounter = 0; | |
210 observable.EmitMessage(MyObservable::MyCustomMessage(20)); | |
211 ASSERT_EQ(0, testCounter); | |
212 } | |
213 | |
214 TEST(MessageBroker2, TestMessageForwarderDeleteIntermediate) | |
215 { | |
216 MessageBroker broker; | |
217 MyObservable observable(broker); | |
218 MyIntermediate* intermediate = new MyIntermediate(broker, observable); | |
219 MyObserver observer(broker); | |
220 | |
221 // let the observer observers the intermediate that is actually forwarding the messages from the observable | |
222 intermediate->RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(observer, &MyObserver::HandleCompletedMessage)); | |
223 | |
224 testCounter = 0; | |
225 observable.EmitMessage(MyObservable::MyCustomMessage(12)); | |
226 ASSERT_EQ(12, testCounter); | |
227 | |
228 delete intermediate; | |
229 | |
230 observable.EmitMessage(MyObservable::MyCustomMessage(20)); | |
231 ASSERT_EQ(12, testCounter); | |
232 } | |
233 | |
234 TEST(MessageBroker2, TestCustomMessage) | |
235 { | |
236 MessageBroker broker; | |
237 MyObservable observable(broker); | |
238 MyIntermediate intermediate(broker, observable); | |
239 MyObserver observer(broker); | |
240 | |
241 // let the observer observers the intermediate that is actually forwarding the messages from the observable | |
242 intermediate.RegisterObserverCallback(new Callable<MyObserver, MyObservable::MyCustomMessage>(observer, &MyObserver::HandleCompletedMessage)); | |
243 | |
244 testCounter = 0; | |
245 observable.EmitMessage(MyObservable::MyCustomMessage(12)); | |
246 ASSERT_EQ(12, testCounter); | |
247 | |
248 // the connection is permanent; if we emit the same message again, the observer will be notified again | |
249 testCounter = 0; | |
250 observable.EmitMessage(MyObservable::MyCustomMessage(20)); | |
251 ASSERT_EQ(20, testCounter); | |
252 } | |
253 | |
254 | |
255 TEST(MessageBroker2, TestPromiseSuccessFailure) | |
256 { | |
257 MessageBroker broker; | |
258 MyPromiseSource source(broker); | |
259 MyPromiseTarget target(broker); | |
260 | |
261 // test a successful promise | |
262 source.StartSomethingAsync() | |
263 .Then(new Callable<MyPromiseTarget, MyPromiseSource::MyPromiseMessage>(target, &MyPromiseTarget::IncrementCounter)) | |
264 .Else(new Callable<MyPromiseTarget, MyPromiseSource::MyPromiseMessage>(target, &MyPromiseTarget::DecrementCounter)); | |
265 | |
266 testCounter = 0; | |
267 source.CompleteSomethingAsyncWithSuccess(10); | |
268 ASSERT_EQ(10, testCounter); | |
269 | |
270 // test a failing promise | |
271 source.StartSomethingAsync() | |
272 .Then(new Callable<MyPromiseTarget, MyPromiseSource::MyPromiseMessage>(target, &MyPromiseTarget::IncrementCounter)) | |
273 .Else(new Callable<MyPromiseTarget, MyPromiseSource::MyPromiseMessage>(target, &MyPromiseTarget::DecrementCounter)); | |
274 | |
275 testCounter = 0; | |
276 source.CompleteSomethingAsyncWithFailure(15); | |
277 ASSERT_EQ(-15, testCounter); | |
278 } | |
279 | |
280 TEST(MessageBroker2, TestPromiseDeleteTarget) | |
281 { | |
282 MessageBroker broker; | |
283 MyPromiseSource source(broker); | |
284 MyPromiseTarget* target = new MyPromiseTarget(broker); | |
285 | |
286 // create the promise | |
287 source.StartSomethingAsync() | |
288 .Then(new Callable<MyPromiseTarget, MyPromiseSource::MyPromiseMessage>(*target, &MyPromiseTarget::IncrementCounter)) | |
289 .Else(new Callable<MyPromiseTarget, MyPromiseSource::MyPromiseMessage>(*target, &MyPromiseTarget::DecrementCounter)); | |
290 | |
291 // delete the promise target | |
292 delete target; | |
293 | |
294 // trigger the promise, make sure it does not throw and does not call the callback | |
295 testCounter = 0; | |
296 source.CompleteSomethingAsyncWithSuccess(10); | |
297 ASSERT_EQ(0, testCounter); | |
298 | |
299 // test a failing promise | |
300 source.StartSomethingAsync() | |
301 .Then(new Callable<MyPromiseTarget, MyPromiseSource::MyPromiseMessage>(*target, &MyPromiseTarget::IncrementCounter)) | |
302 .Else(new Callable<MyPromiseTarget, MyPromiseSource::MyPromiseMessage>(*target, &MyPromiseTarget::DecrementCounter)); | |
303 | |
304 testCounter = 0; | |
305 source.CompleteSomethingAsyncWithFailure(15); | |
306 ASSERT_EQ(0, testCounter); | |
307 } | |
308 | |
309 #if __cplusplus >= 201103L | |
310 | |
311 #include <functional> | |
312 | |
313 namespace OrthancStone { | |
314 | |
315 template <typename TMessage> | |
316 class LambdaCallable : public MessageHandler<TMessage> | |
317 { | |
318 private: | |
319 | |
320 IObserver& observer_; | |
321 std::function<void (const TMessage&)> lambda_; | |
322 | |
323 public: | |
324 LambdaCallable(IObserver& observer, | |
325 std::function<void (const TMessage&)> lambdaFunction) : | |
326 observer_(observer), | |
327 lambda_(lambdaFunction) | |
328 { | |
329 } | |
330 | |
331 virtual void Apply(const IMessage& message) | |
332 { | |
333 lambda_(dynamic_cast<const TMessage&>(message)); | |
334 } | |
335 | |
336 virtual MessageType GetMessageType() const | |
337 { | |
338 return static_cast<MessageType>(TMessage::Type); | |
339 } | |
340 | |
341 virtual IObserver* GetObserver() const | |
342 { | |
343 return &observer_; | |
344 } | |
345 }; | |
346 | |
347 | |
348 } | |
349 | |
350 TEST(MessageBroker2, TestLambdaSimpleUseCase) | |
351 { | |
352 MessageBroker broker; | |
353 MyObservable observable(broker); | |
354 MyObserver* observer = new MyObserver(broker); | |
355 | |
356 // create a permanent connection between an observable and an observer | |
357 observable.RegisterObserverCallback(new LambdaCallable<MyObservable::MyCustomMessage>(*observer, [&](const MyObservable::MyCustomMessage& message) {testCounter += 2 * message.payload_;})); | |
358 | |
359 testCounter = 0; | |
360 observable.EmitMessage(MyObservable::MyCustomMessage(12)); | |
361 ASSERT_EQ(24, testCounter); | |
362 | |
363 // delete the observer and check that the callback is not called anymore | |
364 delete observer; | |
365 | |
366 // the connection is permanent; if we emit the same message again, the observer will be notified again | |
367 testCounter = 0; | |
368 observable.EmitMessage(MyObservable::MyCustomMessage(20)); | |
369 ASSERT_EQ(0, testCounter); | |
370 } | |
371 | |
372 namespace { | |
373 class MyObserverWithLambda : public IObserver { | |
374 private: | |
375 int multiplier_; // this is a private variable we want to access in a lambda | |
376 | |
377 public: | |
378 MyObserverWithLambda(MessageBroker& broker, int multiplier, MyObservable& observable) | |
379 : IObserver(broker), | |
380 multiplier_(multiplier) | |
381 { | |
382 // register a callable to a lambda that access private members | |
383 observable.RegisterObserverCallback(new LambdaCallable<MyObservable::MyCustomMessage>(*this, [this](const MyObservable::MyCustomMessage& message) { | |
384 testCounter += multiplier_ * message.payload_; | |
385 })); | |
386 | |
387 } | |
388 }; | |
389 } | |
390 | |
391 TEST(MessageBroker2, TestLambdaCaptureThisAndAccessPrivateMembers) | |
392 { | |
393 MessageBroker broker; | |
394 MyObservable observable(broker); | |
395 MyObserverWithLambda* observer = new MyObserverWithLambda(broker, 3, observable); | |
396 | |
397 testCounter = 0; | |
398 observable.EmitMessage(MyObservable::MyCustomMessage(12)); | |
399 ASSERT_EQ(36, testCounter); | |
400 | |
401 // delete the observer and check that the callback is not called anymore | |
402 delete observer; | |
403 | |
404 // the connection is permanent; if we emit the same message again, the observer will be notified again | |
405 testCounter = 0; | |
406 observable.EmitMessage(MyObservable::MyCustomMessage(20)); | |
407 ASSERT_EQ(0, testCounter); | |
408 } | |
409 | |
410 #endif // C++ 11 |