PageRenderTime 31ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/mordor/tests/http_stream.cpp

http://github.com/mozy/mordor
C++ | 428 lines | 393 code | 33 blank | 2 comment | 63 complexity | 339f3312c7e6d168852548fb20638784 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright (c) 2011 - Mozy, Inc.
  2. #include <boost/bind.hpp>
  3. #include "mordor/http/broker.h"
  4. #include "mordor/http/server.h"
  5. #include "mordor/test/test.h"
  6. #include "mordor/streams/buffer.h"
  7. #include "mordor/streams/http.h"
  8. #include "mordor/streams/limited.h"
  9. #include "mordor/streams/null.h"
  10. #include "mordor/streams/random.h"
  11. #include "mordor/streams/transfer.h"
  12. #include "mordor/util.h"
  13. #include "mordor/workerpool.h"
  14. using namespace Mordor;
  15. using namespace Mordor::HTTP;
  16. namespace {
  17. class ReadAdviceFixture
  18. {
  19. public:
  20. #ifdef _MSC_VER
  21. #pragma warning(push)
  22. #pragma warning(disable: 4355)
  23. #endif
  24. ReadAdviceFixture()
  25. : server(boost::bind(&ReadAdviceFixture::dummyServer, this, _1, _2)),
  26. baseRequestBroker(ConnectionBroker::ptr(&server,
  27. &nop<ConnectionBroker *>)),
  28. requestBroker(&baseRequestBroker, &nop<RequestBroker *>),
  29. sequence(0)
  30. {}
  31. #ifdef _MSC_VER
  32. #pragma warning(pop)
  33. #pragma warning(disable: 4355)
  34. #endif
  35. private:
  36. void dummyServer(const URI &uri, ServerRequest::ptr request)
  37. {
  38. const RangeSet &range = request->request().request.range;
  39. const URI &requestUri = request->request().requestLine.uri;
  40. if (requestUri == "/startNoAdvice") {
  41. MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
  42. MORDOR_TEST_ASSERT(range.empty());
  43. } else if (requestUri == "/startAdvice0") {
  44. MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
  45. MORDOR_TEST_ASSERT(range.empty());
  46. } else if (requestUri == "/startAdvice64K") {
  47. MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
  48. MORDOR_TEST_ASSERT_EQUAL(range.size(), 1u);
  49. MORDOR_TEST_ASSERT_EQUAL(range,
  50. RangeSet(1u, std::make_pair(0, 65535)));
  51. } else if (requestUri == "/startAfterSeekNoAdvice") {
  52. MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
  53. MORDOR_TEST_ASSERT_EQUAL(range.size(), 1u);
  54. MORDOR_TEST_ASSERT_EQUAL(range,
  55. RangeSet(1u, std::make_pair(512 * 1024, ~0ull)));
  56. } else if (requestUri == "/startAfterSeekAdvice0") {
  57. MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
  58. MORDOR_TEST_ASSERT_EQUAL(range.size(), 1u);
  59. MORDOR_TEST_ASSERT_EQUAL(range,
  60. RangeSet(1u, std::make_pair(512 * 1024, ~0ull)));
  61. } else if (requestUri == "/startAfterSeekAdvice64K") {
  62. MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
  63. MORDOR_TEST_ASSERT_EQUAL(range.size(), 1u);
  64. MORDOR_TEST_ASSERT_EQUAL(range,
  65. RangeSet(1u, std::make_pair(512 * 1024,
  66. 512 * 1024 + 65535)));
  67. } else if (requestUri == "/readNoAdvice") {
  68. MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
  69. MORDOR_TEST_ASSERT(range.empty());
  70. } else if (requestUri == "/readAdvice0") {
  71. MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
  72. MORDOR_TEST_ASSERT_EQUAL(range.size(), 1u);
  73. MORDOR_TEST_ASSERT_EQUAL(range,
  74. RangeSet(1u, std::make_pair(0, 4095)));
  75. } else if (requestUri == "/readAdvice64K") {
  76. MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
  77. MORDOR_TEST_ASSERT_EQUAL(range.size(), 1u);
  78. MORDOR_TEST_ASSERT_EQUAL(range,
  79. RangeSet(1u, std::make_pair(0, 65535)));
  80. } else if (requestUri == "/readAdvice4K") {
  81. MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
  82. MORDOR_TEST_ASSERT_EQUAL(range.size(), 1u);
  83. MORDOR_TEST_ASSERT_EQUAL(range,
  84. RangeSet(1u, std::make_pair(0, 65535)));
  85. } else if (requestUri == "/read4KAdvice4K") {
  86. MORDOR_TEST_ASSERT_LESS_THAN_OR_EQUAL(++sequence, 3);
  87. MORDOR_TEST_ASSERT_EQUAL(range.size(), 1u);
  88. MORDOR_TEST_ASSERT_EQUAL(range,
  89. RangeSet(1u, std::make_pair(4096 * (sequence - 1),
  90. 4096 * sequence - 1)));
  91. } else if (requestUri == "/adviceStillGetsEOF") {
  92. MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
  93. MORDOR_TEST_ASSERT_EQUAL(range.size(), 1u);
  94. MORDOR_TEST_ASSERT_EQUAL(range,
  95. RangeSet(1u, std::make_pair(1024 * 1024 - 4096,
  96. 1024 * 1024 - 1)));
  97. } else if (requestUri == "/adviceStillGetsEOFStraddle") {
  98. MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
  99. MORDOR_TEST_ASSERT_EQUAL(range.size(), 1u);
  100. MORDOR_TEST_ASSERT_EQUAL(range,
  101. RangeSet(1u, std::make_pair(1024 * 1024 - 2048,
  102. 1024 * 1024 + 2048 - 1)));
  103. } else {
  104. MORDOR_NOTREACHED();
  105. }
  106. RandomStream randomStream;
  107. LimitedStream limitedStream(Stream::ptr(&randomStream, &nop<Stream *>),
  108. 1024 * 1024);
  109. try {
  110. respondStream(request, Stream::ptr(&limitedStream, &nop<Stream *>));
  111. } catch (BrokenPipeException &) {
  112. // The tests don't always read the full response; we don't care
  113. }
  114. }
  115. private:
  116. WorkerPool pool;
  117. MockConnectionBroker server;
  118. BaseRequestBroker baseRequestBroker;
  119. protected:
  120. RequestBroker::ptr requestBroker;
  121. int sequence;
  122. };
  123. }
  124. MORDOR_UNITTEST_FIXTURE(ReadAdviceFixture, HTTPStream, startNoAdvice)
  125. {
  126. HTTPStream stream("http://localhost/startNoAdvice", requestBroker);
  127. stream.start();
  128. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  129. }
  130. MORDOR_UNITTEST_FIXTURE(ReadAdviceFixture, HTTPStream, startAdvice0)
  131. {
  132. HTTPStream stream("http://localhost/startAdvice0", requestBroker);
  133. stream.adviseRead(0);
  134. stream.start();
  135. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  136. }
  137. MORDOR_UNITTEST_FIXTURE(ReadAdviceFixture, HTTPStream, startAdvice64K)
  138. {
  139. HTTPStream stream("http://localhost/startAdvice64K", requestBroker);
  140. stream.adviseRead(65536);
  141. stream.start();
  142. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  143. }
  144. MORDOR_UNITTEST_FIXTURE(ReadAdviceFixture, HTTPStream, startAfterSeekNoAdvice)
  145. {
  146. HTTPStream stream("http://localhost/startAfterSeekNoAdvice", requestBroker);
  147. stream.seek(512 * 1024);
  148. stream.start();
  149. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  150. }
  151. MORDOR_UNITTEST_FIXTURE(ReadAdviceFixture, HTTPStream, startAfterSeekAdvice0)
  152. {
  153. HTTPStream stream("http://localhost/startAfterSeekAdvice0", requestBroker);
  154. stream.adviseRead(0);
  155. stream.seek(512 * 1024);
  156. stream.start();
  157. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  158. }
  159. MORDOR_UNITTEST_FIXTURE(ReadAdviceFixture, HTTPStream, startAfterSeekAdvice64K)
  160. {
  161. HTTPStream stream("http://localhost/startAfterSeekAdvice64K", requestBroker);
  162. stream.adviseRead(65536);
  163. stream.seek(512 * 1024);
  164. stream.start();
  165. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  166. }
  167. MORDOR_UNITTEST_FIXTURE(ReadAdviceFixture, HTTPStream, readNoAdvice)
  168. {
  169. HTTPStream stream("http://localhost/readNoAdvice", requestBroker);
  170. Buffer buffer;
  171. stream.read(buffer, 4096);
  172. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  173. }
  174. MORDOR_UNITTEST_FIXTURE(ReadAdviceFixture, HTTPStream, readAdvice0)
  175. {
  176. HTTPStream stream("http://localhost/readAdvice0", requestBroker);
  177. stream.adviseRead(0);
  178. Buffer buffer;
  179. stream.read(buffer, 4096);
  180. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  181. }
  182. MORDOR_UNITTEST_FIXTURE(ReadAdviceFixture, HTTPStream, readAdvice64K)
  183. {
  184. HTTPStream stream("http://localhost/readAdvice64K", requestBroker);
  185. stream.adviseRead(65536);
  186. Buffer buffer;
  187. stream.read(buffer, 4096);
  188. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  189. }
  190. MORDOR_UNITTEST_FIXTURE(ReadAdviceFixture, HTTPStream, readAdvice4K)
  191. {
  192. HTTPStream stream("http://localhost/readAdvice4K", requestBroker);
  193. stream.adviseRead(4096);
  194. Buffer buffer;
  195. stream.read(buffer, 65536);
  196. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  197. }
  198. MORDOR_UNITTEST_FIXTURE(ReadAdviceFixture, HTTPStream, read4KAdvice4K)
  199. {
  200. HTTPStream stream("http://localhost/read4KAdvice4K", requestBroker);
  201. stream.adviseRead(4096);
  202. Buffer buffer;
  203. stream.read(buffer, 4096);
  204. stream.read(buffer, 4096);
  205. stream.read(buffer, 4096);
  206. MORDOR_TEST_ASSERT_EQUAL(sequence, 3);
  207. }
  208. MORDOR_UNITTEST_FIXTURE(ReadAdviceFixture, HTTPStream, adviceStillGetsEOF)
  209. {
  210. HTTPStream stream("http://localhost/adviceStillGetsEOF", requestBroker);
  211. stream.adviseRead(4096);
  212. stream.seek(1024 * 1024 - 4096);
  213. Buffer buffer;
  214. MORDOR_TEST_ASSERT_EQUAL(stream.read(buffer, 4096), 4096u);
  215. MORDOR_TEST_ASSERT_EQUAL(stream.read(buffer, 4096), 0u);
  216. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  217. }
  218. MORDOR_UNITTEST_FIXTURE(ReadAdviceFixture, HTTPStream, adviceStillGetsEOFStraddle)
  219. {
  220. HTTPStream stream("http://localhost/adviceStillGetsEOFStraddle", requestBroker);
  221. stream.adviseRead(4096);
  222. stream.seek(1024 * 1024 - 2048);
  223. Buffer buffer;
  224. MORDOR_TEST_ASSERT_EQUAL(stream.read(buffer, 4096), 2048u);
  225. MORDOR_TEST_ASSERT_EQUAL(stream.read(buffer, 4096), 0u);
  226. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  227. }
  228. namespace {
  229. class WriteAdviceFixture
  230. {
  231. public:
  232. #ifdef _MSC_VER
  233. #pragma warning(push)
  234. #pragma warning(disable: 4355)
  235. #endif
  236. WriteAdviceFixture()
  237. : server(boost::bind(&WriteAdviceFixture::dummyServer, this, _1, _2)),
  238. baseRequestBroker(ConnectionBroker::ptr(&server,
  239. &nop<ConnectionBroker *>)),
  240. requestBroker(&baseRequestBroker, &nop<RequestBroker *>),
  241. sequence(0)
  242. {}
  243. #ifdef _MSC_VER
  244. #pragma warning(pop)
  245. #pragma warning(disable: 4355)
  246. #endif
  247. private:
  248. void dummyServer(const URI &uri, ServerRequest::ptr request)
  249. {
  250. const unsigned long long &contentLength =
  251. request->request().entity.contentLength;
  252. const ContentRange &contentRange =
  253. request->request().entity.contentRange;
  254. const URI &requestUri = request->request().requestLine.uri;
  255. bool chunked = !request->request().general.transferEncoding.empty();
  256. if (requestUri == "/writeNoAdvice") {
  257. MORDOR_TEST_ASSERT_EQUAL(1, ++sequence);
  258. MORDOR_TEST_ASSERT(chunked);
  259. MORDOR_TEST_ASSERT_EQUAL(contentLength, ~0ull);
  260. MORDOR_TEST_ASSERT_EQUAL(contentRange, ContentRange());
  261. MORDOR_TEST_ASSERT_EQUAL(transferStream(request->requestStream(),
  262. NullStream::get()), 1024 * 1024ull);
  263. } else if (requestUri == "/writeSizeAdvice") {
  264. MORDOR_TEST_ASSERT_EQUAL(1, ++sequence);
  265. MORDOR_TEST_ASSERT(!chunked);
  266. MORDOR_TEST_ASSERT_EQUAL(contentLength, 1024 * 1024ull);
  267. MORDOR_TEST_ASSERT_EQUAL(contentRange, ContentRange());
  268. MORDOR_TEST_ASSERT_EQUAL(transferStream(request->requestStream(),
  269. NullStream::get()), 1024 * 1024ull);
  270. request->response().entity.extension["X-UT-ECHO-URI"] = requestUri.toString();
  271. } else if (requestUri == "/writeWriteAdvice") {
  272. MORDOR_TEST_ASSERT_LESS_THAN_OR_EQUAL(++sequence, 16);
  273. MORDOR_TEST_ASSERT(chunked);
  274. MORDOR_TEST_ASSERT_EQUAL(contentLength, ~0ull);
  275. MORDOR_TEST_ASSERT_EQUAL(contentRange,
  276. ContentRange(65536 * (sequence - 1)));
  277. MORDOR_TEST_ASSERT_EQUAL(transferStream(request->requestStream(),
  278. NullStream::get()), 65536ull);
  279. } else if (requestUri == "/writeWriteAndSizeAdvice") {
  280. MORDOR_TEST_ASSERT_LESS_THAN_OR_EQUAL(++sequence, 16);
  281. MORDOR_TEST_ASSERT(!chunked);
  282. MORDOR_TEST_ASSERT_EQUAL(contentLength, 65536ull);
  283. MORDOR_TEST_ASSERT_EQUAL(contentRange,
  284. ContentRange(65536 * (sequence - 1), 65536 * sequence - 1,
  285. 1024 * 1024));
  286. MORDOR_TEST_ASSERT_EQUAL(transferStream(request->requestStream(),
  287. NullStream::get()), 65536ull);
  288. } else if (requestUri == "/writeWriteAndSizeAdviceStraddle") {
  289. MORDOR_TEST_ASSERT_LESS_THAN_OR_EQUAL(++sequence, 16);
  290. MORDOR_TEST_ASSERT(!chunked);
  291. if (sequence != 16) {
  292. MORDOR_TEST_ASSERT_EQUAL(contentLength, 65536ull);
  293. MORDOR_TEST_ASSERT_EQUAL(contentRange,
  294. ContentRange(65536 * (sequence - 1), 65536 * sequence - 1,
  295. 1024 * 1024 - 4096));
  296. MORDOR_TEST_ASSERT_EQUAL(transferStream(
  297. request->requestStream(), NullStream::get()), 65536ull);
  298. } else {
  299. MORDOR_TEST_ASSERT_EQUAL(contentLength, 65536 - 4096ull);
  300. MORDOR_TEST_ASSERT_EQUAL(contentRange,
  301. ContentRange(1024 * 1024 - 65536, 1024 * 1024 - 4096 - 1,
  302. 1024 * 1024 - 4096));
  303. MORDOR_TEST_ASSERT_EQUAL(transferStream(
  304. request->requestStream(), NullStream::get()),
  305. 65536 - 4096ull);
  306. }
  307. } else if (requestUri == "/truncate") {
  308. MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
  309. MORDOR_TEST_ASSERT(!chunked);
  310. MORDOR_TEST_ASSERT_EQUAL(contentLength, 0ull);
  311. MORDOR_TEST_ASSERT_EQUAL(contentRange,
  312. ContentRange(~0ull, ~0ull, 65536));
  313. } else if (requestUri == "/writeZeroLength") {
  314. MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
  315. MORDOR_TEST_ASSERT_EQUAL(contentLength, 0ull);
  316. request->response().entity.extension["X-UT-ECHO-URI"] = requestUri.toString();
  317. } else {
  318. MORDOR_NOTREACHED();
  319. }
  320. respondError(request, OK);
  321. }
  322. private:
  323. WorkerPool pool;
  324. MockConnectionBroker server;
  325. BaseRequestBroker baseRequestBroker;
  326. protected:
  327. RequestBroker::ptr requestBroker;
  328. int sequence;
  329. };
  330. }
  331. MORDOR_UNITTEST_FIXTURE(WriteAdviceFixture, HTTPStream, writeNoAdvice)
  332. {
  333. HTTPStream stream("http://localhost/writeNoAdvice", requestBroker);
  334. RandomStream random;
  335. transferStream(random, stream, 1024 * 1024);
  336. stream.close();
  337. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  338. }
  339. MORDOR_UNITTEST_FIXTURE(WriteAdviceFixture, HTTPStream, writeSizeAdvice)
  340. {
  341. HTTPStream stream("http://localhost/writeSizeAdvice", requestBroker);
  342. stream.adviseSize(1024 * 1024);
  343. RandomStream random;
  344. transferStream(random, stream, 1024 * 1024);
  345. stream.close();
  346. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  347. Response response = stream.response();
  348. MORDOR_TEST_ASSERT_EQUAL(response.entity.extension["X-UT-ECHO-URI"], "/writeSizeAdvice");
  349. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  350. }
  351. MORDOR_UNITTEST_FIXTURE(WriteAdviceFixture, HTTPStream, writeWriteAdvice)
  352. {
  353. HTTPStream stream("http://localhost/writeWriteAdvice", requestBroker);
  354. stream.adviseWrite(65536);
  355. RandomStream random;
  356. transferStream(random, stream, 1024 * 1024);
  357. stream.close();
  358. MORDOR_TEST_ASSERT_EQUAL(sequence, 16);
  359. }
  360. MORDOR_UNITTEST_FIXTURE(WriteAdviceFixture, HTTPStream, writeWriteAndSizeAdvice)
  361. {
  362. HTTPStream stream("http://localhost/writeWriteAndSizeAdvice", requestBroker);
  363. stream.adviseWrite(65536);
  364. stream.adviseSize(1024 * 1024);
  365. RandomStream random;
  366. transferStream(random, stream, 1024 * 1024);
  367. stream.close();
  368. MORDOR_TEST_ASSERT_EQUAL(sequence, 16);
  369. }
  370. MORDOR_UNITTEST_FIXTURE(WriteAdviceFixture, HTTPStream, writeWriteAndSizeAdviceStraddle)
  371. {
  372. HTTPStream stream("http://localhost/writeWriteAndSizeAdviceStraddle", requestBroker);
  373. stream.adviseWrite(65536);
  374. stream.adviseSize(1024 * 1024 - 4096);
  375. RandomStream random;
  376. transferStream(random, stream, 1024 * 1024 - 4096);
  377. stream.close();
  378. MORDOR_TEST_ASSERT_EQUAL(sequence, 16);
  379. }
  380. MORDOR_UNITTEST_FIXTURE(WriteAdviceFixture, HTTPStream, truncate)
  381. {
  382. HTTPStream stream("http://localhost/truncate", requestBroker);
  383. stream.truncate(65536);
  384. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  385. }
  386. MORDOR_UNITTEST_FIXTURE(WriteAdviceFixture, HTTPStream, writeZeroLength)
  387. {
  388. HTTPStream stream("http://localhost/writeZeroLength", requestBroker);
  389. stream.adviseSize(0);
  390. stream.close();
  391. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  392. Response response = stream.response();
  393. MORDOR_TEST_ASSERT_EQUAL(response.entity.extension["X-UT-ECHO-URI"], "/writeZeroLength");
  394. MORDOR_TEST_ASSERT_EQUAL(sequence, 1);
  395. }