PPI: optimized internal connector packet handling (queuing only if necessary, pass...
[senf.git] / senf / PPI / Connectors.test.cc
1 // $Id$
2 //
3 // Copyright (C) 2007
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 //
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at 
9 // http://senf.berlios.de/license.html
10 //
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on, 
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
14 //
15 // Software distributed under the License is distributed on an "AS IS" basis, 
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
17 // for the specific language governing rights and limitations under the License.
18 //
19 // The Original Code is Fraunhofer FOKUS code.
20 //
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V. 
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
24 //
25 // Contributor(s):
26 //   Stefan Bund <g0dil@berlios.de>
27
28 /** \file
29     \brief Connectors unit tests */
30
31 //#include "Connectors.test.hh"
32 //#include "Connectors.test.ih"
33
34 // Custom includes
35 #include "Connectors.hh"
36 #include "DebugModules.hh"
37 #include "Setup.hh"
38
39 #include <senf/Utils/auto_unit_test.hh>
40 #include <boost/test/test_tools.hpp>
41
42 #define prefix_
43 //-/////////////////////////////////////////////////////////////////////////////////////////////////
44
45 namespace ppi = senf::ppi;
46 namespace debug = ppi::module::debug;
47
48 // For each type of connector we use the corresponding debug module. Additionally, we always need
49 // the corresponding connected module since otherwise the connectors cannot be connected anywhere
50 // and will be unusable.
51
52 SENF_AUTO_UNIT_TEST(connector)
53 {
54     // It doesn't matter, which type of connectors we use here since they are all based on
55     // Connector.
56
57     debug::ActiveSource source;
58     debug::PassiveSink target;
59
60     ppi::connect(source.output,target.input);
61     ppi::init();
62
63     BOOST_CHECK_EQUAL( & source.output.module(), & source );
64     BOOST_CHECK_EQUAL( & target.input.module(), & target );
65     BOOST_CHECK_EQUAL( & source.output.peer(), & target.input );
66     BOOST_CHECK_EQUAL( & target.input.peer(), & source.output );
67 }
68
69 SENF_AUTO_UNIT_TEST(passiveConnector)
70 {
71     debug::ActiveSource source;
72     debug::PassiveSink target;
73
74     ppi::connect(source.output,target.input);
75     ppi::init();
76
77     // onRequest is implicitly tested within the PassiveSink implementation which is tested
78     // in DebugModules.test.cc
79
80     target.input.throttle();
81     BOOST_CHECK( target.input.throttled() );
82     BOOST_CHECK( target.input.nativeThrottled() );
83
84     target.input.unthrottle();
85     BOOST_CHECK( ! target.input.throttled() );
86     BOOST_CHECK( ! target.input.nativeThrottled() );
87
88     BOOST_CHECK_EQUAL( & target.input.peer(), & source.output );
89 }
90
91 namespace {
92
93     bool called = false;
94
95     void handler() { called = true; }
96 }
97
98 SENF_AUTO_UNIT_TEST(activeConnector)
99 {
100     debug::ActiveSource source;
101     debug::PassiveSink target;
102
103     ppi::connect(source.output,target.input);
104     ppi::init();
105
106     source.output.onThrottle(handler);
107     BOOST_CHECK( ! called );
108     target.input.throttle();
109     BOOST_CHECK( called );
110     called = false;
111     target.input.unthrottle();
112     BOOST_CHECK( ! called );
113     source.output.onThrottle();
114     source.output.onUnthrottle(handler);
115     BOOST_CHECK( ! called );
116     target.input.throttle();
117     BOOST_CHECK( ! called );
118     target.input.unthrottle();
119     BOOST_CHECK( called );
120     source.output.onUnthrottle();
121     called = false;
122     BOOST_CHECK( ! called );
123     target.input.throttle();
124     target.input.unthrottle();
125     BOOST_CHECK( ! called );
126
127     BOOST_CHECK_EQUAL( & source.output.peer(), & target.input );
128 }
129
130 SENF_AUTO_UNIT_TEST(inputConnector)
131 {
132     debug::ActiveSource source;
133     debug::PassiveSink target;
134
135     ppi::connect(source.output,target.input);
136     ppi::init();
137
138     // operator() is implicitly tested within the Active/PassiveSink implementation which is
139     // tested in DebugModules.test.cc
140
141     // peek() is implicitly tested within the Active/PassiveSink implementation
142
143     BOOST_CHECK_EQUAL ( & target.input.peer(), & source.output );
144
145     BOOST_CHECK_EQUAL( target.input.queueSize(), 0u );
146     BOOST_CHECK( target.input.empty() );
147 }
148
149 SENF_AUTO_UNIT_TEST(outputConnector)
150 {
151     debug::ActiveSource source;
152     debug::PassiveSink target;
153
154     ppi::connect(source.output,target.input);
155     ppi::init();
156
157     // operator() is implicitly tested within the Active/PassiveSource implementation which is
158     // tested in DebugModules.test.cc
159
160     BOOST_CHECK_EQUAL( & source.output.peer(), & target.input );
161 }
162
163 namespace {
164
165     class PassiveInputTest
166         : public ppi::module::Module
167     {
168         SENF_PPI_MODULE(PassiveInputTest);
169
170     public:
171         ppi::connector::PassiveInput<> input;
172
173         PassiveInputTest() : counter() {
174             noroute(input);
175             input.onRequest(&PassiveInputTest::request);
176         }
177
178         void request() {
179             ++ counter;
180         }
181
182         unsigned counter;
183     };
184 }
185
186 SENF_AUTO_UNIT_TEST(passiveInput)
187 {
188     debug::ActiveSource source;
189     PassiveInputTest target;
190
191     ppi::connect(source,target);
192     ppi::init();
193
194     BOOST_CHECK_EQUAL( & target.input.peer(), & source.output );
195
196     target.input.throttle();
197     senf::Packet p (senf::DataPacket::create());
198     source.submit(p);
199
200     BOOST_CHECK_EQUAL( target.counter, 0u );
201     BOOST_CHECK( target.input );
202     BOOST_CHECK_EQUAL( target.input.queueSize(), 1u );
203     target.input.unthrottle();
204     BOOST_CHECK( target.input );
205     BOOST_CHECK_EQUAL( target.counter, 1u );
206
207     BOOST_CHECK( target.input() == p );
208     BOOST_CHECK( ! target.input );
209
210     source.submit(p);
211
212     BOOST_CHECK_EQUAL( target.counter, 2u );
213     BOOST_CHECK( target.input.throttled() );
214     BOOST_CHECK( target.input() == p );
215     BOOST_CHECK( ! target.input.throttled() );
216
217     target.input.qdisc(ppi::ThresholdQueueing(2,0));
218
219     source.submit(p);
220     BOOST_CHECK ( ! target.input.throttled() );
221     source.submit(p);
222     BOOST_CHECK( target.input.throttled() );
223     target.input();
224     BOOST_CHECK( target.input.throttled() );
225     target.input();
226     BOOST_CHECK( ! target.input.throttled() );
227 }
228
229 SENF_AUTO_UNIT_TEST(passiveOutput)
230 {
231     debug::PassiveSource source;
232     debug::ActiveSink target;
233
234     ppi::connect(source,target);
235     ppi::init();
236
237     senf::Packet p (senf::DataPacket::create());
238     source.submit(p);
239
240     BOOST_CHECK_EQUAL( & source.output.peer(), & target.input );
241
242     BOOST_CHECK( source.output );
243
244     source.submit(p);
245     BOOST_CHECK( target.request() == p );
246
247     // connect() is tested indirectly via ppi::connect
248 }
249
250 SENF_AUTO_UNIT_TEST(activeInput)
251 {
252     debug::PassiveSource source;
253     debug::ActiveSink target;
254
255     ppi::connect(source,target);
256     ppi::init();
257
258     BOOST_CHECK_EQUAL( & target.input.peer(), & source.output );
259
260     BOOST_CHECK ( ! target.input );
261
262     senf::Packet p (senf::DataPacket::create());
263     source.submit(p);
264
265     BOOST_CHECK( target.input );
266     BOOST_CHECK( target.request() == p );
267
268     source.submit(p);
269     target.input.request();
270     BOOST_CHECK_EQUAL( target.input.queueSize(), 1u );
271     BOOST_CHECK( target.input );
272     BOOST_CHECK( target.request() == p );
273 }
274
275 SENF_AUTO_UNIT_TEST(activeOutput)
276 {
277     debug::ActiveSource source;
278     debug::PassiveSink target;
279
280     ppi::connect(source,target);
281     ppi::init();
282
283     BOOST_CHECK_EQUAL( & source.output.peer(), & target.input );
284     BOOST_CHECK( source.output );
285     target.input.throttle();
286     BOOST_CHECK( ! source.output );
287
288     // connect() is tested indirectly via ppi::connect
289 }
290
291 namespace {
292
293     template <class PacketType = senf::DataPacket>
294     class TypedPassiveInput
295         : public ppi::module::Module
296     {
297         SENF_PPI_MODULE(TypedPassiveInput);
298
299     public:
300         ppi::connector::PassiveInput<PacketType> input;
301
302         TypedPassiveInput() {
303             noroute(input);
304             input.onRequest(&TypedPassiveInput::request);
305         }
306
307         void request() {
308             senf::IGNORE( input() );
309             senf::IGNORE( input.read() );
310         }
311     };
312
313     template <class PacketType = senf::DataPacket>
314     class TypedActiveInput
315         : public ppi::module::Module
316     {
317         SENF_PPI_MODULE(TypedActiveInput);
318
319     public:
320         ppi::connector::ActiveInput<PacketType> input;
321
322         TypedActiveInput() {
323             noroute(input);
324         }
325     };
326
327     template <class PacketType = senf::DataPacket>
328     class TypedPassiveOutput
329         : public ppi::module::Module
330     {
331         SENF_PPI_MODULE(TypedPassiveOutput);
332
333     public:
334         ppi::connector::PassiveOutput<PacketType> output;
335
336         TypedPassiveOutput() {
337             noroute(output);
338             output.onRequest(&TypedPassiveOutput::request);
339         }
340
341         void request() {
342             senf::DataPacket pkg (senf::DataPacket::create());
343             output(pkg);
344             output.write(pkg);
345         }
346     };
347
348     template <class PacketType = senf::DataPacket>
349     class TypedActiveOutput
350         : public ppi::module::Module
351     {
352         SENF_PPI_MODULE(TypedActiveOutput);
353
354     public:
355         ppi::connector::ActiveOutput<PacketType> output;
356
357         TypedActiveOutput() {
358             noroute(output);
359         }
360     };
361
362     struct MyPacketType : public senf::PacketTypeBase
363     {};
364
365     typedef senf::ConcretePacket<MyPacketType> MyPacket;
366
367 }
368
369 SENF_AUTO_UNIT_TEST(typedInput)
370 {
371     debug::ActiveSource source;
372     TypedPassiveInput<> target;
373
374     ppi::connect(source,target);
375     ppi::init();
376
377     senf::Packet p (senf::DataPacket::create());
378     source.submit(p);
379
380     BOOST_CHECK( true );
381 }
382
383 SENF_AUTO_UNIT_TEST(tyepdOutput)
384 {
385     TypedPassiveOutput<> source;
386     debug::ActiveSink target;
387
388     ppi::connect(source,target);
389     ppi::init();
390
391     senf::IGNORE( target.request() );
392
393     BOOST_CHECK( true );
394 }
395
396 SENF_AUTO_UNIT_TEST(connectorTest)
397 {
398     {
399         TypedPassiveInput<> input;
400         TypedActiveOutput<MyPacket> output;
401         BOOST_CHECK_THROW( ppi::connect(output, input),
402                            ppi::connector::IncompatibleConnectorsException );
403     }
404     {
405         TypedPassiveInput<MyPacket> input;
406         TypedActiveOutput<> output;
407         BOOST_CHECK_THROW( ppi::connect(output, input),
408                            ppi::connector::IncompatibleConnectorsException );
409     }
410     {
411         TypedPassiveInput<> input;
412         TypedActiveOutput<> output;
413         SENF_CHECK_NO_THROW( ppi::connect(output, input) );
414     }
415     {
416         TypedPassiveInput<> input;
417         debug::ActiveSource output;
418         SENF_CHECK_NO_THROW( ppi::connect(output, input) );
419     }
420     {
421         debug::ActiveSink input;
422         TypedPassiveOutput<> output;
423         SENF_CHECK_NO_THROW( ppi::connect(output, input) );
424     }
425     {
426         debug::ActiveSink input;
427         debug::PassiveSource output;
428         SENF_CHECK_NO_THROW( ppi::connect(output, input) );
429     }
430 }
431
432 SENF_AUTO_UNIT_TEST(delayedConnect)
433 {
434     {
435         debug::PassiveSource source;
436         debug::ActiveSink target;
437
438         ppi::init();
439
440         BOOST_CHECK( ! target.input );
441         BOOST_CHECK( ! target.request() );
442
443         ppi::connect(source, target);
444         ppi::init();
445
446         BOOST_CHECK( ! target.input );
447
448         senf::Packet p (senf::DataPacket::create());
449         source.submit(p);
450         BOOST_CHECK( target.request() == p );
451     }
452
453     {
454         debug::PassiveSource source;
455         debug::ActiveSink target;
456
457         ppi::init();
458
459         senf::Packet p (senf::DataPacket::create());
460         source.submit(p);
461
462         BOOST_CHECK( ! target.input );
463         BOOST_CHECK( ! target.request() );
464
465         ppi::connect(source, target);
466         ppi::init();
467
468         BOOST_CHECK( target.input );
469         BOOST_CHECK( target.request() == p );
470     }
471
472     {
473         debug::ActiveSource source;
474         debug::PassiveSink target;
475
476         ppi::init();
477
478         BOOST_CHECK( ! source.output );
479         SENF_CHECK_NO_THROW( source.output(senf::DataPacket::create()) );
480
481         ppi::connect(source, target);
482         ppi::init();
483
484         BOOST_CHECK( source.output );
485
486         senf::Packet p (senf::DataPacket::create());
487         source.submit(p);
488
489         BOOST_CHECK( target.front() == p );
490         BOOST_CHECK_EQUAL( target.size(), 1u );
491     }
492
493     {
494         debug::ActiveSource source;
495         debug::PassiveSink target;
496
497         ppi::init();
498
499         BOOST_CHECK( ! source.output );
500         SENF_CHECK_NO_THROW( source.output(senf::DataPacket::create()) );
501         target.throttle();
502
503         ppi::connect(source, target);
504         ppi::init();
505
506         BOOST_CHECK( ! source.output );
507         target.unthrottle();
508         BOOST_CHECK( source.output );
509     }
510 }
511
512 SENF_AUTO_UNIT_TEST(disconnect)
513 {
514     {
515         debug::PassiveSource source;
516         debug::ActiveSink target;
517
518         ppi::connect(source, target);
519         ppi::init();
520
521         BOOST_CHECK( ! target.input );
522
523         senf::Packet p (senf::DataPacket::create());
524         source.submit(p);
525
526         BOOST_CHECK( target.input );
527
528         target.input.disconnect();
529         ppi::init();
530
531         BOOST_CHECK( ! target.input );
532     }
533     {
534         debug::ActiveSource source;
535         debug::PassiveSink target;
536
537         ppi::connect(source, target);
538         ppi::init();
539
540         BOOST_CHECK( source.output );
541
542         source.output.disconnect();
543         ppi::init();
544
545         BOOST_CHECK( ! source.output );
546     }
547 }
548
549 //-/////////////////////////////////////////////////////////////////////////////////////////////////
550 #undef prefix_
551
552 \f
553 // Local Variables:
554 // mode: c++
555 // fill-column: 100
556 // comment-column: 40
557 // c-file-style: "senf"
558 // indent-tabs-mode: nil
559 // ispell-local-dictionary: "american"
560 // compile-command: "scons -u test"
561 // End: