llhttpclient_tut.cpp

Go to the documentation of this file.
00001 
00038 #include <tut/tut.h>
00039 #include "linden_common.h"
00040 
00041 // These are too slow on Windows to actually include in the build. JC
00042 #if !LL_WINDOWS
00043 
00044 #include "lltut.h"
00045 #include "llhttpclient.h"
00046 #include "llformat.h"
00047 #include "llpipeutil.h"
00048 #include "llpumpio.h"
00049 
00050 #include "llsdhttpserver.h"
00051 #include "lliohttpserver.h"
00052 #include "lliosocket.h"
00053 
00054 namespace tut
00055 {
00056         LLSD storage;
00057         
00058         class LLSDStorageNode : public LLHTTPNode
00059         {
00060         public:
00061                 LLSD get() const                                        { return storage; }
00062                 LLSD put(const LLSD& value) const       { storage = value; return LLSD(); }
00063         };
00064 
00065         class ErrorNode : public LLHTTPNode
00066         {
00067         public:
00068                 void get(ResponsePtr r, const LLSD& context) const
00069                         { r->status(599, "Intentional error"); }
00070                 void post(ResponsePtr r, const LLSD& context, const LLSD& input) const
00071                         { r->status(input["status"], input["reason"]); }
00072         };
00073 
00074         class TimeOutNode : public LLHTTPNode
00075         {
00076         public:
00077                 void get(ResponsePtr r, const LLSD& context) const
00078                 {
00079             /* do nothing, the request will eventually time out */ 
00080                 }
00081         };
00082 
00083         LLHTTPRegistration<LLSDStorageNode> gStorageNode("/test/storage");
00084         LLHTTPRegistration<ErrorNode>           gErrorNode("/test/error");
00085         LLHTTPRegistration<TimeOutNode>         gTimeOutNode("/test/timeout");
00086 
00087         struct HTTPClientTestData
00088         {
00089         public:
00090                 HTTPClientTestData()
00091                 {
00092                         apr_pool_create(&mPool, NULL);
00093                         mServerPump = new LLPumpIO(mPool);
00094                         mClientPump = new LLPumpIO(mPool);
00095                         
00096                         LLHTTPClient::setPump(*mClientPump);
00097                 }
00098                 
00099                 ~HTTPClientTestData()
00100                 {
00101                         delete mServerPump;
00102                         delete mClientPump;
00103                         apr_pool_destroy(mPool);
00104                 }
00105 
00106                 void setupTheServer()
00107                 {
00108                         LLHTTPNode& root = LLIOHTTPServer::create(mPool, *mServerPump, 8888);
00109 
00110                         LLHTTPStandardServices::useServices();
00111                         LLHTTPRegistrar::buildAllServices(root);
00112                 }
00113                 
00114                 void runThePump(float timeout = 100.0f)
00115                 {
00116                         LLTimer timer;
00117                         timer.setTimerExpirySec(timeout);
00118 
00119                         while(!mSawCompleted && !mSawCompletedHeader && !timer.hasExpired())
00120                         {
00121                                 if (mServerPump)
00122                                 {
00123                                         mServerPump->pump();
00124                                         mServerPump->callback();
00125                                 }
00126                                 if (mClientPump)
00127                                 {
00128                                         mClientPump->pump();
00129                                         mClientPump->callback();
00130                                 }
00131                         }
00132                 }
00133 
00134                 void killServer()
00135                 {
00136                         delete mServerPump;
00137                         mServerPump = NULL;
00138                 }
00139         
00140         private:
00141                 apr_pool_t* mPool;
00142                 LLPumpIO* mServerPump;
00143                 LLPumpIO* mClientPump;
00144 
00145                 
00146         protected:
00147                 void ensureStatusOK()
00148                 {
00149                         if (mSawError)
00150                         {
00151                                 std::string msg =
00152                                         llformat("error() called when not expected, status %d",
00153                                                 mStatus); 
00154                                 fail(msg);
00155                         }
00156                 }
00157         
00158                 void ensureStatusError()
00159                 {
00160                         if (!mSawError)
00161                         {
00162                                 fail("error() wasn't called");
00163                         }
00164                 }
00165                 
00166                 LLSD getResult()
00167                 {
00168                         return mResult;
00169                 }
00170                 LLSD getHeader()
00171                 {
00172                         return mHeader;
00173                 }
00174         
00175         protected:
00176                 bool mSawError;
00177                 U32 mStatus;
00178                 std::string mReason;
00179                 bool mSawCompleted;
00180                 bool mSawCompletedHeader;
00181                 LLSD mResult;
00182                 LLSD mHeader;
00183                 bool mResultDeleted;
00184 
00185                 class Result : public LLHTTPClient::Responder
00186                 {
00187                 protected:
00188                         Result(HTTPClientTestData& client)
00189                                 : mClient(client)
00190                         {
00191                         }
00192                 
00193                 public:
00194                         static boost::intrusive_ptr<Result> build(HTTPClientTestData& client)
00195                         {
00196                                 return boost::intrusive_ptr<Result>(new Result(client));
00197                         }
00198                         
00199                         ~Result()
00200                         {
00201                                 mClient.mResultDeleted = true;
00202                         }
00203                         
00204                         virtual void error(U32 status, const std::string& reason)
00205                         {
00206                                 mClient.mSawError = true;
00207                                 mClient.mStatus = status;
00208                                 mClient.mReason = reason;
00209                         }
00210 
00211                         virtual void result(const LLSD& content)
00212                         {
00213                                 mClient.mResult = content;
00214                         }
00215 
00216                         virtual void completed(
00217                                                         U32 status, const std::string& reason,
00218                                                         const LLSD& content)
00219                         {
00220                                 LLHTTPClient::Responder::completed(status, reason, content);
00221                                 
00222                                 mClient.mSawCompleted = true;
00223                         }
00224 
00225                         virtual void completedHeader(
00226                                 U32 status, const std::string& reason,
00227                                 const LLSD& content)
00228                         {
00229                                 mClient.mHeader = content;
00230                                 mClient.mSawCompletedHeader = true;
00231                         }
00232 
00233                 private:
00234                         HTTPClientTestData& mClient;
00235                 };
00236 
00237                 friend class Result;
00238 
00239         protected:
00240                 LLHTTPClient::ResponderPtr newResult()
00241                 {
00242                         mSawError = false;
00243                         mStatus = 0;
00244                         mSawCompleted = false;
00245                         mSawCompletedHeader = false;
00246                         mResult.clear();
00247                         mHeader.clear();
00248                         mResultDeleted = false;
00249                         
00250                         return Result::build(*this);
00251                 }
00252         };
00253         
00254         
00255         typedef test_group<HTTPClientTestData>  HTTPClientTestGroup;
00256         typedef HTTPClientTestGroup::object             HTTPClientTestObject;
00257         HTTPClientTestGroup httpClientTestGroup("http_client");
00258 
00259         template<> template<>
00260         void HTTPClientTestObject::test<1>()
00261         {
00262                 LLHTTPClient::get("http://www.secondlife.com/", newResult());
00263                 runThePump();
00264                 ensureStatusOK();
00265                 ensure("result object wasn't destroyed", mResultDeleted);
00266         }
00267 
00268         template<> template<>
00269         void HTTPClientTestObject::test<2>()
00270         {
00271                 LLHTTPClient::get("http://www.invalid", newResult());
00272                 runThePump();
00273                 ensureStatusError();
00274         }
00275 
00276         template<> template<>
00277                 void HTTPClientTestObject::test<3>()
00278         {
00279                 LLSD sd;
00280 
00281                 sd["list"][0]["one"] = 1;
00282                 sd["list"][0]["two"] = 2;
00283                 sd["list"][1]["three"] = 3;
00284                 sd["list"][1]["four"] = 4;
00285                 
00286                 setupTheServer();
00287 
00288                 LLHTTPClient::post("http://localhost:8888/web/echo", sd, newResult());
00289                 runThePump();
00290                 ensureStatusOK();
00291                 ensure_equals("echoed result matches", getResult(), sd);
00292         }
00293 
00294         template<> template<>
00295                 void HTTPClientTestObject::test<4>()
00296         {
00297                 LLSD sd;
00298 
00299                 sd["message"] = "This is my test message.";
00300 
00301                 setupTheServer();
00302                 LLHTTPClient::put("http://localhost:8888/test/storage", sd, newResult());
00303                 runThePump();
00304                 ensureStatusOK();
00305 
00306                 LLHTTPClient::get("http://localhost:8888/test/storage", newResult());
00307                 runThePump();
00308                 ensureStatusOK();
00309                 ensure_equals("echoed result matches", getResult(), sd);
00310         
00311         }
00312 
00313         template<> template<>
00314                 void HTTPClientTestObject::test<5>()
00315         {
00316                 LLSD sd;
00317                 sd["status"] = 543;
00318                 sd["reason"] = "error for testing";
00319 
00320                 setupTheServer();
00321 
00322                 LLHTTPClient::post("http://localhost:8888/test/error", sd, newResult());
00323                 runThePump();
00324                 ensureStatusError();
00325                 ensure_contains("reason", mReason, sd["reason"]);
00326         }
00327 
00328         template<> template<>
00329                 void HTTPClientTestObject::test<6>()
00330         {
00331                 setupTheServer();
00332 
00333                 LLHTTPClient::get("http://localhost:8888/test/timeout", newResult());
00334                 runThePump(1.0f);
00335                 killServer();
00336                 runThePump();
00337                 ensureStatusError();
00338                 ensure_equals("reason", mReason, "STATUS_ERROR");
00339         }
00340 
00341         template<> template<>
00342                 void HTTPClientTestObject::test<7>()
00343         {
00344                 // Can not use the little mini server.  The blocking request
00345                 // won't ever let it run.  Instead get from a known LLSD
00346                 // source and compare results with the non-blocking get which
00347                 // is tested against the mini server earlier.
00348                 skip_fail("secondlife.com is not reliable enough for unit tests.");
00349 
00350 
00351                 LLSD expected;
00352 
00353                 LLHTTPClient::get("http://secondlife.com/xmlhttp/homepage.php", newResult());
00354                 runThePump();
00355                 ensureStatusOK();
00356                 expected = getResult();
00357 
00358                 LLSD result;
00359                 result = LLHTTPClient::blockingGet("http://secondlife.com/xmlhttp/homepage.php");
00360                 LLSD body = result["body"];
00361                 ensure_equals("echoed result matches", body.size(), expected.size());
00362         }
00363         template<> template<>
00364                 void HTTPClientTestObject::test<8>()
00365         {
00366                 // This is testing for the presence of the Header in the returned results
00367                 // from an HTTP::get call.
00368                 LLHTTPClient::get("http://www.secondlife.com/", newResult());
00369                 runThePump();
00370                 ensureStatusOK();
00371                 LLSD header = getHeader();
00372                 ensure_equals("got a header", header.emptyMap().asBoolean(), FALSE);
00373         }
00374         template<> template<>
00375         void HTTPClientTestObject::test<9>()
00376         {
00377                 LLHTTPClient::head("http://www.secondlife.com/", newResult());
00378                 runThePump();
00379                 ensureStatusOK();
00380                 ensure("result object wasn't destroyed", mResultDeleted);
00381         }
00382 }
00383 
00384 #endif  // !LL_WINDOWS

Generated on Fri May 16 08:34:29 2008 for SecondLife by  doxygen 1.5.5