PageRenderTime 45ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/test/llhttpclient_tut.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 383 lines | 285 code | 60 blank | 38 comment | 6 complexity | cb80f3bce8c21f75949c210234dec2c0 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llhttpclient_tut.cpp
  3. * @brief Testing the HTTP client classes.
  4. *
  5. * $LicenseInfo:firstyear=2006&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. /**
  27. *
  28. * These classes test the HTTP client framework.
  29. *
  30. */
  31. #include <tut/tut.hpp>
  32. #include "linden_common.h"
  33. // These are too slow on Windows to actually include in the build. JC
  34. #if !LL_WINDOWS
  35. #include "lltut.h"
  36. #include "llhttpclient.h"
  37. #include "llformat.h"
  38. #include "llpipeutil.h"
  39. #include "llproxy.h"
  40. #include "llpumpio.h"
  41. #include "llsdhttpserver.h"
  42. #include "lliohttpserver.h"
  43. #include "lliosocket.h"
  44. namespace tut
  45. {
  46. LLSD storage;
  47. class LLSDStorageNode : public LLHTTPNode
  48. {
  49. public:
  50. LLSD simpleGet() const { return storage; }
  51. LLSD simplePut(const LLSD& value) const { storage = value; return LLSD(); }
  52. };
  53. class ErrorNode : public LLHTTPNode
  54. {
  55. public:
  56. void get(ResponsePtr r, const LLSD& context) const
  57. { r->status(599, "Intentional error"); }
  58. void post(ResponsePtr r, const LLSD& context, const LLSD& input) const
  59. { r->status(input["status"], input["reason"]); }
  60. };
  61. class TimeOutNode : public LLHTTPNode
  62. {
  63. public:
  64. void get(ResponsePtr r, const LLSD& context) const
  65. {
  66. /* do nothing, the request will eventually time out */
  67. }
  68. };
  69. LLHTTPRegistration<LLSDStorageNode> gStorageNode("/test/storage");
  70. LLHTTPRegistration<ErrorNode> gErrorNode("/test/error");
  71. LLHTTPRegistration<TimeOutNode> gTimeOutNode("/test/timeout");
  72. struct HTTPClientTestData
  73. {
  74. public:
  75. HTTPClientTestData()
  76. {
  77. apr_pool_create(&mPool, NULL);
  78. LLCurl::initClass(false);
  79. mServerPump = new LLPumpIO(mPool);
  80. mClientPump = new LLPumpIO(mPool);
  81. LLHTTPClient::setPump(*mClientPump);
  82. }
  83. ~HTTPClientTestData()
  84. {
  85. delete mServerPump;
  86. delete mClientPump;
  87. LLProxy::cleanupClass();
  88. apr_pool_destroy(mPool);
  89. }
  90. void setupTheServer()
  91. {
  92. LLHTTPNode& root = LLIOHTTPServer::create(mPool, *mServerPump, 8888);
  93. LLHTTPStandardServices::useServices();
  94. LLHTTPRegistrar::buildAllServices(root);
  95. }
  96. void runThePump(float timeout = 100.0f)
  97. {
  98. LLTimer timer;
  99. timer.setTimerExpirySec(timeout);
  100. while(!mSawCompleted && !mSawCompletedHeader && !timer.hasExpired())
  101. {
  102. if (mServerPump)
  103. {
  104. mServerPump->pump();
  105. mServerPump->callback();
  106. }
  107. if (mClientPump)
  108. {
  109. mClientPump->pump();
  110. mClientPump->callback();
  111. }
  112. }
  113. }
  114. void killServer()
  115. {
  116. delete mServerPump;
  117. mServerPump = NULL;
  118. }
  119. private:
  120. apr_pool_t* mPool;
  121. LLPumpIO* mServerPump;
  122. LLPumpIO* mClientPump;
  123. protected:
  124. void ensureStatusOK()
  125. {
  126. if (mSawError)
  127. {
  128. std::string msg =
  129. llformat("error() called when not expected, status %d",
  130. mStatus);
  131. fail(msg);
  132. }
  133. }
  134. void ensureStatusError()
  135. {
  136. if (!mSawError)
  137. {
  138. fail("error() wasn't called");
  139. }
  140. }
  141. LLSD getResult()
  142. {
  143. return mResult;
  144. }
  145. LLSD getHeader()
  146. {
  147. return mHeader;
  148. }
  149. protected:
  150. bool mSawError;
  151. U32 mStatus;
  152. std::string mReason;
  153. bool mSawCompleted;
  154. bool mSawCompletedHeader;
  155. LLSD mResult;
  156. LLSD mHeader;
  157. bool mResultDeleted;
  158. class Result : public LLHTTPClient::Responder
  159. {
  160. protected:
  161. Result(HTTPClientTestData& client)
  162. : mClient(client)
  163. {
  164. }
  165. public:
  166. static boost::intrusive_ptr<Result> build(HTTPClientTestData& client)
  167. {
  168. return boost::intrusive_ptr<Result>(new Result(client));
  169. }
  170. ~Result()
  171. {
  172. mClient.mResultDeleted = true;
  173. }
  174. virtual void error(U32 status, const std::string& reason)
  175. {
  176. mClient.mSawError = true;
  177. mClient.mStatus = status;
  178. mClient.mReason = reason;
  179. }
  180. virtual void result(const LLSD& content)
  181. {
  182. mClient.mResult = content;
  183. }
  184. virtual void completed(
  185. U32 status, const std::string& reason,
  186. const LLSD& content)
  187. {
  188. LLHTTPClient::Responder::completed(status, reason, content);
  189. mClient.mSawCompleted = true;
  190. }
  191. virtual void completedHeader(
  192. U32 status, const std::string& reason,
  193. const LLSD& content)
  194. {
  195. mClient.mHeader = content;
  196. mClient.mSawCompletedHeader = true;
  197. }
  198. private:
  199. HTTPClientTestData& mClient;
  200. };
  201. friend class Result;
  202. protected:
  203. LLHTTPClient::ResponderPtr newResult()
  204. {
  205. mSawError = false;
  206. mStatus = 0;
  207. mSawCompleted = false;
  208. mSawCompletedHeader = false;
  209. mResult.clear();
  210. mHeader.clear();
  211. mResultDeleted = false;
  212. return Result::build(*this);
  213. }
  214. };
  215. typedef test_group<HTTPClientTestData> HTTPClientTestGroup;
  216. typedef HTTPClientTestGroup::object HTTPClientTestObject;
  217. HTTPClientTestGroup httpClientTestGroup("http_client");
  218. template<> template<>
  219. void HTTPClientTestObject::test<1>()
  220. {
  221. LLHTTPClient::get("http://www.google.com/", newResult());
  222. runThePump();
  223. ensureStatusOK();
  224. ensure("result object wasn't destroyed", mResultDeleted);
  225. }
  226. template<> template<>
  227. void HTTPClientTestObject::test<2>()
  228. {
  229. skip("error test depends on dev's local ISP not supplying \"helpful\" search page");
  230. LLHTTPClient::get("http://www.invalid", newResult());
  231. runThePump();
  232. ensureStatusError();
  233. }
  234. template<> template<>
  235. void HTTPClientTestObject::test<3>()
  236. {
  237. LLSD sd;
  238. sd["list"][0]["one"] = 1;
  239. sd["list"][0]["two"] = 2;
  240. sd["list"][1]["three"] = 3;
  241. sd["list"][1]["four"] = 4;
  242. setupTheServer();
  243. LLHTTPClient::post("http://localhost:8888/web/echo", sd, newResult());
  244. runThePump();
  245. ensureStatusOK();
  246. ensure_equals("echoed result matches", getResult(), sd);
  247. }
  248. template<> template<>
  249. void HTTPClientTestObject::test<4>()
  250. {
  251. LLSD sd;
  252. sd["message"] = "This is my test message.";
  253. setupTheServer();
  254. LLHTTPClient::put("http://localhost:8888/test/storage", sd, newResult());
  255. runThePump();
  256. ensureStatusOK();
  257. LLHTTPClient::get("http://localhost:8888/test/storage", newResult());
  258. runThePump();
  259. ensureStatusOK();
  260. ensure_equals("echoed result matches", getResult(), sd);
  261. }
  262. template<> template<>
  263. void HTTPClientTestObject::test<5>()
  264. {
  265. LLSD sd;
  266. sd["status"] = 543;
  267. sd["reason"] = "error for testing";
  268. setupTheServer();
  269. LLHTTPClient::post("http://localhost:8888/test/error", sd, newResult());
  270. runThePump();
  271. ensureStatusError();
  272. ensure_contains("reason", mReason, sd["reason"]);
  273. }
  274. template<> template<>
  275. void HTTPClientTestObject::test<6>()
  276. {
  277. setupTheServer();
  278. LLHTTPClient::get("http://localhost:8888/test/timeout", newResult());
  279. runThePump(1.0f);
  280. killServer();
  281. runThePump();
  282. ensureStatusError();
  283. ensure_equals("reason", mReason, "STATUS_ERROR");
  284. }
  285. template<> template<>
  286. void HTTPClientTestObject::test<7>()
  287. {
  288. // Can not use the little mini server. The blocking request
  289. // won't ever let it run. Instead get from a known LLSD
  290. // source and compare results with the non-blocking get which
  291. // is tested against the mini server earlier.
  292. skip("secondlife.com is not reliable enough for unit tests.");
  293. LLSD expected;
  294. LLHTTPClient::get("http://secondlife.com/xmlhttp/homepage.php", newResult());
  295. runThePump();
  296. ensureStatusOK();
  297. expected = getResult();
  298. LLSD result;
  299. result = LLHTTPClient::blockingGet("http://secondlife.com/xmlhttp/homepage.php");
  300. LLSD body = result["body"];
  301. ensure_equals("echoed result matches", body.size(), expected.size());
  302. }
  303. template<> template<>
  304. void HTTPClientTestObject::test<8>()
  305. {
  306. // This is testing for the presence of the Header in the returned results
  307. // from an HTTP::get call.
  308. LLHTTPClient::get("http://www.google.com/", newResult());
  309. runThePump();
  310. ensureStatusOK();
  311. LLSD header = getHeader();
  312. ensure_equals("got a header", header.emptyMap().asBoolean(), FALSE);
  313. }
  314. template<> template<>
  315. void HTTPClientTestObject::test<9>()
  316. {
  317. LLHTTPClient::head("http://www.google.com/", newResult());
  318. runThePump();
  319. ensureStatusOK();
  320. ensure("result object wasn't destroyed", mResultDeleted);
  321. }
  322. }
  323. #endif // !LL_WINDOWS