SingleTrackerRequestSessionTest.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2006-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 "../SingleTrackerRequestSession.h"
00025 #include "../TrackerResponseParser.h"
00026 #include "generated/HttpRequestSessionMock.h"
00027 #include "generated/SingleTrackerRequestSessionDriver.h"
00028 #include "generated/TrackerRequestSessionMock.h"
00029 #include "Imports.cpp"
00030 
00031 namespace Protocols {
00032 namespace BitTorrent {
00033 namespace Trackers {
00034 namespace Testing {
00035 
00037 
00039 class SingleTrackerRequestSessionTest : public CppUnit::TestFixture
00040 {
00041     CPPUNIT_TEST_SUITE (SingleTrackerRequestSessionTest);
00042     CPPUNIT_TEST (testOpenClosedSession);
00043     CPPUNIT_TEST (testHttpRequestSessionGetsEstablished);
00044     CPPUNIT_TEST (testSendRequest);
00045     CPPUNIT_TEST (testRecieveResponseHttp200AndValidMessageBody);
00046     CPPUNIT_TEST (testRecieveResponseHttp206AndValidMessageBody);
00047     CPPUNIT_TEST (testHttpErrorHttp100);
00048     CPPUNIT_TEST (testHttpErrorHttp101);
00049     CPPUNIT_TEST (testHttpErrorHttp300);
00050     CPPUNIT_TEST (testHttpErrorHttp307);
00051     CPPUNIT_TEST (testHttpErrorHttp400);
00052     CPPUNIT_TEST (testHttpErrorHttp417);
00053     CPPUNIT_TEST (testHttpErrorHttp500);
00054     CPPUNIT_TEST (testHttpErrorHttp505);
00055     CPPUNIT_TEST (testTrackerErrorHttp200AndInvalidResponseBody);
00056     CPPUNIT_TEST (testTrackerErrorHttp200AndFailureResponseBody);
00057     CPPUNIT_TEST (testCloseClosedSession);
00058     CPPUNIT_TEST (testCloseSessionCompletelyAfterItsEstablished);
00059     CPPUNIT_TEST (testCloseSessionCompletelyWhileWaitingForResponse);
00060     CPPUNIT_TEST (testCloseSessionCompletelyAfterHandledResponseHeader);
00061     CPPUNIT_TEST (testCloseSessionWhileClosing);
00062     CPPUNIT_TEST (testAbortClosedSession);
00063     CPPUNIT_TEST (testAbortSessionAfterItsEstablished);
00064     CPPUNIT_TEST (testAbortSessionWhileWaitingForResponse);
00065     CPPUNIT_TEST (testAbortSessionAfterHandledResponseHeader);
00066     CPPUNIT_TEST (testAbortSessionWhileClosing);
00067     CPPUNIT_TEST (testHttpRequestSessionErrorWhileEstablishingSession);
00068     CPPUNIT_TEST (testHttpRequestSessionErrorAfterSessionIsEstablished);
00069     CPPUNIT_TEST (testHttpRequestSessionErrorWhileWaitingForResponse);
00070     CPPUNIT_TEST (testHttpRequestSessionErrorAfterHandledResponseHeader);
00071     CPPUNIT_TEST (testHttpRequestSessionErrorWhileClosing);
00072     CPPUNIT_TEST_SUITE_END();
00073 
00074     auto_ptr <HttpRequestSessionMock>                   httpRequestSession;
00075     auto_ptr <TrackerRequestSessionStatusMock>          sessionStatus;
00076     auto_ptr <SingleTrackerRequestSession>              sessionReal;
00077     auto_ptr <SingleTrackerRequestSessionDriver>        session;
00078 
00079     const Uri                                   ValidAnnounceUrl;
00080     const TrackerRequest                        ValidTrackerRequest;
00081     const Uri                                   ValidTrackerRequestUrl;
00082     const QByteArray                            ValidResponseBody;
00083     const QByteArray                            InvalidResponseBody;
00084     const QByteArray                            FailureResponseBody;
00085     const TrackerResponse                       ValidTrackerResponse;
00086 
00088 
00092     TrackerResponse createValidTrackerResponse() const
00093     {
00094         TrackerResponse response;
00095         TrackerResponseParser::parseAndLoadTrackerResponse (ValidResponseBody,
00096             response);
00097         return response;
00098     }
00099 
00100 public:
00101     SingleTrackerRequestSessionTest();
00102 
00103     void setUp()
00104     {
00105         httpRequestSession.reset (new HttpRequestSessionMock());
00106         sessionStatus.reset (new TrackerRequestSessionStatusMock());
00107         sessionReal.reset (new SingleTrackerRequestSession (
00108             &httpRequestSession->imp, ValidAnnounceUrl, &sessionStatus->imp));
00109         session.reset (new SingleTrackerRequestSessionDriver (
00110             *sessionReal.get()));
00111     }
00112 
00113     void tearDown()
00114     {
00115         session.reset();
00116         sessionReal.reset();
00117         sessionStatus.reset();
00118         httpRequestSession.reset();
00119     }
00120 
00122     void testOpenClosedSession()
00123     {
00124         call (session->open())
00125             .willCall (httpRequestSession->open (ValidAnnounceUrl))
00126             .returns()
00127         .returns();
00128     }
00129 
00134     void stateSessionIsOpened()
00135     {
00136         testOpenClosedSession();
00137     }
00138 
00140     void testHttpRequestSessionGetsEstablished()
00141     {
00142         call (session->httpRequestSessionEstablished())
00143             .willCall (sessionStatus->trackerRequestSessionEstablished (
00144                 sessionReal.get()))
00145             .returns()
00146         .returns();
00147     }
00148 
00153     void stateSessionIsEstablished()
00154     {
00155         testHttpRequestSessionGetsEstablished();
00156     }
00157 
00162     void testSendRequest()
00163     {
00164         stateSessionIsEstablished();
00165 
00166         call (session->sendRequest (ValidTrackerRequest))
00167             .willCall (httpRequestSession->get (ValidTrackerRequestUrl))
00168             .returns()
00169         .returns();
00170     }
00171 
00176     void stateWaitingForResponse()
00177     {
00178         testSendRequest();
00179     }
00180 
00182 
00185     void refHandleResponseHeaderSuccessfully (const ResponseHeader &responseHeader)
00186     {
00187         call (session->httpRequestSessionResponseHeaderRecieved (responseHeader))
00188         .returns();
00189     }
00190 
00192 
00198     void scenarioRecieveResponse (const ResponseHeader &responseHeader,
00199                                   const QByteArray &responseBody,
00200                                   const TrackerResponse &trackerResponse)
00201     {
00202         stateWaitingForResponse();
00203 
00204         refHandleResponseHeaderSuccessfully (responseHeader);
00205 
00206         call (session->httpRequestSessionResponseBodyRecieved (responseBody))
00207             .willCall (sessionStatus->trackerRequestSessionResponseRecieved (
00208                 sessionReal.get(), trackerResponse))
00209             .returns()
00210         .returns();
00211     }
00212 
00214     void testRecieveResponseHttp200AndValidMessageBody()
00215     {
00216         scenarioRecieveResponse (ResponseHeader ("HTTP/1.1 200 OK\r\n\r\n"),
00217             ValidResponseBody, ValidTrackerResponse);
00218     }
00219 
00221     void testRecieveResponseHttp206AndValidMessageBody()
00222     {
00223         scenarioRecieveResponse (ResponseHeader ("HTTP/1.1 206 Partial Content\r\n\r\n"),
00224             ValidResponseBody, ValidTrackerResponse);
00225     }
00226 
00228 
00233     void scenarioHttpError (const ResponseHeader &responseHeader,
00234                             const QString &httpErrorMessage)
00235     {
00236         stateWaitingForResponse();
00237 
00238         call (session->httpRequestSessionResponseHeaderRecieved (responseHeader))
00239             .willCall (sessionStatus->trackerRequestSessionError (
00240                 sessionReal.get(), httpErrorMessage))
00241             .returns()
00242         .returns();
00243     }
00244 
00246     void testHttpErrorHttp100()
00247     {
00248         scenarioHttpError (ResponseHeader ("HTTP/1.1 100 Continue\r\n\r\n"),
00249             QString ("HTTP error: 100 Continue"));
00250     }
00251 
00253     void testHttpErrorHttp101()
00254     {
00255         scenarioHttpError (ResponseHeader ("HTTP/1.1 101 Switching Protocols\r\n\r\n"),
00256             QString ("HTTP error: 101 Switching Protocols"));
00257     }
00258 
00260     void testHttpErrorHttp300()
00261     {
00262         scenarioHttpError (ResponseHeader ("HTTP/1.1 300 Multiple Choices\r\n\r\n"),
00263             QString ("HTTP error: 300 Multiple Choices"));
00264     }
00265 
00267     void testHttpErrorHttp307()
00268     {
00269         scenarioHttpError (ResponseHeader ("HTTP/1.1 307 Temporary Redirect\r\n\r\n"),
00270             QString ("HTTP error: 307 Temporary Redirect"));
00271     }
00272 
00274     void testHttpErrorHttp400()
00275     {
00276         scenarioHttpError (ResponseHeader ("HTTP/1.1 400 Bad Request\r\n\r\n"),
00277             QString ("HTTP error: 400 Bad Request"));
00278     }
00279 
00281     void testHttpErrorHttp417()
00282     {
00283         scenarioHttpError (ResponseHeader ("HTTP/1.1 417 Expectation Failed\r\n\r\n"),
00284             QString ("HTTP error: 417 Expectation Failed"));
00285     }
00286 
00288     void testHttpErrorHttp500()
00289     {
00290         scenarioHttpError (ResponseHeader ("HTTP/1.1 500 Internal Server Error\r\n\r\n"),
00291             QString ("HTTP error: 500 Internal Server Error"));
00292     }
00293 
00295     void testHttpErrorHttp505()
00296     {
00297         scenarioHttpError (ResponseHeader ("HTTP/1.1 505 HTTP Version Not Supported\r\n\r\n"),
00298             QString ("HTTP error: 505 HTTP Version Not Supported"));
00299     }
00300 
00302 
00308     void scenarioTrackerError (const ResponseHeader &responseHeader,
00309                                const QByteArray &responseBody,
00310                                const QString &trackerErrorMessage)
00311     {
00312         stateWaitingForResponse();
00313 
00314         refHandleResponseHeaderSuccessfully (responseHeader);
00315 
00316         call (session->httpRequestSessionResponseBodyRecieved (responseBody))
00317             .willCall (sessionStatus->trackerRequestSessionError (
00318                 sessionReal.get(), trackerErrorMessage))
00319             .returns()
00320         .returns();
00321     }
00322 
00324     void testTrackerErrorHttp200AndInvalidResponseBody()
00325     {
00326         scenarioTrackerError (ResponseHeader ("HTTP/1.1 200 OK\r\n\r\n"),
00327             InvalidResponseBody, QString ("Tracker error: Tracker response could not be parsed"));
00328     }
00329 
00331     void testTrackerErrorHttp200AndFailureResponseBody()
00332     {
00333         scenarioTrackerError (ResponseHeader ("HTTP/1.1 200 OK\r\n\r\n"),
00334             FailureResponseBody, QString ("Tracker error: Unknown info_hash"));
00335     }
00336 
00341     void stateResponseHeaderHandledSuccessfully()
00342     {
00343         stateWaitingForResponse();
00344 
00345         refHandleResponseHeaderSuccessfully (
00346             ResponseHeader ("HTTP/1.1 200 OK\r\n\r\n"));
00347     }
00348 
00350     void refCloseSessionAfterHttpRequestSessionIsClosed()
00351     {
00352         call (session->httpRequestSessionClosed())
00353             .willCall (sessionStatus->trackerRequestSessionClosed (
00354                 sessionReal.get()))
00355             .returns()
00356         .returns();
00357     }
00358 
00360     void refCloseEstablishedSession()
00361     {
00362         call (session->close())
00363             .willCall (sessionStatus->trackerRequestSessionClosing (
00364                 sessionReal.get()))
00365             .returns()
00366             .willCall (httpRequestSession->close())
00367             .returns()
00368         .returns();
00369     }
00370 
00372     void refCloseEstablishedSessionCompletely()
00373     {
00374         refCloseEstablishedSession();
00375         refCloseSessionAfterHttpRequestSessionIsClosed();
00376     }
00377 
00379     void refCloseClosedOrClosingSession()
00380     {
00381         call (session->close())
00382         .returns();
00383     }
00384 
00388     void stateSessionIsClosing()
00389     {
00390         stateSessionIsEstablished();
00391 
00392         refCloseEstablishedSession();
00393     }
00394 
00396     void testCloseClosedSession()
00397     {
00398         refCloseClosedOrClosingSession();
00399     }
00400 
00402     void testCloseSessionCompletelyAfterItsEstablished()
00403     {
00404         stateSessionIsEstablished();
00405 
00406         refCloseEstablishedSessionCompletely();
00407     }
00408 
00410     void testCloseSessionCompletelyWhileWaitingForResponse()
00411     {
00412         stateWaitingForResponse();
00413 
00414         refCloseEstablishedSessionCompletely();
00415     }
00416 
00418     void testCloseSessionCompletelyAfterHandledResponseHeader()
00419     {
00420         stateResponseHeaderHandledSuccessfully();
00421 
00422         refCloseEstablishedSessionCompletely();
00423     }
00424 
00426     void testCloseSessionWhileClosing()
00427     {
00428         stateSessionIsClosing();
00429 
00430         refCloseClosedOrClosingSession();
00431     }
00432 
00434     void refAbortEstablishedSession()
00435     {
00436         call (session->abort())
00437             .willCall (httpRequestSession->abort())
00438             .returns()
00439             .willCall (sessionStatus->trackerRequestSessionClosed (
00440                 sessionReal.get()))
00441             .returns()
00442         .returns();
00443     }
00444 
00446     void testAbortClosedSession()
00447     {
00448         call (session->abort())
00449         .returns();
00450     }
00451 
00453     void testAbortSessionAfterItsEstablished()
00454     {
00455         stateSessionIsEstablished();
00456 
00457         refAbortEstablishedSession();
00458     }
00459 
00461     void testAbortSessionWhileWaitingForResponse()
00462     {
00463         stateWaitingForResponse();
00464 
00465         refAbortEstablishedSession();
00466     }
00467 
00469     void testAbortSessionAfterHandledResponseHeader()
00470     {
00471         stateResponseHeaderHandledSuccessfully();
00472 
00473         refAbortEstablishedSession();
00474     }
00475 
00477     void testAbortSessionWhileClosing()
00478     {
00479         stateSessionIsClosing();
00480 
00481         refAbortEstablishedSession();
00482     }
00483 
00485     void refHandleHttpRequestSessionError (const QString &errorMessage)
00486     {
00487         call (session->httpRequestSessionError (errorMessage))
00488             .willCall (sessionStatus->trackerRequestSessionError (
00489                 sessionReal.get(), QString ("HTTP request session error: " +
00490                     errorMessage)))
00491             .returns()
00492         .returns();
00493     }
00494 
00496     void testHttpRequestSessionErrorWhileEstablishingSession()
00497     {
00498         stateSessionIsOpened();
00499 
00500         refHandleHttpRequestSessionError (QString ("Connection failed"));
00501     }
00502 
00504     void testHttpRequestSessionErrorAfterSessionIsEstablished()
00505     {
00506         stateSessionIsEstablished();
00507 
00508         refHandleHttpRequestSessionError (QString ("Connection lost"));
00509     }
00510 
00512     void testHttpRequestSessionErrorWhileWaitingForResponse()
00513     {
00514         stateWaitingForResponse();
00515 
00516         refHandleHttpRequestSessionError (QString ("Connection lost"));
00517     }
00518 
00520     void testHttpRequestSessionErrorAfterHandledResponseHeader()
00521     {
00522         stateResponseHeaderHandledSuccessfully();
00523 
00524         refHandleHttpRequestSessionError (QString ("Connection lost"));
00525     }
00526 
00528     void testHttpRequestSessionErrorWhileClosing()
00529     {
00530         stateSessionIsClosing();
00531 
00532         refHandleHttpRequestSessionError (QString ("Closing problem"));
00533     }
00534 };
00535 
00536 CPPUNIT_TEST_SUITE_REGISTRATION(SingleTrackerRequestSessionTest);
00537 
00539 SingleTrackerRequestSessionTest::SingleTrackerRequestSessionTest()
00540     : httpRequestSession(),
00541       sessionStatus(),
00542       sessionReal(),
00543       session(),
00544       ValidAnnounceUrl (Uri::fromUnencoded ("http://localhost/announce.php")),
00545       ValidTrackerRequest (
00546         ValidAnnounceUrl,
00547         PeerInfo ("0.0.0.0", 6881, PeerInfo::PeerId ("-CA0610-574938205849")),
00548         Torrent::InfoHash ("z53bf64bd05hfn2daqml"),
00549         4096,
00550         2048,
00551         63488,
00552         false),
00553       ValidTrackerRequestUrl (Uri::fromUnencoded (
00554         ValidAnnounceUrl.unencoded() +
00555         "?info_hash=z53bf64bd05hfn2daqml"
00556         "&peer_id=-CA0610-574938205849"
00557         "&port=6881"
00558         "&uploaded=4096"
00559         "&downloaded=2048"
00560         "&left=63488"
00561         "&compact=0"
00562         "&event=empty"
00563         "&numwant=0")),
00564       ValidResponseBody (
00565         "d"
00566             "8:intervali300e"
00567             "5:peersle"
00568         "e"),
00569       InvalidResponseBody (
00570         "d"
00571             "1:too-long-key-namei467e"
00572         "e"),
00573       FailureResponseBody (
00574         "d"
00575             "14:failure reason17:Unknown info_hash"
00576         "e"),
00577       ValidTrackerResponse (createValidTrackerResponse())
00578 {
00579 }
00580 
00581 } // namespace Testing
00582 } // namespace Trackers
00583 } // namespace BitTorrent
00584 } // namespace Protocols