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