GenericSessionTest.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2005-2007 by Peter Dimov.
00004 
00005 This file is part of Calitko (http://www.calitko.org).
00006 
00007 Calitko is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 Calitko is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Calitko; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021 */
00022 
00023 #include "Qt.h"
00024 #include "../BadPacket.h"
00025 #include "generated/DataSerializerMock.h"
00026 #include "generated/DataQueueMock.h"
00027 #include "generated/GenericSessionDriver.h"
00028 #include "generated/SessionMock.h"
00029 #include "generated/SessionStatusMock.h"
00030 #include "generated/TransportMock.h"
00031 #include "Imports.cpp"
00032 
00033 namespace Protocols {
00034 namespace Generics {
00035 namespace Testing {
00036 
00037 class DataChecker
00038 {
00039     Data        data;
00040     Transport   &transport;
00041 
00042 public:
00043     DataChecker (const Data &d, Transport *t) : data (d), transport (*t) {}
00044 
00045     typedef bool (Function) (Data &, Transport *);
00046 
00047     bool check (Data &d, Transport *t)
00048     {
00049         if (t != &transport)
00050             return false;
00051         d = data;
00052         return true;
00053     }
00054 };
00055 
00057 
00061 class GenericSessionTest : public CppUnit::TestFixture
00062 {
00063     CPPUNIT_TEST_SUITE(GenericSessionTest);
00064     CPPUNIT_TEST (testOpenSessionStartsReading);
00065     CPPUNIT_TEST (testSentDataSerializedDirectly);
00066     CPPUNIT_TEST (testSentDataCannotBeSerializedMustBeQueued);
00067     CPPUNIT_TEST (testSentDataIsBufferedDirectly);
00068     CPPUNIT_TEST (testSentTwoDatasThatGetQueued);
00069     CPPUNIT_TEST (testWriteQueuedDataOnReadyWrite);
00070     CPPUNIT_TEST (testWriteTwoQueuedDatasOnReadyWrite);
00071     CPPUNIT_TEST (testWriteQueuedDataOnReadyWriteFails);
00072     CPPUNIT_TEST (testWriteTwoQueuedDatasOnReadyWriteSecondFails);
00073     CPPUNIT_TEST (testCannotReadPacketOnReadyRead);
00074     CPPUNIT_TEST (testReadTwoPacketsOnReadyRead);
00075     CPPUNIT_TEST (testCloseSessionDisconnectsTransportOnlyIfNothingToWrite);
00076     CPPUNIT_TEST (testCloseSessionDisconnectsTransportOnlyAfterQueueGetsEmpty);
00077     CPPUNIT_TEST (testAbortSessionAbortsTransportAndClosesSession);
00078     CPPUNIT_TEST (testCloseSessionFromSessionDataReceivedNotificationDisconnectDeferred);
00079     CPPUNIT_TEST (testAbortSessionFromSessionDataReceivedNotification);
00080     CPPUNIT_TEST_SUITE_END();
00081 
00082     auto_ptr <TransportMock>                transport;
00083     auto_ptr <DataSerializerMock>           serializer;
00084     auto_ptr <SessionStatusMock>            status;
00085     auto_ptr <DataQueueMock>                queue;
00086     auto_ptr <GenericSession>               sessionReal;
00087     auto_ptr <GenericSessionDriver>         session;
00088 
00089     const Data                              data1;
00090     const Data                              data2;
00091 
00092 public:
00093     GenericSessionTest()
00094      :  transport(), serializer(), status(), queue(), sessionReal(), session(),
00095         data1 (BadPacket ("header1", "payload1")),
00096         data2 (BadPacket ("header2", "payload2"))
00097     {
00098     }
00099 
00100     void setUp()
00101     {
00102         transport.reset (new TransportMock);
00103         serializer.reset (new DataSerializerMock);
00104         status.reset (new SessionStatusMock);
00105         queue.reset (new DataQueueMock);
00106         sessionReal.reset (new GenericSession (*transport,
00107                                                *serializer,
00108                                                *queue,
00109                                                *status));
00110         session.reset (new GenericSessionDriver (*sessionReal.get()));
00111     }
00112 
00113     void tearDown()
00114     {
00115         session.reset();
00116         sessionReal.reset();
00117         status.reset();
00118         queue.reset();
00119         serializer.reset();
00120         transport.reset();
00121     }
00122 
00124 
00131     void testOpenSessionStartsReading()
00132     {
00133         call (session->open())
00134             //.willCall (status->sessionOpened (*session))
00135             //.returns()
00136             .willCall (serializer->read (checker (DataChecker (data1, *transport))))
00137             .willReturn (false)
00138         .returns();
00139     }
00140 
00141     void stateSessionOpened()
00142     {
00143         testOpenSessionStartsReading();
00144     }
00145 
00147     void refSentDataSerializedDirectly (const Data &data)
00148     {
00149         call (session->send (data))
00150             .willCall (status->sessionSendingData (*session, data))
00151             .returns()
00152             .willCall (queue->isEmpty())
00153             .willReturn (true)
00154             .willCall (serializer->write (data, *transport))
00155             .willReturn (true)
00156         .returns();
00157     }
00158 
00159     void testSentDataSerializedDirectly()
00160     {
00161         stateSessionOpened();
00162         refSentDataSerializedDirectly (data1);
00163     }
00164 
00169     void refSentDataCannotBeSerializedMustBeQueued (const Data &data)
00170     {
00171         call (session->send (data))
00172             .willCall (status->sessionSendingData (*session, data))
00173             .returns()
00174             .willCall (queue->isEmpty())
00175             .willReturn (true)
00176             .willCall (serializer->write (data, *transport))
00177             .willReturn (false)
00178             .willCall (queue->enqueue (data))
00179             .returns()
00180         .returns();
00181     }
00182 
00183     void testSentDataCannotBeSerializedMustBeQueued()
00184     {
00185         stateSessionOpened();
00186         refSentDataCannotBeSerializedMustBeQueued (data1);
00187     }
00188 
00190 
00195     void refSentDataIsBufferedDirectly (const Data &data)
00196     {
00197         call (session->send (data))
00198             .willCall (status->sessionSendingData (*session, data))
00199             .returns()
00200             .willCall (queue->isEmpty())
00201             .willReturn (false)
00202             .willCall (queue->enqueue (data))
00203             .returns()
00204         .returns();
00205     }
00206 
00207     void testSentDataIsBufferedDirectly()
00208     {
00209         stateSessionOpened();
00210         refSentDataIsBufferedDirectly (data1);
00211     }
00212 
00213     void testSentTwoDatasThatGetQueued()
00214     {
00215         stateSessionOpened();
00216         refSentDataIsBufferedDirectly (data1);
00217         refSentDataIsBufferedDirectly (data2);
00218     }
00219 
00220     void refWriteQueuedDatasOnReadyWrite (const QList <Data> &datas)
00221     {
00222         CallDriver <BoundFunction <GenericSession, void (Transport*)> > foo =
00223             call (session->transportReadyWrite (*transport));
00224 
00225         bool wroteAll = true;
00226         foreach (const Data &data, datas) {
00227             foo
00228                 .willCall (queue->isEmpty())
00229                 .willReturn (false)
00230                 .willCall (queue->next())
00231                 .willReturn (data);
00232             if (data != Data()) {
00233             foo .willCall (serializer->write (data, *transport))
00234                 .willReturn (true)
00235                 .willCall (queue->dequeue())
00236                 .returns();
00237             } else {
00238             foo .willCall (serializer->write (data, *transport))
00239                 .willReturn (false);
00240                 wroteAll = false;
00241                 break; // Don't write any more.
00242             }
00243         }
00244         if (wroteAll) {
00245             // Stop writing when the queue gets empty.
00246             foo
00247                 .willCall (queue->isEmpty())
00248                 .willReturn (true);
00249         }
00250         foo.returns();
00251     }
00252 
00253     void testWriteQueuedDataOnReadyWrite()
00254     {
00255         stateSessionOpened();
00256         refWriteQueuedDatasOnReadyWrite (QList <Data>() += data1);
00257     }
00258 
00259     void testWriteTwoQueuedDatasOnReadyWrite()
00260     {
00261         stateSessionOpened();
00262         refWriteQueuedDatasOnReadyWrite ((QList <Data>() += data1) += data2);
00263     }
00264 
00265     void testWriteQueuedDataOnReadyWriteFails()
00266     {
00267         stateSessionOpened();
00268         refWriteQueuedDatasOnReadyWrite (QList <Data>() += Data());
00269     }
00270 
00271     void testWriteTwoQueuedDatasOnReadyWriteSecondFails()
00272     {
00273         stateSessionOpened();
00274         refWriteQueuedDatasOnReadyWrite ((QList <Data>() += data1) += Data());
00275     }
00276 
00277     void refReadDatasOnReadyRead (const QList <Data> &datas)
00278     {
00279         CallDriver <BoundFunction <GenericSession, void (Transport*)> > foo =
00280             call (session->transportReadyRead (*transport));
00281 
00282         foreach (const Data &data, datas) {
00283             foo
00284                 .willCall (serializer->read (
00285                                 checker (DataChecker (data, *transport))))
00286                 .willReturn (true)
00287                 .willCall (status->sessionReceivedData (*session, data))
00288                 .returns();
00289         }
00290         // Cannot ready any more Data objects:
00291         Data data;
00292         foo
00293             .willCall (serializer->read (
00294                                 checker (DataChecker (data, *transport))))
00295             .willReturn (false)
00296         .returns();
00297     }
00298 
00299     void testCannotReadPacketOnReadyRead()
00300     {
00301         stateSessionOpened();
00302         refReadDatasOnReadyRead (QList <Data>());
00303     }
00304 
00305     void testReadTwoPacketsOnReadyRead()
00306     {
00307         stateSessionOpened();
00308         refReadDatasOnReadyRead ((QList <Data>() += data1) += data2);
00309     }
00310 
00312     void refCloseSessionDisconnectsTransportImmediately()
00313     {
00314         call (session->close())
00315             .willCall (queue->isEmpty())
00316             .willReturn (true)
00317             .willCall (status->sessionClosing (*session))
00318             .returns()
00319             .willCall (transport->disconnectFromNode())
00320             .returns()
00321         .returns();
00322     }
00323 
00324     void refCloseSessionDoesNotDisconnectTransportWhenQueueIsNotEmpty()
00325     {
00326         call (session->close())
00327             .willCall (queue->isEmpty())
00328             .willReturn (false)
00329             .willCall (status->sessionClosing (*session))
00330             .returns()
00331         .returns();
00332     }
00333 
00334     void refTransportDisconnectedClosesTheSessionCompletely()
00335     {
00336         call (session->transportDisconnected (*transport))
00337             .willCall (status->sessionClosed (*session))
00338             .returns()
00339         .returns();
00340     }
00341 
00342     void refTransportReadyWriteDisconnectsTransportWhenEmptyQueueAndClosing()
00343     {
00344         call (session->transportReadyWrite (*transport))
00345             // take data1 from queue:
00346             .willCall (queue->isEmpty())
00347             .willReturn (true)
00348             // connection was closing, buffer is now empty, disconnect:
00349             .willCall (transport->disconnectFromNode())
00350             .returns()
00351         .returns();
00352     }
00353 
00355     void testCloseSessionDisconnectsTransportOnlyIfNothingToWrite()
00356     {
00357         stateSessionOpened();
00358         refCloseSessionDisconnectsTransportImmediately();
00359         refTransportDisconnectedClosesTheSessionCompletely();
00360     }
00361 
00363     void testCloseSessionDisconnectsTransportOnlyAfterQueueGetsEmpty()
00364     {
00365         stateSessionOpened();
00366         refCloseSessionDoesNotDisconnectTransportWhenQueueIsNotEmpty();
00367         refTransportReadyWriteDisconnectsTransportWhenEmptyQueueAndClosing();
00368         refTransportDisconnectedClosesTheSessionCompletely();
00369     }
00370 
00371     void testAbortSessionAbortsTransportAndClosesSession()
00372     {
00373         call (session->abort())
00374             .willCall (status->sessionClosing (*session))
00375             //.willCall (queue.clear())
00376             //.returns()
00377             .returns()
00378             .willCall (transport->abort())
00379                 .willCall (session->transportDisconnected (*transport))
00380                     .willCall (status->sessionClosed (*session))
00381                     .returns()
00382                 .returns()
00383             .returns()
00384         .returns();
00385     }
00386 
00388 
00393     void testCloseSessionFromSessionDataReceivedNotificationDisconnectDeferred()
00394     {
00395         stateSessionOpened();
00396 
00397         call (session->transportReadyRead (*transport))
00398             .willCall (serializer->read (
00399                             checker (DataChecker (data1, *transport))))
00400             .willReturn (true)
00401             .willCall (status->sessionReceivedData (*session, data1))
00402                 .willCall (session->close())
00403                     .willCall (status->sessionClosing (*session))
00404                     .returns()
00405                     .willCall (queue->isEmpty())
00406                     .willReturn (false)
00407                 .returns()
00408             .returns()
00409             .willCall (serializer->read (
00410                             checker (DataChecker (Data(), *transport))))
00411             .willReturn (false)
00412         .returns();
00413     }
00414 
00415     void testAbortSessionFromSessionDataReceivedNotification()
00416     {
00417         stateSessionOpened();
00418 
00419         call (session->transportReadyRead (*transport))
00420             .willCall (serializer->read (
00421                             checker (DataChecker (data1, *transport))))
00422             .willReturn (true)
00423             .willCall (status->sessionReceivedData (*session, data1))
00424                 .willCall (session->abort())
00425                     .willCall (status->sessionClosing (*session))
00426                     //.willCall (queue.clear())
00427                     //.returns()
00428                     .returns()
00429                     .willCall (transport->abort())
00430                         .willCall (session->transportDisconnected (*transport))
00431                             .willCall (status->sessionClosed (*session))
00432                             .returns()
00433                         .returns()
00434                     .returns()
00435                 .returns()
00436             .returns()
00437         .returns();
00438     }
00439 };
00440 
00441 CPPUNIT_TEST_SUITE_REGISTRATION (GenericSessionTest);
00442 
00443 } // Testing;
00444 } // Generics;
00445 } // Protocols;