~ubuntu-branches/debian/experimental/kopete/experimental

« back to all changes in this revision

Viewing changes to protocols/jabber/libjingle/talk/base/httpbase_unittest.cc

  • Committer: Package Import Robot
  • Author(s): Maximiliano Curia
  • Date: 2015-02-24 11:32:57 UTC
  • mfrom: (1.1.41 vivid)
  • Revision ID: package-import@ubuntu.com-20150224113257-gnupg4v7lzz18ij0
Tags: 4:14.12.2-1
* New upstream release (14.12.2).
* Bump Standards-Version to 3.9.6, no changes needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * libjingle
 
3
 * Copyright 2004--2011, Google Inc.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions are met:
 
7
 *
 
8
 *  1. Redistributions of source code must retain the above copyright notice,
 
9
 *     this list of conditions and the following disclaimer.
 
10
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 
11
 *     this list of conditions and the following disclaimer in the documentation
 
12
 *     and/or other materials provided with the distribution.
 
13
 *  3. The name of the author may not be used to endorse or promote products
 
14
 *     derived from this software without specific prior written permission.
 
15
 *
 
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 
17
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 
18
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 
19
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
20
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
21
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 
22
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
23
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 
24
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
25
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
26
 */
 
27
 
 
28
#include "talk/base/gunit.h"
 
29
#include "talk/base/httpbase.h"
 
30
#include "talk/base/testutils.h"
 
