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