1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ppapi/tests/test_websocket.h"
6
7#include <stdio.h>
8#include <string.h>
9
10#include <algorithm>
11#include <memory>
12#include <string>
13#include <vector>
14
15#include "ppapi/c/pp_bool.h"
16#include "ppapi/c/pp_completion_callback.h"
17#include "ppapi/c/pp_errors.h"
18#include "ppapi/c/pp_instance.h"
19#include "ppapi/c/pp_resource.h"
20#include "ppapi/c/pp_var.h"
21#include "ppapi/c/ppb_core.h"
22#include "ppapi/c/ppb_var.h"
23#include "ppapi/c/ppb_var_array_buffer.h"
24#include "ppapi/c/ppb_websocket.h"
25#include "ppapi/c/private/ppb_testing_private.h"
26#include "ppapi/cpp/instance.h"
27#include "ppapi/cpp/module.h"
28#include "ppapi/cpp/var_array_buffer.h"
29#include "ppapi/cpp/websocket.h"
30#include "ppapi/tests/test_utils.h"
31#include "ppapi/tests/testing_instance.h"
32#include "ppapi/utility/websocket/websocket_api.h"
33
34// net::SpawnedTestServer serves WebSocket service for testing.
35// Following URLs are handled by pywebsocket handlers in
36// net/data/websocket/*_wsh.py.
37const char kEchoServerURL[] = "echo-with-no-extension";
38const char kCloseServerURL[] = "close";
39const char kCloseWithCodeAndReasonServerURL[] = "close-code-and-reason";
40const char kProtocolTestServerURL[] = "protocol-test?protocol=";
41
42const char* const kInvalidURLs[] = {
43  "http://www.google.com/invalid_scheme",
44  "ws://www.google.com/invalid#fragment",
45  "ws://www.google.com:65535/invalid_port",
46  NULL
47};
48
49// Internal packet sizes.
50const uint64_t kMessageFrameOverhead = 6;
51
52namespace {
53
54struct WebSocketEvent {
55  enum EventType {
56    EVENT_OPEN,
57    EVENT_MESSAGE,
58    EVENT_ERROR,
59    EVENT_CLOSE
60  };
61
62  WebSocketEvent(EventType type,
63                 bool was_clean,
64                 uint16_t close_code,
65                 const pp::Var& var)
66      : event_type(type),
67        was_clean(was_clean),
68        close_code(close_code),
69        var(var) {
70  }
71  EventType event_type;
72  bool was_clean;
73  uint16_t close_code;
74  pp::Var var;
75};
76
77class ReleaseResourceDelegate : public TestCompletionCallback::Delegate {
78 public:
79  explicit ReleaseResourceDelegate(const PPB_Core* core_interface,
80                                   PP_Resource resource)
81      : core_interface_(core_interface),
82        resource_(resource) {
83  }
84
85  // TestCompletionCallback::Delegate implementation.
86  virtual void OnCallback(void* user_data, int32_t result) {
87    if (resource_)
88      core_interface_->ReleaseResource(resource_);
89  }
90
91 private:
92  const PPB_Core* core_interface_;
93  PP_Resource resource_;
94};
95
96class TestWebSocketAPI : public pp::WebSocketAPI {
97 public:
98  explicit TestWebSocketAPI(pp::Instance* instance)
99      : pp::WebSocketAPI(instance),
100        connected_(false),
101        received_(false),
102        closed_(false),
103        wait_for_connected_(false),
104        wait_for_received_(false),
105        wait_for_closed_(false),
106        instance_(instance->pp_instance()) {
107  }
108
109  virtual void WebSocketDidOpen() {
110    events_.push_back(
111        WebSocketEvent(WebSocketEvent::EVENT_OPEN, true, 0U, pp::Var()));
112    connected_ = true;
113    if (wait_for_connected_) {
114      GetTestingInterface()->QuitMessageLoop(instance_);
115      wait_for_connected_ = false;
116    }
117  }
118
119  virtual void WebSocketDidClose(
120      bool was_clean, uint16_t code, const pp::Var& reason) {
121    events_.push_back(
122        WebSocketEvent(WebSocketEvent::EVENT_CLOSE, was_clean, code, reason));
123    connected_ = true;
124    closed_ = true;
125    if (wait_for_connected_ || wait_for_closed_) {
126      GetTestingInterface()->QuitMessageLoop(instance_);
127      wait_for_connected_ = false;
128      wait_for_closed_ = false;
129    }
130  }
131
132  virtual void HandleWebSocketMessage(const pp::Var &message) {
133    events_.push_back(
134        WebSocketEvent(WebSocketEvent::EVENT_MESSAGE, true, 0U, message));
135    received_ = true;
136    if (wait_for_received_) {
137      GetTestingInterface()->QuitMessageLoop(instance_);
138      wait_for_received_ = false;
139      received_ = false;
140    }
141  }
142
143  virtual void HandleWebSocketError() {
144    events_.push_back(
145        WebSocketEvent(WebSocketEvent::EVENT_ERROR, true, 0U, pp::Var()));
146  }
147
148  void WaitForConnected() {
149    if (!connected_) {
150      wait_for_connected_ = true;
151      GetTestingInterface()->RunMessageLoop(instance_);
152    }
153  }
154
155  void WaitForReceived() {
156    if (!received_) {
157      wait_for_received_ = true;
158      GetTestingInterface()->RunMessageLoop(instance_);
159    }
160  }
161
162  void WaitForClosed() {
163    if (!closed_) {
164      wait_for_closed_ = true;
165      GetTestingInterface()->RunMessageLoop(instance_);
166    }
167  }
168
169  const std::vector<WebSocketEvent>& GetSeenEvents() const {
170    return events_;
171  }
172
173 private:
174  std::vector<WebSocketEvent> events_;
175  bool connected_;
176  bool received_;
177  bool closed_;
178  bool wait_for_connected_;
179  bool wait_for_received_;
180  bool wait_for_closed_;
181  PP_Instance instance_;
182};
183
184}  // namespace
185
186REGISTER_TEST_CASE(WebSocket);
187
188bool TestWebSocket::Init() {
189  websocket_interface_ = static_cast<const PPB_WebSocket*>(
190      pp::Module::Get()->GetBrowserInterface(PPB_WEBSOCKET_INTERFACE));
191  var_interface_ = static_cast<const PPB_Var*>(
192      pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE));
193  arraybuffer_interface_ = static_cast<const PPB_VarArrayBuffer*>(
194      pp::Module::Get()->GetBrowserInterface(
195          PPB_VAR_ARRAY_BUFFER_INTERFACE));
196  core_interface_ = static_cast<const PPB_Core*>(
197      pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE));
198  if (!websocket_interface_ || !var_interface_ || !arraybuffer_interface_ ||
199      !core_interface_)
200    return false;
201
202  return CheckTestingInterface();
203}
204
205void TestWebSocket::RunTests(const std::string& filter) {
206  RUN_TEST_WITH_REFERENCE_CHECK(IsWebSocket, filter);
207  RUN_TEST_WITH_REFERENCE_CHECK(UninitializedPropertiesAccess, filter);
208  RUN_TEST_WITH_REFERENCE_CHECK(InvalidConnect, filter);
209  RUN_TEST_WITH_REFERENCE_CHECK(Protocols, filter);
210  RUN_TEST_WITH_REFERENCE_CHECK(GetURL, filter);
211  RUN_TEST_WITH_REFERENCE_CHECK(ValidConnect, filter);
212  RUN_TEST_WITH_REFERENCE_CHECK(InvalidClose, filter);
213  RUN_TEST_WITH_REFERENCE_CHECK(ValidClose, filter);
214  RUN_TEST_WITH_REFERENCE_CHECK(GetProtocol, filter);
215  RUN_TEST_WITH_REFERENCE_CHECK(TextSendReceive, filter);
216  RUN_TEST_BACKGROUND(TestWebSocket, TextSendReceiveTwice, filter);
217  RUN_TEST_WITH_REFERENCE_CHECK(BinarySendReceive, filter);
218  RUN_TEST_WITH_REFERENCE_CHECK(StressedSendReceive, filter);
219  RUN_TEST_WITH_REFERENCE_CHECK(BufferedAmount, filter);
220  // PP_Resource for WebSocket may be released later because of an internal
221  // reference for asynchronous IPC handling. So, suppress reference check on
222  // the following AbortCallsWithCallback test.
223  RUN_TEST(AbortCallsWithCallback, filter);
224  RUN_TEST_WITH_REFERENCE_CHECK(AbortSendMessageCall, filter);
225  RUN_TEST_WITH_REFERENCE_CHECK(AbortCloseCall, filter);
226  RUN_TEST_WITH_REFERENCE_CHECK(AbortReceiveMessageCall, filter);
227
228  RUN_TEST_WITH_REFERENCE_CHECK(CcInterfaces, filter);
229
230  RUN_TEST_WITH_REFERENCE_CHECK(UtilityInvalidConnect, filter);
231  RUN_TEST_WITH_REFERENCE_CHECK(UtilityProtocols, filter);
232  RUN_TEST_WITH_REFERENCE_CHECK(UtilityGetURL, filter);
233  RUN_TEST_WITH_REFERENCE_CHECK(UtilityValidConnect, filter);
234  RUN_TEST_WITH_REFERENCE_CHECK(UtilityInvalidClose, filter);
235  RUN_TEST_WITH_REFERENCE_CHECK(UtilityValidClose, filter);
236  RUN_TEST_WITH_REFERENCE_CHECK(UtilityGetProtocol, filter);
237  RUN_TEST_WITH_REFERENCE_CHECK(UtilityTextSendReceive, filter);
238  RUN_TEST_WITH_REFERENCE_CHECK(UtilityBinarySendReceive, filter);
239  RUN_TEST_WITH_REFERENCE_CHECK(UtilityBufferedAmount, filter);
240}
241
242std::string TestWebSocket::GetFullURL(const char* url) {
243  std::string rv = "ws://";
244  // Some WebSocket tests don't start the server so there'll be no host and
245  // port.
246  if (instance_->websocket_host().empty())
247    rv += "127.0.0.1";
248  else
249    rv += instance_->websocket_host();
250  if (instance_->websocket_port() != -1) {
251    char buffer[10];
252    sprintf(buffer, ":%d", instance_->websocket_port());
253    rv += std::string(buffer);
254  }
255  rv += "/";
256  rv += url;
257  return rv;
258}
259
260PP_Var TestWebSocket::CreateVarString(const std::string& string) {
261  return var_interface_->VarFromUtf8(string.c_str(), string.size());
262}
263
264PP_Var TestWebSocket::CreateVarBinary(const std::vector<uint8_t>& binary) {
265  PP_Var var = arraybuffer_interface_->Create(binary.size());
266  uint8_t* var_data = static_cast<uint8_t*>(arraybuffer_interface_->Map(var));
267  std::copy(binary.begin(), binary.end(), var_data);
268  return var;
269}
270
271void TestWebSocket::ReleaseVar(const PP_Var& var) {
272  var_interface_->Release(var);
273}
274
275bool TestWebSocket::AreEqualWithString(const PP_Var& var,
276                                       const std::string& string) {
277  if (var.type != PP_VARTYPE_STRING)
278    return false;
279  uint32_t utf8_length;
280  const char* utf8 = var_interface_->VarToUtf8(var, &utf8_length);
281  if (utf8_length != string.size())
282    return false;
283  if (string.compare(utf8))
284    return false;
285  return true;
286}
287
288bool TestWebSocket::AreEqualWithBinary(const PP_Var& var,
289                                       const std::vector<uint8_t>& binary) {
290  uint32_t buffer_size = 0;
291  PP_Bool success = arraybuffer_interface_->ByteLength(var, &buffer_size);
292  if (!success || buffer_size != binary.size())
293    return false;
294  if (!std::equal(binary.begin(), binary.end(),
295      static_cast<uint8_t*>(arraybuffer_interface_->Map(var))))
296    return false;
297  return true;
298}
299
300PP_Resource TestWebSocket::Connect(const std::string& url,
301                                   int32_t* result,
302                                   const std::string& protocol) {
303  PP_Var protocols[] = { PP_MakeUndefined() };
304  PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
305  if (!ws)
306    return 0;
307  PP_Var url_var = CreateVarString(url);
308  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
309  uint32_t protocol_count = 0U;
310  if (protocol.size()) {
311    protocols[0] = CreateVarString(protocol);
312    protocol_count = 1U;
313  }
314  callback.WaitForResult(websocket_interface_->Connect(
315      ws, url_var, protocols, protocol_count,
316      callback.GetCallback().pp_completion_callback()));
317  ReleaseVar(url_var);
318  if (protocol.size())
319    ReleaseVar(protocols[0]);
320  *result = callback.result();
321  return ws;
322}
323
324void TestWebSocket::Send(int32_t /* result */, PP_Resource ws,
325                         const std::string& message) {
326  PP_Var message_var = CreateVarString(message);
327  websocket_interface_->SendMessage(ws, message_var);
328  ReleaseVar(message_var);
329}
330
331std::string TestWebSocket::TestIsWebSocket() {
332  // Test that a NULL resource isn't a websocket.
333  pp::Resource null_resource;
334  PP_Bool result =
335      websocket_interface_->IsWebSocket(null_resource.pp_resource());
336  ASSERT_FALSE(result);
337
338  PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
339  ASSERT_TRUE(ws);
340
341  result = websocket_interface_->IsWebSocket(ws);
342  ASSERT_TRUE(result);
343
344  core_interface_->ReleaseResource(ws);
345
346  PASS();
347}
348
349std::string TestWebSocket::TestUninitializedPropertiesAccess() {
350  PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
351  ASSERT_TRUE(ws);
352
353  uint64_t bufferedAmount = websocket_interface_->GetBufferedAmount(ws);
354  ASSERT_EQ(0U, bufferedAmount);
355
356  uint16_t close_code = websocket_interface_->GetCloseCode(ws);
357  ASSERT_EQ(0U, close_code);
358
359  PP_Var close_reason = websocket_interface_->GetCloseReason(ws);
360  ASSERT_TRUE(AreEqualWithString(close_reason, std::string()));
361  ReleaseVar(close_reason);
362
363  PP_Bool close_was_clean = websocket_interface_->GetCloseWasClean(ws);
364  ASSERT_EQ(PP_FALSE, close_was_clean);
365
366  PP_Var extensions = websocket_interface_->GetExtensions(ws);
367  ASSERT_TRUE(AreEqualWithString(extensions, std::string()));
368  ReleaseVar(extensions);
369
370  PP_Var protocol = websocket_interface_->GetProtocol(ws);
371  ASSERT_TRUE(AreEqualWithString(protocol, std::string()));
372  ReleaseVar(protocol);
373
374  PP_WebSocketReadyState ready_state =
375      websocket_interface_->GetReadyState(ws);
376  ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID, ready_state);
377
378  PP_Var url = websocket_interface_->GetURL(ws);
379  ASSERT_TRUE(AreEqualWithString(url, std::string()));
380  ReleaseVar(url);
381
382  core_interface_->ReleaseResource(ws);
383
384  PASS();
385}
386
387std::string TestWebSocket::TestInvalidConnect() {
388  PP_Var protocols[] = { PP_MakeUndefined() };
389
390  PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
391  ASSERT_TRUE(ws);
392
393  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
394  callback.WaitForResult(websocket_interface_->Connect(
395      ws, PP_MakeUndefined(), protocols, 1U,
396      callback.GetCallback().pp_completion_callback()));
397  ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result());
398
399  callback.WaitForResult(websocket_interface_->Connect(
400      ws, PP_MakeUndefined(), protocols, 1U,
401      callback.GetCallback().pp_completion_callback()));
402  ASSERT_EQ(PP_ERROR_INPROGRESS, callback.result());
403
404  core_interface_->ReleaseResource(ws);
405
406  for (int i = 0; kInvalidURLs[i]; ++i) {
407    int32_t result;
408    ws = Connect(kInvalidURLs[i], &result, std::string());
409    ASSERT_TRUE(ws);
410    ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
411
412    core_interface_->ReleaseResource(ws);
413  }
414
415  PASS();
416}
417
418std::string TestWebSocket::TestProtocols() {
419  PP_Var url = CreateVarString(GetFullURL(kEchoServerURL).c_str());
420  PP_Var bad_protocols[] = {
421    CreateVarString("x-test"),
422    CreateVarString("x-test")
423  };
424  PP_Var good_protocols[] = {
425    CreateVarString("x-test"),
426    CreateVarString("x-yatest")
427  };
428
429  PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
430  ASSERT_TRUE(ws);
431  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
432  callback.WaitForResult(websocket_interface_->Connect(
433      ws, url, bad_protocols, 2U,
434      callback.GetCallback().pp_completion_callback()));
435  ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result());
436  core_interface_->ReleaseResource(ws);
437
438  ws = websocket_interface_->Create(instance_->pp_instance());
439  ASSERT_TRUE(ws);
440  int32_t result = websocket_interface_->Connect(
441      ws, url, good_protocols, 2U, PP_BlockUntilComplete());
442  ASSERT_EQ(PP_ERROR_BLOCKS_MAIN_THREAD, result);
443  core_interface_->ReleaseResource(ws);
444
445  ReleaseVar(url);
446  for (int i = 0; i < 2; ++i) {
447    ReleaseVar(bad_protocols[i]);
448    ReleaseVar(good_protocols[i]);
449  }
450  core_interface_->ReleaseResource(ws);
451
452  PASS();
453}
454
455std::string TestWebSocket::TestGetURL() {
456  for (int i = 0; kInvalidURLs[i]; ++i) {
457    int32_t result;
458    PP_Resource ws = Connect(kInvalidURLs[i], &result, std::string());
459    ASSERT_TRUE(ws);
460    PP_Var url = websocket_interface_->GetURL(ws);
461    ASSERT_TRUE(AreEqualWithString(url, kInvalidURLs[i]));
462    ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
463
464    ReleaseVar(url);
465    core_interface_->ReleaseResource(ws);
466  }
467
468  PASS();
469}
470
471std::string TestWebSocket::TestValidConnect() {
472  int32_t result;
473  PP_Resource ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
474  ASSERT_TRUE(ws);
475  ASSERT_EQ(PP_OK, result);
476  PP_Var extensions = websocket_interface_->GetExtensions(ws);
477  ASSERT_TRUE(AreEqualWithString(extensions, std::string()));
478  core_interface_->ReleaseResource(ws);
479  ReleaseVar(extensions);
480
481  PASS();
482}
483
484std::string TestWebSocket::TestInvalidClose() {
485  PP_Var reason = CreateVarString("close for test");
486  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
487  TestCompletionCallback async_callback(instance_->pp_instance(), PP_REQUIRED);
488
489  // Close before connect.
490  PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
491  callback.WaitForResult(websocket_interface_->Close(
492      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
493      callback.GetCallback().pp_completion_callback()));
494  ASSERT_EQ(PP_ERROR_FAILED, callback.result());
495  core_interface_->ReleaseResource(ws);
496
497  // Close with bad arguments.
498  int32_t result;
499  ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
500  ASSERT_TRUE(ws);
501  ASSERT_EQ(PP_OK, result);
502  callback.WaitForResult(websocket_interface_->Close(
503      ws, 1U, reason, callback.GetCallback().pp_completion_callback()));
504  ASSERT_EQ(PP_ERROR_NOACCESS, callback.result());
505  core_interface_->ReleaseResource(ws);
506
507  // Close with PP_VARTYPE_NULL.
508  ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
509  ASSERT_TRUE(ws);
510  ASSERT_EQ(PP_OK, result);
511  callback.WaitForResult(websocket_interface_->Close(
512      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeNull(),
513      callback.GetCallback().pp_completion_callback()));
514  ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result());
515  core_interface_->ReleaseResource(ws);
516
517  // Close with PP_VARTYPE_NULL and ongoing receive message.
518  ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
519  ASSERT_TRUE(ws);
520  ASSERT_EQ(PP_OK, result);
521  PP_Var receive_message_var;
522  result = websocket_interface_->ReceiveMessage(
523      ws, &receive_message_var,
524      async_callback.GetCallback().pp_completion_callback());
525  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
526  callback.WaitForResult(websocket_interface_->Close(
527      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeNull(),
528      callback.GetCallback().pp_completion_callback()));
529  ASSERT_EQ(PP_ERROR_BADARGUMENT, callback.result());
530  const char* send_message = "hi";
531  PP_Var send_message_var = CreateVarString(send_message);
532  result = websocket_interface_->SendMessage(ws, send_message_var);
533  ReleaseVar(send_message_var);
534  ASSERT_EQ(PP_OK, result);
535  async_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
536  ASSERT_EQ(PP_OK, async_callback.result());
537  ASSERT_TRUE(AreEqualWithString(receive_message_var, send_message));
538  ReleaseVar(receive_message_var);
539  core_interface_->ReleaseResource(ws);
540
541  // Close twice.
542  ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
543  ASSERT_TRUE(ws);
544  ASSERT_EQ(PP_OK, result);
545  result = websocket_interface_->Close(
546      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
547      async_callback.GetCallback().pp_completion_callback());
548  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
549  // Call another Close() before previous one is in progress.
550  result = websocket_interface_->Close(
551      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
552      callback.GetCallback().pp_completion_callback());
553  ASSERT_EQ(PP_ERROR_INPROGRESS, result);
554  async_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
555  ASSERT_EQ(PP_OK, async_callback.result());
556  // Call another Close() after previous one is completed.
557  // This Close() must do nothing and reports no error.
558  callback.WaitForResult(websocket_interface_->Close(
559      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
560      callback.GetCallback().pp_completion_callback()));
561  ASSERT_EQ(PP_OK, callback.result());
562  core_interface_->ReleaseResource(ws);
563
564  ReleaseVar(reason);
565
566  PASS();
567}
568
569std::string TestWebSocket::TestValidClose() {
570  PP_Var reason = CreateVarString("close for test");
571  PP_Var url = CreateVarString(GetFullURL(kEchoServerURL).c_str());
572  PP_Var protocols[] = { PP_MakeUndefined() };
573  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
574  TestCompletionCallback another_callback(
575      instance_->pp_instance(), callback_type());
576
577  // Close.
578  int32_t result;
579  PP_Resource ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
580  ASSERT_TRUE(ws);
581  ASSERT_EQ(PP_OK, result);
582  callback.WaitForResult(websocket_interface_->Close(
583      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
584      callback.GetCallback().pp_completion_callback()));
585  CHECK_CALLBACK_BEHAVIOR(callback);
586  ASSERT_EQ(PP_OK, callback.result());
587  core_interface_->ReleaseResource(ws);
588
589  // Close without code and reason.
590  ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
591  ASSERT_TRUE(ws);
592  ASSERT_EQ(PP_OK, result);
593  callback.WaitForResult(websocket_interface_->Close(
594      ws, PP_WEBSOCKETSTATUSCODE_NOT_SPECIFIED, reason,
595      callback.GetCallback().pp_completion_callback()));
596  ASSERT_EQ(PP_OK, callback.result());
597  core_interface_->ReleaseResource(ws);
598
599  // Close with PP_VARTYPE_UNDEFINED.
600  ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
601  ASSERT_TRUE(ws);
602  ASSERT_EQ(PP_OK, result);
603  callback.WaitForResult(websocket_interface_->Close(
604      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(),
605      callback.GetCallback().pp_completion_callback()));
606  CHECK_CALLBACK_BEHAVIOR(callback);
607  ASSERT_EQ(PP_OK, callback.result());
608  core_interface_->ReleaseResource(ws);
609
610  // Close in connecting.
611  // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
612  // successfully.
613  ws = websocket_interface_->Create(instance_->pp_instance());
614  result = websocket_interface_->Connect(
615      ws, url, protocols, 0U, callback.GetCallback().pp_completion_callback());
616  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
617  result = websocket_interface_->Close(
618      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
619      another_callback.GetCallback().pp_completion_callback());
620  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
621  callback.WaitForResult(PP_OK_COMPLETIONPENDING);
622  ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
623  another_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
624  ASSERT_EQ(PP_OK, another_callback.result());
625  core_interface_->ReleaseResource(ws);
626
627  // Close in closing.
628  // The first close will be done successfully, then the second one failed with
629  // with PP_ERROR_INPROGRESS immediately.
630  ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
631  ASSERT_TRUE(ws);
632  ASSERT_EQ(PP_OK, result);
633  result = websocket_interface_->Close(
634      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
635      callback.GetCallback().pp_completion_callback());
636  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
637  result = websocket_interface_->Close(
638      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
639      another_callback.GetCallback().pp_completion_callback());
640  ASSERT_EQ(PP_ERROR_INPROGRESS, result);
641  callback.WaitForResult(PP_OK_COMPLETIONPENDING);
642  ASSERT_EQ(PP_OK, callback.result());
643  core_interface_->ReleaseResource(ws);
644
645  // Close with ongoing receive message.
646  ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
647  ASSERT_TRUE(ws);
648  ASSERT_EQ(PP_OK, result);
649  PP_Var receive_message_var;
650  result = websocket_interface_->ReceiveMessage(
651      ws, &receive_message_var,
652      callback.GetCallback().pp_completion_callback());
653  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
654  result = websocket_interface_->Close(
655      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
656      another_callback.GetCallback().pp_completion_callback());
657  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
658  callback.WaitForResult(PP_OK_COMPLETIONPENDING);
659  ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
660  another_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
661  ASSERT_EQ(PP_OK, another_callback.result());
662  core_interface_->ReleaseResource(ws);
663
664  // Close with PP_VARTYPE_UNDEFINED and ongoing receive message.
665  ws = Connect(GetFullURL(kEchoServerURL), &result, std::string());
666  ASSERT_TRUE(ws);
667  ASSERT_EQ(PP_OK, result);
668  result = websocket_interface_->ReceiveMessage(
669      ws, &receive_message_var,
670      callback.GetCallback().pp_completion_callback());
671  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
672  result = websocket_interface_->Close(
673      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(),
674      another_callback.GetCallback().pp_completion_callback());
675  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
676  callback.WaitForResult(PP_OK_COMPLETIONPENDING);
677  ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
678  another_callback.WaitForResult(PP_OK_COMPLETIONPENDING);
679  ASSERT_EQ(PP_OK, another_callback.result());
680  core_interface_->ReleaseResource(ws);
681
682  // Server initiated closing handshake.
683  ws = Connect(
684      GetFullURL(kCloseWithCodeAndReasonServerURL), &result, std::string());
685  ASSERT_TRUE(ws);
686  ASSERT_EQ(PP_OK, result);
687  // Text messsage "1000 bye" requests the server to initiate closing handshake
688  // with code being 1000 and reason being "bye".
689  PP_Var close_request_var = CreateVarString("1000 bye");
690  result = websocket_interface_->SendMessage(ws, close_request_var);
691  ReleaseVar(close_request_var);
692  callback.WaitForResult(websocket_interface_->ReceiveMessage(
693      ws, &receive_message_var,
694      callback.GetCallback().pp_completion_callback()));
695  ASSERT_EQ(PP_ERROR_FAILED, callback.result());
696  core_interface_->ReleaseResource(ws);
697
698  ReleaseVar(reason);
699  ReleaseVar(url);
700
701  PASS();
702}
703
704std::string TestWebSocket::TestGetProtocol() {
705  const char* expected_protocols[] = {
706    "x-chat",
707    "hoehoe",
708    NULL
709  };
710  for (int i = 0; expected_protocols[i]; ++i) {
711    std::string url(GetFullURL(kProtocolTestServerURL));
712    url += expected_protocols[i];
713    int32_t result;
714    PP_Resource ws = Connect(url.c_str(), &result, expected_protocols[i]);
715    ASSERT_TRUE(ws);
716    ASSERT_EQ(PP_OK, result);
717
718    PP_Var protocol = websocket_interface_->GetProtocol(ws);
719    ASSERT_TRUE(AreEqualWithString(protocol, expected_protocols[i]));
720
721    ReleaseVar(protocol);
722    core_interface_->ReleaseResource(ws);
723  }
724
725  PASS();
726}
727
728std::string TestWebSocket::TestTextSendReceive() {
729  // Connect to test echo server.
730  int32_t connect_result;
731  PP_Resource ws =
732      Connect(GetFullURL(kEchoServerURL), &connect_result, std::string());
733  ASSERT_TRUE(ws);
734  ASSERT_EQ(PP_OK, connect_result);
735
736  // Send 'hello pepper' text message.
737  const char* message = "hello pepper";
738  PP_Var message_var = CreateVarString(message);
739  int32_t result = websocket_interface_->SendMessage(ws, message_var);
740  ReleaseVar(message_var);
741  ASSERT_EQ(PP_OK, result);
742
743  // Receive echoed 'hello pepper'.
744  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
745  PP_Var received_message;
746  callback.WaitForResult(websocket_interface_->ReceiveMessage(
747      ws, &received_message, callback.GetCallback().pp_completion_callback()));
748  ASSERT_EQ(PP_OK, callback.result());
749  ASSERT_TRUE(AreEqualWithString(received_message, message));
750  ReleaseVar(received_message);
751  core_interface_->ReleaseResource(ws);
752
753  PASS();
754}
755
756// Run as a BACKGROUND test.
757std::string TestWebSocket::TestTextSendReceiveTwice() {
758  // Connect to test echo server.
759  int32_t connect_result;
760  PP_Resource ws =
761      Connect(GetFullURL(kEchoServerURL), &connect_result, std::string());
762  ASSERT_TRUE(ws);
763  ASSERT_EQ(PP_OK, connect_result);
764  pp::MessageLoop message_loop = pp::MessageLoop::GetCurrent();
765  pp::CompletionCallbackFactory<TestWebSocket> factory(this);
766
767  message_loop.PostWork(factory.NewCallback(&TestWebSocket::Send,
768                                            ws, std::string("hello")));
769  // When the server receives 'Goodbye', it closes the session.
770  message_loop.PostWork(factory.NewCallback(&TestWebSocket::Send,
771                                            ws, std::string("Goodbye")));
772  message_loop.PostQuit(false);
773  message_loop.Run();
774
775  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
776  PP_Var received_message;
777  int32_t result = websocket_interface_->ReceiveMessage(
778      ws, &received_message, callback.GetCallback().pp_completion_callback());
779  ASSERT_EQ(PP_OK, result);
780  // Since we don't run the message loop, the callback will stay
781  // "pending and scheduled to run" state.
782
783  // Waiting for the connection close which will be done by the server.
784  while (true) {
785    PP_WebSocketReadyState ready_state =
786        websocket_interface_->GetReadyState(ws);
787    if (ready_state != PP_WEBSOCKETREADYSTATE_CONNECTING &&
788        ready_state != PP_WEBSOCKETREADYSTATE_OPEN) {
789      break;
790    }
791    PlatformSleep(100);  // 100ms
792  }
793
794  // Cleanup the message loop
795  message_loop.PostQuit(false);
796  message_loop.Run();
797
798  ASSERT_EQ(PP_OK, callback.result());
799  ASSERT_TRUE(AreEqualWithString(received_message, "hello"));
800  ReleaseVar(received_message);
801  core_interface_->ReleaseResource(ws);
802  PASS();
803}
804
805std::string TestWebSocket::TestBinarySendReceive() {
806  // Connect to test echo server.
807  int32_t connect_result;
808  PP_Resource ws =
809      Connect(GetFullURL(kEchoServerURL), &connect_result, std::string());
810  ASSERT_TRUE(ws);
811  ASSERT_EQ(PP_OK, connect_result);
812
813  // Send binary message.
814  std::vector<uint8_t> binary(256);
815  for (uint32_t i = 0; i < binary.size(); ++i)
816    binary[i] = i;
817  PP_Var message_var = CreateVarBinary(binary);
818  int32_t result = websocket_interface_->SendMessage(ws, message_var);
819  ReleaseVar(message_var);
820  ASSERT_EQ(PP_OK, result);
821
822  // Receive echoed binary.
823  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
824  PP_Var received_message;
825  callback.WaitForResult(websocket_interface_->ReceiveMessage(
826      ws, &received_message, callback.GetCallback().pp_completion_callback()));
827  ASSERT_EQ(PP_OK, callback.result());
828  ASSERT_TRUE(AreEqualWithBinary(received_message, binary));
829  ReleaseVar(received_message);
830  core_interface_->ReleaseResource(ws);
831
832  PASS();
833}
834
835std::string TestWebSocket::TestStressedSendReceive() {
836  // Connect to test echo server.
837  int32_t connect_result;
838  PP_Resource ws =
839      Connect(GetFullURL(kEchoServerURL), &connect_result, std::string());
840  ASSERT_TRUE(ws);
841  ASSERT_EQ(PP_OK, connect_result);
842
843  // Prepare PP_Var objects to send.
844  const char* text = "hello pepper";
845  PP_Var text_var = CreateVarString(text);
846  std::vector<uint8_t> binary(256);
847  for (uint32_t i = 0; i < binary.size(); ++i)
848    binary[i] = i;
849  PP_Var binary_var = CreateVarBinary(binary);
850  // Prepare very large binary data over 64KiB. Object serializer in
851  // ppapi_proxy has a limitation of 64KiB as maximum return PP_Var data size
852  // to SRPC. In case received data over 64KiB exists, a specific code handles
853  // this large data via asynchronous callback from main thread. This data
854  // intends to test the code.
855  std::vector<uint8_t> large_binary(65 * 1024);
856  for (uint32_t i = 0; i < large_binary.size(); ++i)
857    large_binary[i] = i & 0xff;
858  PP_Var large_binary_var = CreateVarBinary(large_binary);
859
860  // Send many messages.
861  int32_t result;
862  for (int i = 0; i < 256; ++i) {
863    result = websocket_interface_->SendMessage(ws, text_var);
864    ASSERT_EQ(PP_OK, result);
865    result = websocket_interface_->SendMessage(ws, binary_var);
866    ASSERT_EQ(PP_OK, result);
867  }
868  result = websocket_interface_->SendMessage(ws, large_binary_var);
869  ASSERT_EQ(PP_OK, result);
870  ReleaseVar(text_var);
871  ReleaseVar(binary_var);
872  ReleaseVar(large_binary_var);
873
874  // Receive echoed data.
875  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
876  for (int i = 0; i <= 512; ++i) {
877    PP_Var received_message;
878    callback.WaitForResult(websocket_interface_->ReceiveMessage(
879        ws, &received_message,
880        callback.GetCallback().pp_completion_callback()));
881    ASSERT_EQ(PP_OK, callback.result());
882    if (i == 512) {
883      ASSERT_TRUE(AreEqualWithBinary(received_message, large_binary));
884    } else if (i & 1) {
885      ASSERT_TRUE(AreEqualWithBinary(received_message, binary));
886    } else {
887      ASSERT_TRUE(AreEqualWithString(received_message, text));
888    }
889    ReleaseVar(received_message);
890  }
891  core_interface_->ReleaseResource(ws);
892
893  PASS();
894}
895
896std::string TestWebSocket::TestBufferedAmount() {
897  // Connect to test echo server.
898  int32_t connect_result;
899  PP_Resource ws =
900      Connect(GetFullURL(kEchoServerURL), &connect_result, std::string());
901  ASSERT_TRUE(ws);
902  ASSERT_EQ(PP_OK, connect_result);
903
904  // Prepare a large message that is not aligned with the internal buffer
905  // sizes.
906  std::string message(8193, 'x');
907  PP_Var message_var = CreateVarString(message);
908
909  uint64_t buffered_amount = 0;
910  int32_t result;
911  for (int i = 0; i < 100; i++) {
912    result = websocket_interface_->SendMessage(ws, message_var);
913    ASSERT_EQ(PP_OK, result);
914    buffered_amount = websocket_interface_->GetBufferedAmount(ws);
915    // Buffered amount size 262144 is too big for the internal buffer size.
916    if (buffered_amount > 262144)
917      break;
918  }
919
920  // Close connection.
921  std::string reason_str = "close while busy";
922  PP_Var reason = CreateVarString(reason_str.c_str());
923  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
924  result = websocket_interface_->Close(
925      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason,
926      callback.GetCallback().pp_completion_callback());
927  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
928  ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING,
929      websocket_interface_->GetReadyState(ws));
930
931  callback.WaitForResult(result);
932  ASSERT_EQ(PP_OK, callback.result());
933  ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED,
934      websocket_interface_->GetReadyState(ws));
935
936  uint64_t base_buffered_amount = websocket_interface_->GetBufferedAmount(ws);
937
938  // After connection closure, all sending requests fail and just increase
939  // the bufferedAmount property.
940  PP_Var empty_string = CreateVarString(std::string());
941  result = websocket_interface_->SendMessage(ws, empty_string);
942  ASSERT_EQ(PP_ERROR_FAILED, result);
943  buffered_amount = websocket_interface_->GetBufferedAmount(ws);
944  ASSERT_EQ(base_buffered_amount + kMessageFrameOverhead, buffered_amount);
945  base_buffered_amount = buffered_amount;
946
947  result = websocket_interface_->SendMessage(ws, reason);
948  ASSERT_EQ(PP_ERROR_FAILED, result);
949  buffered_amount = websocket_interface_->GetBufferedAmount(ws);
950  uint64_t reason_frame_size = kMessageFrameOverhead + reason_str.length();
951  ASSERT_EQ(base_buffered_amount + reason_frame_size, buffered_amount);
952
953  ReleaseVar(message_var);
954  ReleaseVar(reason);
955  ReleaseVar(empty_string);
956  core_interface_->ReleaseResource(ws);
957
958  PASS();
959}
960
961// Test abort behaviors where a WebSocket PP_Resource is released while each
962// function is in-flight on the WebSocket PP_Resource.
963std::string TestWebSocket::TestAbortCallsWithCallback() {
964  // Following tests make sure the behavior for functions which require a
965  // callback. The callback must get a PP_ERROR_ABORTED.
966
967  // Test the behavior for Connect().
968  PP_Resource ws = websocket_interface_->Create(instance_->pp_instance());
969  ASSERT_TRUE(ws);
970  std::string url = GetFullURL(kEchoServerURL);
971  PP_Var url_var = CreateVarString(url);
972  TestCompletionCallback connect_callback(
973      instance_->pp_instance(), callback_type());
974  int32_t result = websocket_interface_->Connect(
975      ws, url_var, NULL, 0,
976      connect_callback.GetCallback().pp_completion_callback());
977  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
978  core_interface_->ReleaseResource(ws);
979  connect_callback.WaitForResult(result);
980  ASSERT_EQ(PP_ERROR_ABORTED, connect_callback.result());
981
982  // Test the behavior for Close().
983  ws = Connect(url, &result, std::string());
984  ASSERT_TRUE(ws);
985  ASSERT_EQ(PP_OK, result);
986  PP_Var reason_var = CreateVarString("abort");
987  TestCompletionCallback close_callback(
988      instance_->pp_instance(), callback_type());
989  result = websocket_interface_->Close(
990      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason_var,
991      close_callback.GetCallback().pp_completion_callback());
992  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
993  core_interface_->ReleaseResource(ws);
994  close_callback.WaitForResult(result);
995  ASSERT_EQ(PP_ERROR_ABORTED, close_callback.result());
996  ReleaseVar(reason_var);
997
998  // Test the behavior for ReceiveMessage().
999  // Make sure the simplest case to wait for data which never arrives, here.
1000  ws = Connect(url, &result, std::string());
1001  ASSERT_TRUE(ws);
1002  ASSERT_EQ(PP_OK, result);
1003  PP_Var receive_var;
1004  TestCompletionCallback receive_callback(
1005      instance_->pp_instance(), callback_type());
1006  result = websocket_interface_->ReceiveMessage(
1007      ws, &receive_var,
1008      receive_callback.GetCallback().pp_completion_callback());
1009  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1010  core_interface_->ReleaseResource(ws);
1011  receive_callback.WaitForResult(result);
1012  ASSERT_EQ(PP_ERROR_ABORTED, receive_callback.result());
1013
1014  // Release the resource in the aborting receive completion callback which is
1015  // introduced by calling Close().
1016  ws = Connect(url, &result, std::string());
1017  ASSERT_TRUE(ws);
1018  ASSERT_EQ(PP_OK, result);
1019  result = websocket_interface_->ReceiveMessage(
1020      ws, &receive_var,
1021      receive_callback.GetCallback().pp_completion_callback());
1022  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1023  ReleaseResourceDelegate receive_delegate(core_interface_, ws);
1024  receive_callback.SetDelegate(&receive_delegate);
1025  result = websocket_interface_->Close(
1026      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(),
1027      close_callback.GetCallback().pp_completion_callback());
1028  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1029  receive_callback.WaitForResult(result);
1030  CHECK_CALLBACK_BEHAVIOR(receive_callback);
1031  ASSERT_EQ(PP_ERROR_ABORTED, receive_callback.result());
1032  close_callback.WaitForResult(result);
1033  CHECK_CALLBACK_BEHAVIOR(close_callback);
1034  ASSERT_EQ(PP_ERROR_ABORTED, close_callback.result());
1035
1036  ReleaseVar(url_var);
1037
1038  PASS();
1039}
1040
1041std::string TestWebSocket::TestAbortSendMessageCall() {
1042  // Test the behavior for SendMessage().
1043  // This function doesn't require a callback, but operation will be done
1044  // asynchronously in WebKit and browser process.
1045  std::vector<uint8_t> large_binary(65 * 1024);
1046  PP_Var large_var = CreateVarBinary(large_binary);
1047
1048  int32_t result;
1049  std::string url = GetFullURL(kEchoServerURL);
1050  PP_Resource ws = Connect(url, &result, std::string());
1051  ASSERT_TRUE(ws);
1052  ASSERT_EQ(PP_OK, result);
1053  result = websocket_interface_->SendMessage(ws, large_var);
1054  ASSERT_EQ(PP_OK, result);
1055  core_interface_->ReleaseResource(ws);
1056  ReleaseVar(large_var);
1057
1058  PASS();
1059}
1060
1061std::string TestWebSocket::TestAbortCloseCall() {
1062  // Release the resource in the close completion callback.
1063  int32_t result;
1064  std::string url = GetFullURL(kEchoServerURL);
1065  PP_Resource ws = Connect(url, &result, std::string());
1066  ASSERT_TRUE(ws);
1067  ASSERT_EQ(PP_OK, result);
1068  TestCompletionCallback close_callback(
1069      instance_->pp_instance(), callback_type());
1070  result = websocket_interface_->Close(
1071      ws, PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, PP_MakeUndefined(),
1072      close_callback.GetCallback().pp_completion_callback());
1073  ReleaseResourceDelegate close_delegate(core_interface_, ws);
1074  close_callback.SetDelegate(&close_delegate);
1075  close_callback.WaitForResult(result);
1076  CHECK_CALLBACK_BEHAVIOR(close_callback);
1077  ASSERT_EQ(PP_OK, close_callback.result());
1078
1079  PASS();
1080}
1081
1082std::string TestWebSocket::TestAbortReceiveMessageCall() {
1083  // Test the behavior where receive process might be in-flight.
1084  std::vector<uint8_t> large_binary(65 * 1024);
1085  PP_Var large_var = CreateVarBinary(large_binary);
1086  const char* text = "yukarin";
1087  PP_Var text_var = CreateVarString(text);
1088
1089  std::string url = GetFullURL(kEchoServerURL);
1090  int32_t result;
1091  PP_Resource ws;
1092
1093  // Each trial sends |trial_count| + 1 messages and receives just |trial|
1094  // number of message(s) before releasing the WebSocket. The WebSocket is
1095  // released while the next message is going to be received.
1096  const int trial_count = 8;
1097  for (int trial = 1; trial <= trial_count; trial++) {
1098    ws = Connect(url, &result, std::string());
1099    ASSERT_TRUE(ws);
1100    ASSERT_EQ(PP_OK, result);
1101    for (int i = 0; i <= trial_count; ++i) {
1102      result = websocket_interface_->SendMessage(ws, text_var);
1103      ASSERT_EQ(PP_OK, result);
1104    }
1105    TestCompletionCallback callback(instance_->pp_instance(), callback_type());
1106    PP_Var var;
1107    for (int i = 0; i < trial; ++i) {
1108      callback.WaitForResult(websocket_interface_->ReceiveMessage(
1109          ws, &var, callback.GetCallback().pp_completion_callback()));
1110      ASSERT_EQ(PP_OK, callback.result());
1111      ASSERT_TRUE(AreEqualWithString(var, text));
1112      ReleaseVar(var);
1113    }
1114    result = websocket_interface_->ReceiveMessage(
1115        ws, &var, callback.GetCallback().pp_completion_callback());
1116    core_interface_->ReleaseResource(ws);
1117    if (result != PP_OK) {
1118      callback.WaitForResult(result);
1119      ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
1120    }
1121  }
1122  // Same test, but the last receiving message is large message over 64KiB.
1123  for (int trial = 1; trial <= trial_count; trial++) {
1124    ws = Connect(url, &result, std::string());
1125    ASSERT_TRUE(ws);
1126    ASSERT_EQ(PP_OK, result);
1127    for (int i = 0; i <= trial_count; ++i) {
1128      if (i == trial)
1129        result = websocket_interface_->SendMessage(ws, large_var);
1130      else
1131        result = websocket_interface_->SendMessage(ws, text_var);
1132      ASSERT_EQ(PP_OK, result);
1133    }
1134    TestCompletionCallback callback(instance_->pp_instance(), callback_type());
1135    PP_Var var;
1136    for (int i = 0; i < trial; ++i) {
1137      callback.WaitForResult(websocket_interface_->ReceiveMessage(
1138          ws, &var, callback.GetCallback().pp_completion_callback()));
1139      ASSERT_EQ(PP_OK, callback.result());
1140      ASSERT_TRUE(AreEqualWithString(var, text));
1141      ReleaseVar(var);
1142    }
1143    result = websocket_interface_->ReceiveMessage(
1144        ws, &var, callback.GetCallback().pp_completion_callback());
1145    core_interface_->ReleaseResource(ws);
1146    if (result != PP_OK) {
1147      callback.WaitForResult(result);
1148      ASSERT_EQ(PP_ERROR_ABORTED, callback.result());
1149    }
1150  }
1151
1152  ReleaseVar(large_var);
1153  ReleaseVar(text_var);
1154
1155  PASS();
1156}
1157
1158std::string TestWebSocket::TestCcInterfaces() {
1159  // C++ bindings is simple straightforward, then just verifies interfaces work
1160  // as a interface bridge fine.
1161  pp::WebSocket ws(instance_);
1162
1163  // Check uninitialized properties access.
1164  ASSERT_EQ(0, ws.GetBufferedAmount());
1165  ASSERT_EQ(0, ws.GetCloseCode());
1166  ASSERT_TRUE(AreEqualWithString(ws.GetCloseReason().pp_var(), std::string()));
1167  ASSERT_EQ(false, ws.GetCloseWasClean());
1168  ASSERT_TRUE(AreEqualWithString(ws.GetExtensions().pp_var(), std::string()));
1169  ASSERT_TRUE(AreEqualWithString(ws.GetProtocol().pp_var(), std::string()));
1170  ASSERT_EQ(PP_WEBSOCKETREADYSTATE_INVALID, ws.GetReadyState());
1171  ASSERT_TRUE(AreEqualWithString(ws.GetURL().pp_var(), std::string()));
1172
1173  // Check communication interfaces (connect, send, receive, and close).
1174  TestCompletionCallback connect_callback(
1175      instance_->pp_instance(), callback_type());
1176  connect_callback.WaitForResult(ws.Connect(
1177      pp::Var(GetFullURL(kCloseServerURL)), NULL, 0U,
1178              connect_callback.GetCallback()));
1179  CHECK_CALLBACK_BEHAVIOR(connect_callback);
1180  ASSERT_EQ(PP_OK, connect_callback.result());
1181
1182  std::string text_message("hello C++");
1183  int32_t result = ws.SendMessage(pp::Var(text_message));
1184  ASSERT_EQ(PP_OK, result);
1185
1186  std::vector<uint8_t> binary(256);
1187  for (uint32_t i = 0; i < binary.size(); ++i)
1188    binary[i] = i;
1189  result = ws.SendMessage(
1190      pp::Var(pp::PASS_REF, CreateVarBinary(binary)));
1191  ASSERT_EQ(PP_OK, result);
1192
1193  pp::Var text_receive_var;
1194  TestCompletionCallback text_receive_callback(
1195      instance_->pp_instance(), callback_type());
1196  text_receive_callback.WaitForResult(
1197      ws.ReceiveMessage(&text_receive_var,
1198                        text_receive_callback.GetCallback()));
1199  ASSERT_EQ(PP_OK, text_receive_callback.result());
1200  ASSERT_TRUE(
1201      AreEqualWithString(text_receive_var.pp_var(), text_message.c_str()));
1202
1203  pp::Var binary_receive_var;
1204  TestCompletionCallback binary_receive_callback(
1205      instance_->pp_instance(), callback_type());
1206  binary_receive_callback.WaitForResult(
1207      ws.ReceiveMessage(&binary_receive_var,
1208                        binary_receive_callback.GetCallback()));
1209  ASSERT_EQ(PP_OK, binary_receive_callback.result());
1210  ASSERT_TRUE(AreEqualWithBinary(binary_receive_var.pp_var(), binary));
1211
1212  TestCompletionCallback close_callback(
1213      instance_->pp_instance(), callback_type());
1214  std::string reason("bye");
1215  close_callback.WaitForResult(ws.Close(
1216      PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason),
1217      close_callback.GetCallback()));
1218  CHECK_CALLBACK_BEHAVIOR(close_callback);
1219  ASSERT_EQ(PP_OK, close_callback.result());
1220
1221  // Check initialized properties access.
1222  ASSERT_EQ(0, ws.GetBufferedAmount());
1223  ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, ws.GetCloseCode());
1224  ASSERT_TRUE(
1225      AreEqualWithString(ws.GetCloseReason().pp_var(), reason.c_str()));
1226  ASSERT_EQ(true, ws.GetCloseWasClean());
1227  ASSERT_TRUE(AreEqualWithString(ws.GetProtocol().pp_var(), std::string()));
1228  ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED, ws.GetReadyState());
1229  ASSERT_TRUE(AreEqualWithString(
1230      ws.GetURL().pp_var(), GetFullURL(kCloseServerURL).c_str()));
1231
1232  PASS();
1233}
1234
1235std::string TestWebSocket::TestUtilityInvalidConnect() {
1236  const pp::Var protocols[] = { pp::Var() };
1237
1238  TestWebSocketAPI websocket(instance_);
1239  int32_t result = websocket.Connect(pp::Var(), protocols, 1U);
1240  ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
1241  ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1242
1243  result = websocket.Connect(pp::Var(), protocols, 1U);
1244  ASSERT_EQ(PP_ERROR_INPROGRESS, result);
1245  ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1246
1247  for (int i = 0; kInvalidURLs[i]; ++i) {
1248    TestWebSocketAPI ws(instance_);
1249    result = ws.Connect(pp::Var(std::string(kInvalidURLs[i])), protocols, 0U);
1250    if (result == PP_OK_COMPLETIONPENDING) {
1251      ws.WaitForClosed();
1252      const std::vector<WebSocketEvent>& events = ws.GetSeenEvents();
1253      ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type);
1254      ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
1255      ASSERT_EQ(2U, ws.GetSeenEvents().size());
1256    } else {
1257      ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
1258      ASSERT_EQ(0U, ws.GetSeenEvents().size());
1259    }
1260  }
1261
1262  PASS();
1263}
1264
1265std::string TestWebSocket::TestUtilityProtocols() {
1266  const pp::Var bad_protocols[] = {
1267      pp::Var(std::string("x-test")), pp::Var(std::string("x-test")) };
1268  const pp::Var good_protocols[] = {
1269      pp::Var(std::string("x-test")), pp::Var(std::string("x-yatest")) };
1270
1271  {
1272    TestWebSocketAPI websocket(instance_);
1273    int32_t result = websocket.Connect(
1274        pp::Var(GetFullURL(kEchoServerURL)), bad_protocols, 2U);
1275    ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
1276    ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1277  }
1278
1279  {
1280    TestWebSocketAPI websocket(instance_);
1281    int32_t result = websocket.Connect(
1282        pp::Var(GetFullURL(kEchoServerURL)), good_protocols, 2U);
1283    ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1284    websocket.WaitForConnected();
1285    const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1286    // Protocol arguments are valid, but this test run without a WebSocket
1287    // server. As a result, OnError() and OnClose() are invoked because of
1288    // a connection establishment failure.
1289    ASSERT_EQ(2U, events.size());
1290    ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type);
1291    ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
1292    ASSERT_FALSE(events[1].was_clean);
1293  }
1294
1295  PASS();
1296}
1297
1298std::string TestWebSocket::TestUtilityGetURL() {
1299  const pp::Var protocols[] = { pp::Var() };
1300
1301  for (int i = 0; kInvalidURLs[i]; ++i) {
1302    TestWebSocketAPI websocket(instance_);
1303    int32_t result = websocket.Connect(
1304        pp::Var(std::string(kInvalidURLs[i])), protocols, 0U);
1305    if (result == PP_OK_COMPLETIONPENDING) {
1306      websocket.WaitForClosed();
1307      const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1308      ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type);
1309      ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
1310      ASSERT_EQ(2U, events.size());
1311    } else {
1312      ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
1313      ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1314    }
1315    pp::Var url = websocket.GetURL();
1316    ASSERT_TRUE(AreEqualWithString(url.pp_var(), kInvalidURLs[i]));
1317  }
1318
1319  PASS();
1320}
1321
1322std::string TestWebSocket::TestUtilityValidConnect() {
1323  const pp::Var protocols[] = { pp::Var() };
1324  TestWebSocketAPI websocket(instance_);
1325  int32_t result = websocket.Connect(
1326      pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1327  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1328  websocket.WaitForConnected();
1329  const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1330  ASSERT_EQ(1U, events.size());
1331  ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1332  ASSERT_TRUE(
1333      AreEqualWithString(websocket.GetExtensions().pp_var(), std::string()));
1334
1335  PASS();
1336}
1337
1338std::string TestWebSocket::TestUtilityInvalidClose() {
1339  const pp::Var reason = pp::Var(std::string("close for test"));
1340
1341  // Close before connect.
1342  {
1343    TestWebSocketAPI websocket(instance_);
1344    int32_t result = websocket.Close(
1345        PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, reason);
1346    ASSERT_EQ(PP_ERROR_FAILED, result);
1347    ASSERT_EQ(0U, websocket.GetSeenEvents().size());
1348  }
1349
1350  // Close with bad arguments.
1351  {
1352    TestWebSocketAPI websocket(instance_);
1353    int32_t result = websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)),
1354        NULL, 0);
1355    ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1356    websocket.WaitForConnected();
1357    result = websocket.Close(1U, reason);
1358    ASSERT_EQ(PP_ERROR_NOACCESS, result);
1359    const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1360    ASSERT_EQ(1U, events.size());
1361    ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1362  }
1363
1364  PASS();
1365}
1366
1367std::string TestWebSocket::TestUtilityValidClose() {
1368  std::string reason("close for test");
1369  pp::Var url = pp::Var(GetFullURL(kCloseServerURL));
1370
1371  // Close.
1372  {
1373    TestWebSocketAPI websocket(instance_);
1374    int32_t result = websocket.Connect(url, NULL, 0U);
1375    ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1376    websocket.WaitForConnected();
1377    result = websocket.Close(
1378        PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1379    ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1380    websocket.WaitForClosed();
1381    const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1382    ASSERT_EQ(2U, events.size());
1383    ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1384    ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type);
1385    ASSERT_TRUE(events[1].was_clean);
1386    ASSERT_EQ(PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, events[1].close_code);
1387    ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), reason.c_str()));
1388  }
1389
1390  // Close in connecting.
1391  // The ongoing connect failed with PP_ERROR_ABORTED, then the close is done
1392  // successfully.
1393  {
1394    TestWebSocketAPI websocket(instance_);
1395    int32_t result = websocket.Connect(url, NULL, 0U);
1396    ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1397    result = websocket.Close(
1398        PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1399    ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1400    websocket.WaitForClosed();
1401    const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1402    ASSERT_TRUE(events.size() == 2 || events.size() == 3);
1403    int index = 0;
1404    if (events.size() == 3)
1405      ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[index++].event_type);
1406    ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[index++].event_type);
1407    ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[index].event_type);
1408    ASSERT_FALSE(events[index].was_clean);
1409  }
1410
1411  // Close in closing.
1412  // The first close will be done successfully, then the second one failed with
1413  // with PP_ERROR_INPROGRESS immediately.
1414  {
1415    TestWebSocketAPI websocket(instance_);
1416    int32_t result = websocket.Connect(url, NULL, 0U);
1417    result = websocket.Close(
1418        PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1419    ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1420    result = websocket.Close(
1421        PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1422    ASSERT_EQ(PP_ERROR_INPROGRESS, result);
1423    websocket.WaitForClosed();
1424    const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1425    ASSERT_TRUE(events.size() == 2 || events.size() == 3);
1426    int index = 0;
1427    if (events.size() == 3)
1428      ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[index++].event_type);
1429    ASSERT_EQ(WebSocketEvent::EVENT_ERROR, events[index++].event_type);
1430    ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[index].event_type);
1431    ASSERT_FALSE(events[index].was_clean);
1432  }
1433
1434  PASS();
1435}
1436
1437std::string TestWebSocket::TestUtilityGetProtocol() {
1438  const std::string protocol("x-chat");
1439  const pp::Var protocols[] = { pp::Var(protocol) };
1440  std::string url(GetFullURL(kProtocolTestServerURL));
1441  url += protocol;
1442  TestWebSocketAPI websocket(instance_);
1443  int32_t result = websocket.Connect(pp::Var(url), protocols, 1U);
1444  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1445  websocket.WaitForReceived();
1446  ASSERT_TRUE(AreEqualWithString(
1447      websocket.GetProtocol().pp_var(), protocol.c_str()));
1448  const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1449  // The server to which this test connect returns the decided protocol as a
1450  // text frame message. So the WebSocketEvent records EVENT_MESSAGE event
1451  // after EVENT_OPEN event.
1452  ASSERT_EQ(2U, events.size());
1453  ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1454  ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type);
1455  ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), protocol.c_str()));
1456
1457  PASS();
1458}
1459
1460std::string TestWebSocket::TestUtilityTextSendReceive() {
1461  const pp::Var protocols[] = { pp::Var() };
1462  TestWebSocketAPI websocket(instance_);
1463  int32_t result =
1464      websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1465  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1466  websocket.WaitForConnected();
1467
1468  // Send 'hello pepper'.
1469  std::string message1("hello pepper");
1470  result = websocket.Send(pp::Var(std::string(message1)));
1471  ASSERT_EQ(PP_OK, result);
1472
1473  // Receive echoed 'hello pepper'.
1474  websocket.WaitForReceived();
1475
1476  // Send 'goodbye pepper'.
1477  std::string message2("goodbye pepper");
1478  result = websocket.Send(pp::Var(std::string(message2)));
1479
1480  // Receive echoed 'goodbye pepper'.
1481  websocket.WaitForReceived();
1482
1483  const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1484  ASSERT_EQ(3U, events.size());
1485  ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1486  ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type);
1487  ASSERT_TRUE(AreEqualWithString(events[1].var.pp_var(), message1.c_str()));
1488  ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[2].event_type);
1489  ASSERT_TRUE(AreEqualWithString(events[2].var.pp_var(), message2.c_str()));
1490
1491  PASS();
1492}
1493
1494std::string TestWebSocket::TestUtilityBinarySendReceive() {
1495  const pp::Var protocols[] = { pp::Var() };
1496  TestWebSocketAPI websocket(instance_);
1497  int32_t result =
1498      websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1499  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1500  websocket.WaitForConnected();
1501
1502  // Send binary message.
1503  uint32_t len = 256;
1504  std::vector<uint8_t> binary(len);
1505  for (uint32_t i = 0; i < len; ++i)
1506    binary[i] = i;
1507  pp::VarArrayBuffer message(len);
1508  uint8_t* var_data = static_cast<uint8_t*>(message.Map());
1509  std::copy(binary.begin(), binary.end(), var_data);
1510  result = websocket.Send(message);
1511  ASSERT_EQ(PP_OK, result);
1512
1513  // Receive echoed binary message.
1514  websocket.WaitForReceived();
1515
1516  const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1517  ASSERT_EQ(2U, events.size());
1518  ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1519  ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type);
1520  ASSERT_TRUE(AreEqualWithBinary(events[1].var.pp_var(), binary));
1521
1522  PASS();
1523}
1524
1525std::string TestWebSocket::TestUtilityBufferedAmount() {
1526  // Connect to test echo server.
1527  const pp::Var protocols[] = { pp::Var() };
1528  TestWebSocketAPI websocket(instance_);
1529  int32_t result =
1530      websocket.Connect(pp::Var(GetFullURL(kEchoServerURL)), protocols, 0U);
1531  ASSERT_EQ(PP_OK_COMPLETIONPENDING, result);
1532  websocket.WaitForConnected();
1533
1534  // Prepare a large message that is not aligned with the internal buffer
1535  // sizes.
1536  std::string message(8193, 'x');
1537  uint64_t buffered_amount = 0;
1538  uint32_t sent;
1539  for (sent = 0; sent < 100; sent++) {
1540    result = websocket.Send(pp::Var(message));
1541    ASSERT_EQ(PP_OK, result);
1542    buffered_amount = websocket.GetBufferedAmount();
1543    // Buffered amount size 262144 is too big for the internal buffer size.
1544    if (buffered_amount > 262144)
1545      break;
1546  }
1547
1548  // Close connection.
1549  std::string reason = "close while busy";
1550  result = websocket.Close(
1551      PP_WEBSOCKETSTATUSCODE_NORMAL_CLOSURE, pp::Var(reason));
1552  ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSING, websocket.GetReadyState());
1553  websocket.WaitForClosed();
1554  ASSERT_EQ(PP_WEBSOCKETREADYSTATE_CLOSED, websocket.GetReadyState());
1555
1556  uint64_t base_buffered_amount = websocket.GetBufferedAmount();
1557  size_t events_on_closed = websocket.GetSeenEvents().size();
1558
1559  // After connection closure, all sending requests fail and just increase
1560  // the bufferedAmount property.
1561  result = websocket.Send(pp::Var(std::string()));
1562  ASSERT_EQ(PP_ERROR_FAILED, result);
1563  buffered_amount = websocket.GetBufferedAmount();
1564  ASSERT_EQ(base_buffered_amount + kMessageFrameOverhead, buffered_amount);
1565  base_buffered_amount = buffered_amount;
1566
1567  result = websocket.Send(pp::Var(reason));
1568  ASSERT_EQ(PP_ERROR_FAILED, result);
1569  buffered_amount = websocket.GetBufferedAmount();
1570  uint64_t reason_frame_size = kMessageFrameOverhead + reason.length();
1571  ASSERT_EQ(base_buffered_amount + reason_frame_size, buffered_amount);
1572
1573  const std::vector<WebSocketEvent>& events = websocket.GetSeenEvents();
1574  ASSERT_EQ(events_on_closed, events.size());
1575  ASSERT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type);
1576  size_t last_event = events_on_closed - 1;
1577  for (uint32_t i = 1; i < last_event; ++i) {
1578    ASSERT_EQ(WebSocketEvent::EVENT_MESSAGE, events[i].event_type);
1579    ASSERT_TRUE(AreEqualWithString(events[i].var.pp_var(), message));
1580  }
1581  ASSERT_EQ(WebSocketEvent::EVENT_CLOSE, events[last_event].event_type);
1582  ASSERT_TRUE(events[last_event].was_clean);
1583
1584  PASS();
1585}
1586