31
 
 
32
namespace talk_base {
 
33
 
 
34
const char* const kHttpResponse =
 
35
  "HTTP/1.1 200\r\n"
 
36
  "Connection: Keep-Alive\r\n"
 
37
  "Content-Type: text/plain\r\n"
 
38
  "Proxy-Authorization: 42\r\n"
 
39
  "Transfer-Encoding: chunked\r\n"
 
40
  "\r\n"
 
41
  "00000008\r\n"
 
42
  "Goodbye!\r\n"
 
43
  "0\r\n\r\n";
 
44
 
 
45
const char* const kHttpEmptyResponse =
 
46
  "HTTP/1.1 200\r\n"
 
47
  "Connection: Keep-Alive\r\n"
 
48
  "Content-Length: 0\r\n"
 
49
  "Proxy-Authorization: 42\r\n"
 
50
  "\r\n";
 
51
 
 
52
const char* const kHttpResponsePrefix =
 
53
  "HTTP/1.1 200\r\n"
 
54
  "Connection: Keep-Alive\r\n"
 
55
  "Content-Type: text/plain\r\n"
 
56
  "Proxy-Authorization: 42\r\n"
 
57
  "Transfer-Encoding: chunked\r\n"
 
58
  "\r\n"
 
59
  "8\r\n"
 
60
  "Goodbye!\r\n";
 
61
 
 
62
class HttpBaseTest : public testing::Test, public IHttpNotify {
 
63
public:
 
64
  enum EventType { E_HEADER_COMPLETE, E_COMPLETE, E_CLOSED };
 
65
  struct Event {
 
66
    EventType event;
 
67
    bool chunked;
 
68
    size_t data_size;
 
69
    HttpMode mode;
 
70
    HttpError err;
 
71
  };
 
72
  HttpBaseTest() : mem(NULL), obtain_stream(false), http_stream(NULL) { }
 
73
 
 
74
  virtual void SetUp() { }
 
75
  virtual void TearDown() {
 
76
    // Avoid an ASSERT, in case a test doesn't clean up properly
 
77
    base.abort(HE_NONE);
 
78
  }
 
79
 
 
80
  virtual HttpError onHttpHeaderComplete(bool chunked, size_t& data_size) {
 
81
    LOG_F(LS_VERBOSE) << "chunked: " << chunked << " size: " << data_size;
 
82
    Event e = { E_HEADER_COMPLETE, chunked, data_size, HM_NONE, HE_NONE};
 
83
    events.push_back(e);
 
84
    if (obtain_stream) {
 
85
      ObtainDocumentStream();
 
86
    }
 
87
    return HE_NONE;
 
88
  }
 
89
  virtual void onHttpComplete(HttpMode mode, HttpError err) {
 
90
    LOG_F(LS_VERBOSE) << "mode: " << mode << " err: " << err;
 
91
    Event e = { E_COMPLETE, false, 0, mode, err };
 
92
    events.push_back(e);
 
93
  }
 
94
  virtual void onHttpClosed(HttpError err) {
 
95
    LOG_F(LS_VERBOSE) << "err: " << err;
 
96
    Event e = { E_CLOSED, false, 0, HM_NONE, err };
 
97
    events.push_back(e);
 
98
  }
 
99
 
 
100
  void SetupSource(const char* response);
 
101
 
 
102
  void VerifyHeaderComplete(size_t event_count, bool empty_doc);
 
103
  void VerifyDocumentContents(const char* expected_data,
 
104
                              size_t expected_length = SIZE_UNKNOWN);
 
105
 
 
106
  void ObtainDocumentStream();
 
107
  void VerifyDocumentStreamIsOpening();
 
108
  void VerifyDocumentStreamOpenEvent();
 
109
  void ReadDocumentStreamData(const char* expected_data);
 
110
  void VerifyDocumentStreamIsEOS();
 
111
 
 
112
  void SetupDocument(const char* response);
 
113
  void VerifySourceContents(const char* expected_data,
 
114
                            size_t expected_length = SIZE_UNKNOWN);
 
115
 
 
116
  void VerifyTransferComplete(HttpMode mode, HttpError error);
 
117
 
 
118
  HttpBase base;
 
119
  MemoryStream* mem;
 
120
  HttpResponseData data;
 
121
 
 
122
  // The source of http data, and source events
 
123
  testing::StreamSource src;
 
124
  std::vector<Event> events;
 
125
 
 
126
  // Document stream, and stream events
 
127
  bool obtain_stream;
 
128
  StreamInterface* http_stream;
 
129
  testing::StreamSink sink;
 
130
};
 
131
 
 
132
void HttpBaseTest::SetupSource(const char* http_data) {
 
133
  LOG_F(LS_VERBOSE) << "Enter";
 
134
 
 
135
  src.SetState(SS_OPENING);
 
136
  src.QueueString(http_data);
 
137
 
 
138
  base.notify(this);
 
139
  base.attach(&src);
 
140
  EXPECT_TRUE(events.empty());
 
141
 
 
142
  src.SetState(SS_OPEN);
 
143
  ASSERT_EQ(1U, events.size());
 
144
  EXPECT_EQ(E_COMPLETE, events[0].event);
 
145
  EXPECT_EQ(HM_CONNECT, events[0].mode);
 
146
  EXPECT_EQ(HE_NONE, events[0].err);
 
147
  events.clear();
 
148
 
 
149
  mem = new MemoryStream;
 
150
  data.document.reset(mem);
 
151
  LOG_F(LS_VERBOSE) << "Exit";
 
152
}
 
153
 
 
154
void HttpBaseTest::VerifyHeaderComplete(size_t event_count, bool empty_doc) {
 
155
  LOG_F(LS_VERBOSE) << "Enter";
 
156
 
 
157
  ASSERT_EQ(event_count, events.size());
 
158
  EXPECT_EQ(E_HEADER_COMPLETE, events[0].event);
 
159
 
 
160
  std::string header;
 
161
  EXPECT_EQ(HVER_1_1, data.version);
 
162
  EXPECT_EQ(static_cast<uint32>(HC_OK), data.scode);
 
163
  EXPECT_TRUE(data.hasHeader(HH_PROXY_AUTHORIZATION, &header));
 
164
  EXPECT_EQ("42", header);
 
165
  EXPECT_TRUE(data.hasHeader(HH_CONNECTION, &header));
 
166
  EXPECT_EQ("Keep-Alive", header);
 
167
 
 
168
  if (empty_doc) {
 
169
    EXPECT_FALSE(events[0].chunked);
 
170
    EXPECT_EQ(0U, events[0].data_size);
 
171
 
 
172
    EXPECT_TRUE(data.hasHeader(HH_CONTENT_LENGTH, &header));
 
173
    EXPECT_EQ("0", header);
 
174
  } else {
 
175
    EXPECT_TRUE(events[0].chunked);
 
176
    EXPECT_EQ(SIZE_UNKNOWN, events[0].data_size);
 
177
 
 
178
    EXPECT_TRUE(data.hasHeader(HH_CONTENT_TYPE, &header));
 
179
    EXPECT_EQ("text/plain", header);
 
180
    EXPECT_TRUE(data.hasHeader(HH_TRANSFER_ENCODING, &header));
 
181
    EXPECT_EQ("chunked", header);
 
182
  }
 
183
  LOG_F(LS_VERBOSE) << "Exit";
 
184
}
 
185
 
 
186
void HttpBaseTest::VerifyDocumentContents(const char* expected_data,
 
187
                                          size_t expected_length) {
 
188
  LOG_F(LS_VERBOSE) << "Enter";
 
189
 
 
190
  if (SIZE_UNKNOWN == expected_length) {
 
191
    expected_length = strlen(expected_data);
 
192
  }
 
193
  EXPECT_EQ(mem, data.document.get());
 
194
 
 
195
  size_t length;
 
196
  mem->GetSize(&length);
 
197
  EXPECT_EQ(expected_length, length);
 
198
  EXPECT_TRUE(0 == memcmp(expected_data, mem->GetBuffer(), length));
 
199
  LOG_F(LS_VERBOSE) << "Exit";
 
200
}
 
201
 
 
202
void HttpBaseTest::ObtainDocumentStream() {
 
203
  LOG_F(LS_VERBOSE) << "Enter";
 
204
  EXPECT_FALSE(http_stream);
 
205
  http_stream = base.GetDocumentStream();
 
206
  ASSERT_TRUE(NULL != http_stream);
 
207
  sink.Monitor(http_stream);
 
208
  LOG_F(LS_VERBOSE) << "Exit";
 
209
}
 
210
 
 
211
void HttpBaseTest::VerifyDocumentStreamIsOpening() {
 
212
  LOG_F(LS_VERBOSE) << "Enter";
 
213
  ASSERT_TRUE(NULL != http_stream);
 
214
  EXPECT_EQ(0, sink.Events(http_stream));
 
215
  EXPECT_EQ(SS_OPENING, http_stream->GetState());
 
216
 
 
217
  size_t read = 0;
 
218
  char buffer[5] = { 0 };
 
219
  EXPECT_EQ(SR_BLOCK, http_stream->Read(buffer, sizeof(buffer), &read, NULL));
 
220
  LOG_F(LS_VERBOSE) << "Exit";
 
221
}
 
222
 
 
223
void HttpBaseTest::VerifyDocumentStreamOpenEvent() {
 
224
  LOG_F(LS_VERBOSE) << "Enter";
 
225
 
 
226
  ASSERT_TRUE(NULL != http_stream);
 
227
  EXPECT_EQ(SE_OPEN | SE_READ, sink.Events(http_stream));
 
228
  EXPECT_EQ(SS_OPEN, http_stream->GetState());
 
229
 
 
230
  // HTTP headers haven't arrived yet
 
231
  EXPECT_EQ(0U, events.size());
 
232
  EXPECT_EQ(static_cast<uint32>(HC_INTERNAL_SERVER_ERROR), data.scode);
 
233
  LOG_F(LS_VERBOSE) << "Exit";
 
234
}
 
235
 
 
236
void HttpBaseTest::ReadDocumentStreamData(const char* expected_data) {
 
237
  LOG_F(LS_VERBOSE) << "Enter";
 
238
 
 
239
  ASSERT_TRUE(NULL != http_stream);
 
240
  EXPECT_EQ(SS_OPEN, http_stream->GetState());
 
241
 
 
242
  // Pump the HTTP I/O using Read, and verify the results.
 
243
  size_t verified_length = 0;
 
244
  const size_t expected_length = strlen(expected_data);
 
245
  while (verified_length < expected_length) {
 
246
    size_t read = 0;
 
247
    char buffer[5] = { 0 };
 
248
    size_t amt_to_read = _min(expected_length - verified_length, sizeof(buffer));
 
249
    EXPECT_EQ(SR_SUCCESS, http_stream->Read(buffer, amt_to_read, &read, NULL));
 
250
    EXPECT_EQ(amt_to_read, read);
 
251
    EXPECT_TRUE(0 == memcmp(expected_data + verified_length, buffer, read));
 
252
    verified_length += read;
 
253
  }
 
254
  LOG_F(LS_VERBOSE) << "Exit";
 
255
}
 
256
 
 
257
void HttpBaseTest::VerifyDocumentStreamIsEOS() {
 
258
  LOG_F(LS_VERBOSE) << "Enter";
 
259
 
 
260
  ASSERT_TRUE(NULL != http_stream);
 
261
  size_t read = 0;
 
262
  char buffer[5] = { 0 };
 
263
  EXPECT_EQ(SR_EOS, http_stream->Read(buffer, sizeof(buffer), &read, NULL));
 
264
  EXPECT_EQ(SS_CLOSED, http_stream->GetState());
 
265
 
 
266
  // When EOS is caused by Read, we don't expect SE_CLOSE
 
267
  EXPECT_EQ(0, sink.Events(http_stream));
 
268
  LOG_F(LS_VERBOSE) << "Exit";
 
269
}
 
270
 
 
271
void HttpBaseTest::SetupDocument(const char* document_data) {
 
272
  LOG_F(LS_VERBOSE) << "Enter";
 
273
  src.SetState(SS_OPEN);
 
274
 
 
275
  base.notify(this);
 
276
  base.attach(&src);
 
277
  EXPECT_TRUE(events.empty());
 
278
 
 
279
  if (document_data) {
 
280
    // Note: we could just call data.set_success("text/plain", mem), but that
 
281
    // won't allow us to use the chunked transfer encoding.
 
282
    mem = new MemoryStream(document_data);
 
283
    data.document.reset(mem);
 
284
    data.setHeader(HH_CONTENT_TYPE, "text/plain");
 
285
    data.setHeader(HH_TRANSFER_ENCODING, "chunked");
 
286
  } else {
 
287
    data.setHeader(HH_CONTENT_LENGTH, "0");
 
288
  }
 
289
  data.scode = HC_OK;
 
290
  data.setHeader(HH_PROXY_AUTHORIZATION, "42");
 
291
  data.setHeader(HH_CONNECTION, "Keep-Alive");
 
292
  LOG_F(LS_VERBOSE) << "Exit";
 
293
}
 
294
 
 
295
void HttpBaseTest::VerifySourceContents(const char* expected_data,
 
296
                                        size_t expected_length) {
 
297
  LOG_F(LS_VERBOSE) << "Enter";
 
298
  if (SIZE_UNKNOWN == expected_length) {
 
299
    expected_length = strlen(expected_data);
 
300
  }
 
301
  std::string contents = src.ReadData();
 
302
  EXPECT_EQ(expected_length, contents.length());
 
303
  EXPECT_TRUE(0 == memcmp(expected_data, contents.data(), expected_length));
 
304
  LOG_F(LS_VERBOSE) << "Exit";
 
305
}
 
306
 
 
307
void HttpBaseTest::VerifyTransferComplete(HttpMode mode, HttpError error) {
 
308
  LOG_F(LS_VERBOSE) << "Enter";
 
309
  // Verify that http operation has completed
 
310
  ASSERT_TRUE(events.size() > 0);
 
311
  size_t last_event = events.size() - 1;
 
312
  EXPECT_EQ(E_COMPLETE, events[last_event].event);
 
313
  EXPECT_EQ(mode, events[last_event].mode);
 
314
  EXPECT_EQ(error, events[last_event].err);
 
315
  LOG_F(LS_VERBOSE) << "Exit";
 
316
}
 
317
 
 
318
//
 
319
// Tests
 
320
//
 
321
 
 
322
TEST_F(HttpBaseTest, SupportsSend) {
 
323
  // Queue response document
 
324
  SetupDocument("Goodbye!");
 
325
 
 
326
  // Begin send
 
327
  base.send(&data);
 
328
 
 
329
  // Send completed successfully
 
330
  VerifyTransferComplete(HM_SEND, HE_NONE);
 
331
  VerifySourceContents(kHttpResponse);
 
332
}
 
333
 
 
334
TEST_F(HttpBaseTest, SupportsSendNoDocument) {
 
335
  // Queue response document
 
336
  SetupDocument(NULL);
 
337
 
 
338
  // Begin send
 
339
  base.send(&data);
 
340
 
 
341
  // Send completed successfully
 
342
  VerifyTransferComplete(HM_SEND, HE_NONE);
 
343
  VerifySourceContents(kHttpEmptyResponse);
 
344
}
 
345
 
 
346
TEST_F(HttpBaseTest, SignalsCompleteOnInterruptedSend) {
 
347
  // This test is attempting to expose a bug that occurs when a particular
 
348
  // base objects is used for receiving, and then used for sending.  In
 
349
  // particular, the HttpParser state is different after receiving.  Simulate
 
350
  // that here.
 
351
  SetupSource(kHttpResponse);
 
352
  base.recv(&data);
 
353
  VerifyTransferComplete(HM_RECV, HE_NONE);
 
354
 
 
355
  src.Clear();
 
356
  data.clear(true);
 
357
  events.clear();
 
358
  base.detach();
 
359
 
 
360
  // Queue response document
 
361
  SetupDocument("Goodbye!");
 
362
 
 
363
  // Prevent entire response from being sent
 
364
  const size_t kInterruptedLength = strlen(kHttpResponse) - 1;
 
365
  src.SetWriteBlock(kInterruptedLength);
 
366
 
 
367
  // Begin send
 
368
  base.send(&data);
 
369
 
 
370
  // Document is mostly complete, but no completion signal yet.
 
371
  EXPECT_TRUE(events.empty());
 
372
  VerifySourceContents(kHttpResponse, kInterruptedLength);
 
373
 
 
374
  src.SetState(SS_CLOSED);
 
375
 
 
376
  // Send completed with disconnect error, and no additional data.
 
377
  VerifyTransferComplete(HM_SEND, HE_DISCONNECTED);
 
378
  EXPECT_TRUE(src.ReadData().empty());
 
379
}
 
380
 
 
381
TEST_F(HttpBaseTest, SupportsReceiveViaDocumentPush) {
 
382
  // Queue response document
 
383
  SetupSource(kHttpResponse);
 
384
 
 
385
  // Begin receive
 
386
  base.recv(&data);
 
387
 
 
388
  // Document completed successfully
 
389
  VerifyHeaderComplete(2, false);
 
390
  VerifyTransferComplete(HM_RECV, HE_NONE);
 
391
  VerifyDocumentContents("Goodbye!");
 
392
}
 
393
 
 
394
TEST_F(HttpBaseTest, SupportsReceiveViaStreamPull) {
 
395
  // Switch to pull mode
 
396
  ObtainDocumentStream();
 
397
  VerifyDocumentStreamIsOpening();
 
398
 
 
399
  // Queue response document
 
400
  SetupSource(kHttpResponse);
 
401
  VerifyDocumentStreamIsOpening();
 
402
 
 
403
  // Begin receive
 
404
  base.recv(&data);
 
405
 
 
406
  // Pull document data
 
407
  VerifyDocumentStreamOpenEvent();
 
408
  ReadDocumentStreamData("Goodbye!");
 
409
  VerifyDocumentStreamIsEOS();
 
410
 
 
411
  // Document completed successfully
 
412
  VerifyHeaderComplete(2, false);
 
413
  VerifyTransferComplete(HM_RECV, HE_NONE);
 
414
  VerifyDocumentContents("");
 
415
}
 
416
 
 
417
TEST_F(HttpBaseTest, DISABLED_AllowsCloseStreamBeforeDocumentIsComplete) {
 
418
 
 
419
  // TODO: Remove extra logging once test failure is understood
 
420
  int old_sev = talk_base::LogMessage::GetLogToDebug();
 
421
  talk_base::LogMessage::LogToDebug(LS_VERBOSE);
 
422
 
 
423
 
 
424
  // Switch to pull mode
 
425
  ObtainDocumentStream();
 
426
  VerifyDocumentStreamIsOpening();
 
427
 
 
428
  // Queue response document
 
429
  SetupSource(kHttpResponse);
 
430
  VerifyDocumentStreamIsOpening();
 
431
 
 
432
  // Begin receive
 
433
  base.recv(&data);
 
434
 
 
435
  // Pull some of the data
 
436
  VerifyDocumentStreamOpenEvent();
 
437
  ReadDocumentStreamData("Goodb");
 
438
 
 
439
  // We've seen the header by now
 
440
  VerifyHeaderComplete(1, false);
 
441
 
 
442
  // Close the pull stream, this will transition back to push I/O.
 
443
  http_stream->Close();
 
444
  Thread::Current()->ProcessMessages(0);
 
445
 
 
446
  // Remainder of document completed successfully
 
447
  VerifyTransferComplete(HM_RECV, HE_NONE);
 
448
  VerifyDocumentContents("ye!");
 
449
 
 
450
  talk_base::LogMessage::LogToDebug(old_sev);
 
451
}
 
452
 
 
453
TEST_F(HttpBaseTest, AllowsGetDocumentStreamInResponseToHttpHeader) {
 
454
  // Queue response document
 
455
  SetupSource(kHttpResponse);
 
456
 
 
457
  // Switch to pull mode in response to header arrival
 
458
  obtain_stream = true;
 
459
 
 
460
  // Begin receive
 
461
  base.recv(&data);
 
462
 
 
463
  // We've already seen the header, but not data has arrived
 
464
  VerifyHeaderComplete(1, false);
 
465
  VerifyDocumentContents("");
 
466
 
 
467
  // Pull the document data
 
468
  ReadDocumentStreamData("Goodbye!");
 
469
  VerifyDocumentStreamIsEOS();
 
470
 
 
471
  // Document completed successfully
 
472
  VerifyTransferComplete(HM_RECV, HE_NONE);
 
473
  VerifyDocumentContents("");
 
474
}
 
475
 
 
476
TEST_F(HttpBaseTest, AllowsGetDocumentStreamWithEmptyDocumentBody) {
 
477
  // Queue empty response document
 
478
  SetupSource(kHttpEmptyResponse);
 
479
 
 
480
  // Switch to pull mode in response to header arrival
 
481
  obtain_stream = true;
 
482
 
 
483
  // Begin receive
 
484
  base.recv(&data);
 
485
 
 
486
  // We've already seen the header, but not data has arrived
 
487
  VerifyHeaderComplete(1, true);
 
488
  VerifyDocumentContents("");
 
489
 
 
490
  // The document is still open, until we attempt to read
 
491
  ASSERT_TRUE(NULL != http_stream);
 
492
  EXPECT_EQ(SS_OPEN, http_stream->GetState());
 
493
 
 
494
  // Attempt to read data, and discover EOS
 
495
  VerifyDocumentStreamIsEOS();
 
496
 
 
497
  // Document completed successfully
 
498
  VerifyTransferComplete(HM_RECV, HE_NONE);
 
499
  VerifyDocumentContents("");
 
500
}
 
501
 
 
502
TEST_F(HttpBaseTest, SignalsDocumentStreamCloseOnUnexpectedClose) {
 
503
  // Switch to pull mode
 
504
  ObtainDocumentStream();
 
505
  VerifyDocumentStreamIsOpening();
 
506
 
 
507
  // Queue response document
 
508
  SetupSource(kHttpResponsePrefix);
 
509
  VerifyDocumentStreamIsOpening();
 
510
 
 
511
  // Begin receive
 
512
  base.recv(&data);
 
513
 
 
514
  // Pull document data
 
515
  VerifyDocumentStreamOpenEvent();
 
516
  ReadDocumentStreamData("Goodbye!");
 
517
 
 
518
  // Simulate unexpected close
 
519
  src.SetState(SS_CLOSED);
 
520
 
 
521
  // Observe error event on document stream
 
522
  EXPECT_EQ(testing::SSE_ERROR, sink.Events(http_stream));
 
523
 
 
524
  // Future reads give an error
 
525
  int error = 0;
 
526
  char buffer[5] = { 0 };
 
527
  EXPECT_EQ(SR_ERROR, http_stream->Read(buffer, sizeof(buffer), NULL, &error));
 
528
  EXPECT_EQ(HE_DISCONNECTED, error);
 
529
 
 
530
  // Document completed with error
 
531
  VerifyHeaderComplete(2, false);
 
532
  VerifyTransferComplete(HM_RECV, HE_DISCONNECTED);
 
533
  VerifyDocumentContents("");
 
534
}
 
535
 
 
536
} // namespace talk_base