Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / net / websockets / websocket_job_test.cc
index 31bd9d6..c84af8f 100644 (file)
@@ -41,30 +41,27 @@ namespace {
 
 class MockSocketStream : public SocketStream {
  public:
-  MockSocketStream(const GURL& url, SocketStream::Delegate* delegate)
-      : SocketStream(url, delegate) {}
+  MockSocketStream(const GURL& url, SocketStream::Delegate* delegate,
+                   URLRequestContext* context, CookieStore* cookie_store)
+      : SocketStream(url, delegate, context, cookie_store) {}
 
-  virtual void Connect() OVERRIDE {}
-  virtual bool SendData(const char* data, int len) OVERRIDE {
+  void Connect() override {}
+  bool SendData(const char* data, int len) override {
     sent_data_ += std::string(data, len);
     return true;
   }
 
-  virtual void Close() OVERRIDE {}
-  virtual void RestartWithAuth(
-      const AuthCredentials& credentials) OVERRIDE {
-  }
+  void Close() override {}
+  void RestartWithAuth(const AuthCredentials& credentials) override {}
 
-  virtual void DetachDelegate() OVERRIDE {
-    delegate_ = NULL;
-  }
+  void DetachDelegate() override { delegate_ = NULL; }
 
   const std::string& sent_data() const {
     return sent_data_;
   }
 
  protected:
-  virtual ~MockSocketStream() {}
+  ~MockSocketStream() override {}
 
  private:
   std::string sent_data_;
@@ -77,7 +74,7 @@ class MockSocketStreamDelegate : public SocketStream::Delegate {
   void set_allow_all_cookies(bool allow_all_cookies) {
     allow_all_cookies_ = allow_all_cookies;
   }
-  virtual ~MockSocketStreamDelegate() {}
+  ~MockSocketStreamDelegate() override {}
 
   void SetOnStartOpenConnection(const base::Closure& callback) {
     on_start_open_connection_ = callback;
@@ -95,42 +92,40 @@ class MockSocketStreamDelegate : public SocketStream::Delegate {
     on_close_ = callback;
   }
 
-  virtual int OnStartOpenConnection(
-      SocketStream* socket,
-      const CompletionCallback& callback) OVERRIDE {
+  int OnStartOpenConnection(SocketStream* socket,
+                            const CompletionCallback& callback) override {
     if (!on_start_open_connection_.is_null())
       on_start_open_connection_.Run();
     return OK;
   }
-  virtual void OnConnected(SocketStream* socket,
-                           int max_pending_send_allowed) OVERRIDE {
+  void OnConnected(SocketStream* socket,
+                   int max_pending_send_allowed) override {
     if (!on_connected_.is_null())
       on_connected_.Run();
   }
-  virtual void OnSentData(SocketStream* socket,
-                          int amount_sent) OVERRIDE {
+  void OnSentData(SocketStream* socket, int amount_sent) override {
     amount_sent_ += amount_sent;
     if (!on_sent_data_.is_null())
       on_sent_data_.Run();
   }
-  virtual void OnReceivedData(SocketStream* socket,
-                              const char* data, int len) OVERRIDE {
+  void OnReceivedData(SocketStream* socket,
+                      const char* data,
+                      int len) override {
     received_data_ += std::string(data, len);
     if (!on_received_data_.is_null())
       on_received_data_.Run();
   }
-  virtual void OnClose(SocketStream* socket) OVERRIDE {
+  void OnClose(SocketStream* socket) override {
     if (!on_close_.is_null())
       on_close_.Run();
   }
-  virtual bool CanGetCookies(SocketStream* socket,
-                             const GURL& url) OVERRIDE {
+  bool CanGetCookies(SocketStream* socket, const GURL& url) override {
     return allow_all_cookies_;
   }
-  virtual bool CanSetCookie(SocketStream* request,
-                            const GURL& url,
-                            const std::string& cookie_line,
-                            CookieOptions* options) OVERRIDE {
+  bool CanSetCookie(SocketStream* request,
+                    const GURL& url,
+                    const std::string& cookie_line,
+                    CookieOptions* options) override {
     return allow_all_cookies_;
   }
 
@@ -185,66 +180,76 @@ class MockCookieStore : public CookieStore {
   }
 
   // CookieStore:
-  virtual void SetCookieWithOptionsAsync(
-      const GURL& url,
-      const std::string& cookie_line,
-      const CookieOptions& options,
-      const SetCookiesCallback& callback) OVERRIDE {
+  void SetCookieWithOptionsAsync(const GURL& url,
+                                 const std::string& cookie_line,
+                                 const CookieOptions& options,
+                                 const SetCookiesCallback& callback) override {
     bool result = SetCookieWithOptions(url, cookie_line, options);
     if (!callback.is_null())
       callback.Run(result);
   }
 
-  virtual void GetCookiesWithOptionsAsync(
-      const GURL& url,
-      const CookieOptions& options,
-      const GetCookiesCallback& callback) OVERRIDE {
+  void GetCookiesWithOptionsAsync(const GURL& url,
+                                  const CookieOptions& options,
+                                  const GetCookiesCallback& callback) override {
     if (!callback.is_null())
       callback.Run(GetCookiesWithOptions(url, options));
   }
 
-  virtual void DeleteCookieAsync(const GURL& url,
-                                 const std::string& cookie_name,
-                                 const base::Closure& callback) OVERRIDE {
+  void GetAllCookiesForURLAsync(
+      const GURL& url,
+      const GetCookieListCallback& callback) override {
+    ADD_FAILURE();
+  }
+
+  void DeleteCookieAsync(const GURL& url,
+                         const std::string& cookie_name,
+                         const base::Closure& callback) override {
     ADD_FAILURE();
   }
 
-  virtual void DeleteAllCreatedBetweenAsync(
-      const base::Time& delete_begin,
-      const base::Time& delete_end,
-      const DeleteCallback& callback) OVERRIDE {
+  void DeleteAllCreatedBetweenAsync(const base::Time& delete_begin,
+                                    const base::Time& delete_end,
+                                    const DeleteCallback& callback) override {
     ADD_FAILURE();
   }
 
-  virtual void DeleteAllCreatedBetweenForHostAsync(
+  void DeleteAllCreatedBetweenForHostAsync(
       const base::Time delete_begin,
       const base::Time delete_end,
       const GURL& url,
-      const DeleteCallback& callback) OVERRIDE {
+      const DeleteCallback& callback) override {
     ADD_FAILURE();
   }
 
-  virtual void DeleteSessionCookiesAsync(const DeleteCallback&) OVERRIDE {
+  void DeleteSessionCookiesAsync(const DeleteCallback&) override {
     ADD_FAILURE();
   }
 
-  virtual CookieMonster* GetCookieMonster() OVERRIDE { return NULL; }
+  CookieMonster* GetCookieMonster() override { return NULL; }
+
+  scoped_ptr<CookieStore::CookieChangedSubscription>
+  AddCallbackForCookie(const GURL& url, const std::string& name,
+                       const CookieChangedCallback& callback) override {
+    ADD_FAILURE();
+    return scoped_ptr<CookieChangedSubscription>();
+  }
 
   const std::vector<Entry>& entries() const { return entries_; }
 
  private:
   friend class base::RefCountedThreadSafe<MockCookieStore>;
-  virtual ~MockCookieStore() {}
+  ~MockCookieStore() override {}
 
   std::vector<Entry> entries_;
 };
 
 class MockSSLConfigService : public SSLConfigService {
  public:
-  virtual void GetSSLConfig(SSLConfig* config) OVERRIDE {}
+  void GetSSLConfig(SSLConfig* config) override {}
 
  protected:
-  virtual ~MockSSLConfigService() {}
+  ~MockSSLConfigService() override {}
 };
 
 class MockURLRequestContext : public URLRequestContext {
@@ -259,7 +264,7 @@ class MockURLRequestContext : public URLRequestContext {
                                       include_subdomains);
   }
 
-  virtual ~MockURLRequestContext() {}
+  ~MockURLRequestContext() override { AssertNoURLRequests(); }
 
  private:
   TransportSecurityState transport_security_state_;
@@ -267,11 +272,14 @@ class MockURLRequestContext : public URLRequestContext {
 
 class MockHttpTransactionFactory : public HttpTransactionFactory {
  public:
-  MockHttpTransactionFactory(NextProto next_proto, OrderedSocketData* data) {
+  MockHttpTransactionFactory(NextProto next_proto,
+                             OrderedSocketData* data,
+                             bool enable_websocket_over_spdy) {
     data_ = data;
     MockConnect connect_data(SYNCHRONOUS, OK);
     data_->set_connect_data(connect_data);
     session_deps_.reset(new SpdySessionDependencies(next_proto));
+    session_deps_->enable_websocket_over_spdy = enable_websocket_over_spdy;
     session_deps_->socket_factory->AddSocketDataProvider(data_);
     http_session_ =
         SpdySessionDependencies::SpdyCreateSession(session_deps_.get());
@@ -279,26 +287,23 @@ class MockHttpTransactionFactory : public HttpTransactionFactory {
     host_port_pair_.set_port(80);
     spdy_session_key_ = SpdySessionKey(host_port_pair_,
                                             ProxyServer::Direct(),
-                                            kPrivacyModeDisabled);
+                                            PRIVACY_MODE_DISABLED);
     session_ = CreateInsecureSpdySession(
         http_session_, spdy_session_key_, BoundNetLog());
   }
 
-  virtual int CreateTransaction(
-      RequestPriority priority,
-      scoped_ptr<HttpTransaction>* trans) OVERRIDE {
+  int CreateTransaction(RequestPriority priority,
+                        scoped_ptr<HttpTransaction>* trans) override {
     NOTREACHED();
     return ERR_UNEXPECTED;
   }
 
-  virtual HttpCache* GetCache() OVERRIDE {
+  HttpCache* GetCache() override {
     NOTREACHED();
     return NULL;
   }
 
-  virtual HttpNetworkSession* GetSession() OVERRIDE {
-    return http_session_.get();
-  }
+  HttpNetworkSession* GetSession() override { return http_session_.get(); }
 
  private:
   OrderedSocketData* data_;
@@ -309,19 +314,89 @@ class MockHttpTransactionFactory : public HttpTransactionFactory {
   SpdySessionKey spdy_session_key_;
 };
 
+class DeletingSocketStreamDelegate : public SocketStream::Delegate {
+ public:
+  DeletingSocketStreamDelegate()
+      : delete_next_(false) {}
+
+  // Since this class needs to be able to delete |job_|, it must be the only
+  // reference holder (except for temporary references). Provide access to the
+  // pointer for tests to use.
+  WebSocketJob* job() { return job_.get(); }
+
+  void set_job(WebSocketJob* job) { job_ = job; }
+
+  // After calling this, the next call to a method on this delegate will delete
+  // the WebSocketJob object.
+  void set_delete_next(bool delete_next) { delete_next_ = delete_next; }
+
+  void DeleteJobMaybe() {
+    if (delete_next_) {
+      job_->DetachContext();
+      job_->DetachDelegate();
+      job_ = NULL;
+    }
+  }
+
+  // SocketStream::Delegate implementation
+
+  // OnStartOpenConnection() is not implemented by SocketStreamDispatcherHost
+
+  void OnConnected(SocketStream* socket,
+                   int max_pending_send_allowed) override {
+    DeleteJobMaybe();
+  }
+
+  void OnSentData(SocketStream* socket, int amount_sent) override {
+    DeleteJobMaybe();
+  }
+
+  void OnReceivedData(SocketStream* socket,
+                      const char* data,
+                      int len) override {
+    DeleteJobMaybe();
+  }
+
+  void OnClose(SocketStream* socket) override { DeleteJobMaybe(); }
+
+  void OnAuthRequired(SocketStream* socket,
+                      AuthChallengeInfo* auth_info) override {
+    DeleteJobMaybe();
+  }
+
+  void OnSSLCertificateError(SocketStream* socket,
+                             const SSLInfo& ssl_info,
+                             bool fatal) override {
+    DeleteJobMaybe();
+  }
+
+  void OnError(const SocketStream* socket, int error) override {
+    DeleteJobMaybe();
+  }
+
+  // CanGetCookies() and CanSetCookies() do not appear to be able to delete the
+  // WebSocketJob object.
+
+ private:
+  scoped_refptr<WebSocketJob> job_;
+  bool delete_next_;
+};
+
 }  // namespace
 
 class WebSocketJobTest : public PlatformTest,
                          public ::testing::WithParamInterface<NextProto> {
  public:
-  WebSocketJobTest() : spdy_util_(GetParam()) {}
+  WebSocketJobTest()
+      : spdy_util_(GetParam()),
+        enable_websocket_over_spdy_(false) {}
 
-  virtual void SetUp() OVERRIDE {
+  void SetUp() override {
     stream_type_ = STREAM_INVALID;
     cookie_store_ = new MockCookieStore;
     context_.reset(new MockURLRequestContext(cookie_store_.get()));
   }
-  virtual void TearDown() OVERRIDE {
+  void TearDown() override {
     cookie_store_ = NULL;
     context_.reset();
     websocket_ = NULL;
@@ -341,6 +416,7 @@ class WebSocketJobTest : public PlatformTest,
   int WaitForResult() {
     return sync_test_callback_.WaitForResult();
   }
+
  protected:
   enum StreamType {
     STREAM_INVALID,
@@ -364,12 +440,13 @@ class WebSocketJobTest : public PlatformTest,
     websocket_ = new WebSocketJob(delegate);
 
     if (stream_type == STREAM_MOCK_SOCKET)
-      socket_ = new MockSocketStream(url, websocket_.get());
+      socket_ = new MockSocketStream(url, websocket_.get(), context_.get(),
+                                     NULL);
 
     if (stream_type == STREAM_SOCKET || stream_type == STREAM_SPDY_WEBSOCKET) {
       if (stream_type == STREAM_SPDY_WEBSOCKET) {
-        http_factory_.reset(
-            new MockHttpTransactionFactory(GetParam(), data_.get()));
+        http_factory_.reset(new MockHttpTransactionFactory(
+            GetParam(), data_.get(), enable_websocket_over_spdy_));
         context_->set_http_transaction_factory(http_factory_.get());
       }
 
@@ -380,7 +457,7 @@ class WebSocketJobTest : public PlatformTest,
       host_resolver_.reset(new MockHostResolver);
       context_->set_host_resolver(host_resolver_.get());
 
-      socket_ = new SocketStream(url, websocket_.get());
+      socket_ = new SocketStream(url, websocket_.get(), context_.get(), NULL);
       socket_factory_.reset(new MockClientSocketFactory);
       DCHECK(data_.get());
       socket_factory_->AddSocketDataProvider(data_.get());
@@ -388,7 +465,6 @@ class WebSocketJobTest : public PlatformTest,
     }
 
     websocket_->InitSocketStream(socket_.get());
-    websocket_->set_context(context_.get());
     // MockHostResolver resolves all hosts to 127.0.0.1; however, when we create
     // a WebSocketJob purely to block another one in a throttling test, we don't
     // perform a real connect. In that case, the following address is used
@@ -455,6 +531,9 @@ class WebSocketJobTest : public PlatformTest,
   scoped_ptr<MockHostResolver> host_resolver_;
   scoped_ptr<MockHttpTransactionFactory> http_factory_;
 
+  // Must be set before call to enable_websocket_over_spdy, defaults to false.
+  bool enable_websocket_over_spdy_;
+
   static const char kHandshakeRequestWithoutCookie[];
   static const char kHandshakeRequestWithCookie[];
   static const char kHandshakeRequestWithFilteredCookie[];
@@ -473,6 +552,34 @@ class WebSocketJobTest : public PlatformTest,
   static const size_t kDataWorldLength;
 };
 
+// Tests using this fixture verify that the WebSocketJob can handle being
+// deleted while calling back to the delegate correctly. These tests need to be
+// run under AddressSanitizer or other systems for detecting use-after-free
+// errors in order to find problems.
+class WebSocketJobDeleteTest : public ::testing::Test {
+ protected:
+  WebSocketJobDeleteTest()
+      : delegate_(new DeletingSocketStreamDelegate),
+        cookie_store_(new MockCookieStore),
+        context_(new MockURLRequestContext(cookie_store_.get())) {
+    WebSocketJob* websocket = new WebSocketJob(delegate_.get());
+    delegate_->set_job(websocket);
+
+    socket_ = new MockSocketStream(
+        GURL("ws://127.0.0.1/"), websocket, context_.get(), NULL);
+
+    websocket->InitSocketStream(socket_.get());
+  }
+
+  void SetDeleteNext() { return delegate_->set_delete_next(true); }
+  WebSocketJob* job() { return delegate_->job(); }
+
+  scoped_ptr<DeletingSocketStreamDelegate> delegate_;
+  scoped_refptr<MockCookieStore> cookie_store_;
+  scoped_ptr<MockURLRequestContext> context_;
+  scoped_refptr<SocketStream> socket_;
+};
+
 const char WebSocketJobTest::kHandshakeRequestWithoutCookie[] =
     "GET /demo HTTP/1.1\r\n"
     "Host: example.com\r\n"
@@ -605,11 +712,10 @@ INSTANTIATE_TEST_CASE_P(
     NextProto,
     WebSocketJobTest,
     testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2,
-                    kProtoHTTP2Draft04));
+                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
 
 TEST_P(WebSocketJobTest, DelayedCookies) {
-  WebSocketJob::set_websocket_over_spdy_enabled(true);
+  enable_websocket_over_spdy_ = true;
   GURL url("ws://example.com/demo");
   GURL cookieUrl("http://example.com/demo");
   CookieOptions cookie_options;
@@ -738,14 +844,14 @@ void WebSocketJobTest::TestHSTSUpgrade() {
   scoped_refptr<SocketStreamJob> job =
       SocketStreamJob::CreateSocketStreamJob(
           url, &delegate, context_->transport_security_state(),
-          context_->ssl_config_service());
+          context_->ssl_config_service(), NULL, NULL);
   EXPECT_TRUE(GetSocket(job.get())->is_secure());
   job->DetachDelegate();
 
   url = GURL("ws://donotupgrademe.com/");
   job = SocketStreamJob::CreateSocketStreamJob(
       url, &delegate, context_->transport_security_state(),
-      context_->ssl_config_service());
+      context_->ssl_config_service(), NULL, NULL);
   EXPECT_FALSE(GetSocket(job.get())->is_secure());
   job->DetachDelegate();
 }
@@ -992,9 +1098,9 @@ void WebSocketJobTest::TestThrottlingLimit() {
     scoped_refptr<WebSocketJob> job = new WebSocketJob(NULL);
     job->addresses_ = AddressList(AddressList::CreateFromIPAddress(ip, 80));
     if (i >= kMaxWebSocketJobsThrottled)
-      EXPECT_FALSE(WebSocketThrottle::GetInstance()->PutInQueue(job));
+      EXPECT_FALSE(WebSocketThrottle::GetInstance()->PutInQueue(job.get()));
     else
-      EXPECT_TRUE(WebSocketThrottle::GetInstance()->PutInQueue(job));
+      EXPECT_TRUE(WebSocketThrottle::GetInstance()->PutInQueue(job.get()));
     jobs.push_back(job);
   }
 
@@ -1012,87 +1118,79 @@ void WebSocketJobTest::TestThrottlingLimit() {
 
 // Execute tests in both spdy-disabled mode and spdy-enabled mode.
 TEST_P(WebSocketJobTest, SimpleHandshake) {
-  WebSocketJob::set_websocket_over_spdy_enabled(false);
   TestSimpleHandshake();
 }
 
 TEST_P(WebSocketJobTest, SlowHandshake) {
-  WebSocketJob::set_websocket_over_spdy_enabled(false);
   TestSlowHandshake();
 }
 
 TEST_P(WebSocketJobTest, HandshakeWithCookie) {
-  WebSocketJob::set_websocket_over_spdy_enabled(false);
   TestHandshakeWithCookie();
 }
 
 TEST_P(WebSocketJobTest, HandshakeWithCookieButNotAllowed) {
-  WebSocketJob::set_websocket_over_spdy_enabled(false);
   TestHandshakeWithCookieButNotAllowed();
 }
 
 TEST_P(WebSocketJobTest, HSTSUpgrade) {
-  WebSocketJob::set_websocket_over_spdy_enabled(false);
   TestHSTSUpgrade();
 }
 
 TEST_P(WebSocketJobTest, InvalidSendData) {
-  WebSocketJob::set_websocket_over_spdy_enabled(false);
   TestInvalidSendData();
 }
 
 TEST_P(WebSocketJobTest, SimpleHandshakeSpdyEnabled) {
-  WebSocketJob::set_websocket_over_spdy_enabled(true);
+  enable_websocket_over_spdy_ = true;
   TestSimpleHandshake();
 }
 
 TEST_P(WebSocketJobTest, SlowHandshakeSpdyEnabled) {
-  WebSocketJob::set_websocket_over_spdy_enabled(true);
+  enable_websocket_over_spdy_ = true;
   TestSlowHandshake();
 }
 
 TEST_P(WebSocketJobTest, HandshakeWithCookieSpdyEnabled) {
-  WebSocketJob::set_websocket_over_spdy_enabled(true);
+  enable_websocket_over_spdy_ = true;
   TestHandshakeWithCookie();
 }
 
 TEST_P(WebSocketJobTest, HandshakeWithCookieButNotAllowedSpdyEnabled) {
-  WebSocketJob::set_websocket_over_spdy_enabled(true);
+  enable_websocket_over_spdy_ = true;
   TestHandshakeWithCookieButNotAllowed();
 }
 
 TEST_P(WebSocketJobTest, HSTSUpgradeSpdyEnabled) {
-  WebSocketJob::set_websocket_over_spdy_enabled(true);
+  enable_websocket_over_spdy_ = true;
   TestHSTSUpgrade();
 }
 
 TEST_P(WebSocketJobTest, InvalidSendDataSpdyEnabled) {
-  WebSocketJob::set_websocket_over_spdy_enabled(true);
+  enable_websocket_over_spdy_ = true;
   TestInvalidSendData();
 }
 
 TEST_P(WebSocketJobTest, ConnectByWebSocket) {
-  WebSocketJob::set_websocket_over_spdy_enabled(false);
+  enable_websocket_over_spdy_ = true;
   TestConnectByWebSocket(THROTTLING_OFF);
 }
 
 TEST_P(WebSocketJobTest, ConnectByWebSocketSpdyEnabled) {
-  WebSocketJob::set_websocket_over_spdy_enabled(true);
+  enable_websocket_over_spdy_ = true;
   TestConnectByWebSocket(THROTTLING_OFF);
 }
 
 TEST_P(WebSocketJobTest, ConnectBySpdy) {
-  WebSocketJob::set_websocket_over_spdy_enabled(false);
   TestConnectBySpdy(SPDY_OFF, THROTTLING_OFF);
 }
 
 TEST_P(WebSocketJobTest, ConnectBySpdySpdyEnabled) {
-  WebSocketJob::set_websocket_over_spdy_enabled(true);
+  enable_websocket_over_spdy_ = true;
   TestConnectBySpdy(SPDY_ON, THROTTLING_OFF);
 }
 
 TEST_P(WebSocketJobTest, ThrottlingWebSocket) {
-  WebSocketJob::set_websocket_over_spdy_enabled(false);
   TestConnectByWebSocket(THROTTLING_ON);
 }
 
@@ -1101,20 +1199,89 @@ TEST_P(WebSocketJobTest, ThrottlingMaxNumberOfThrottledJobLimit) {
 }
 
 TEST_P(WebSocketJobTest, ThrottlingWebSocketSpdyEnabled) {
-  WebSocketJob::set_websocket_over_spdy_enabled(true);
+  enable_websocket_over_spdy_ = true;
   TestConnectByWebSocket(THROTTLING_ON);
 }
 
 TEST_P(WebSocketJobTest, ThrottlingSpdy) {
-  WebSocketJob::set_websocket_over_spdy_enabled(false);
   TestConnectBySpdy(SPDY_OFF, THROTTLING_ON);
 }
 
 TEST_P(WebSocketJobTest, ThrottlingSpdySpdyEnabled) {
-  WebSocketJob::set_websocket_over_spdy_enabled(true);
+  enable_websocket_over_spdy_ = true;
   TestConnectBySpdy(SPDY_ON, THROTTLING_ON);
 }
 
+TEST_F(WebSocketJobDeleteTest, OnClose) {
+  SetDeleteNext();
+  job()->OnClose(socket_.get());
+  // OnClose() sets WebSocketJob::_socket to NULL before we can detach it, so
+  // socket_->delegate is still set at this point. Clear it to avoid hitting
+  // DCHECK(!delegate_) in the SocketStream destructor. SocketStream::Finish()
+  // is the only caller of this method in real code, and it also sets delegate_
+  // to NULL.
+  socket_->DetachDelegate();
+  EXPECT_FALSE(job());
+}
+
+TEST_F(WebSocketJobDeleteTest, OnAuthRequired) {
+  SetDeleteNext();
+  job()->OnAuthRequired(socket_.get(), NULL);
+  EXPECT_FALSE(job());
+}
+
+TEST_F(WebSocketJobDeleteTest, OnSSLCertificateError) {
+  SSLInfo ssl_info;
+  SetDeleteNext();
+  job()->OnSSLCertificateError(socket_.get(), ssl_info, true);
+  EXPECT_FALSE(job());
+}
+
+TEST_F(WebSocketJobDeleteTest, OnError) {
+  SetDeleteNext();
+  job()->OnError(socket_.get(), ERR_CONNECTION_RESET);
+  EXPECT_FALSE(job());
+}
+
+TEST_F(WebSocketJobDeleteTest, OnSentSpdyHeaders) {
+  job()->Connect();
+  SetDeleteNext();
+  job()->OnSentSpdyHeaders();
+  EXPECT_FALSE(job());
+}
+
+TEST_F(WebSocketJobDeleteTest, OnSentHandshakeRequest) {
+  static const char kMinimalRequest[] =
+      "GET /demo HTTP/1.1\r\n"
+      "Host: example.com\r\n"
+      "Upgrade: WebSocket\r\n"
+      "Connection: Upgrade\r\n"
+      "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
+      "Origin: http://example.com\r\n"
+      "Sec-WebSocket-Version: 13\r\n"
+      "\r\n";
+  const size_t kMinimalRequestSize = arraysize(kMinimalRequest) - 1;
+  job()->Connect();
+  job()->SendData(kMinimalRequest, kMinimalRequestSize);
+  SetDeleteNext();
+  job()->OnSentData(socket_.get(), kMinimalRequestSize);
+  EXPECT_FALSE(job());
+}
+
+TEST_F(WebSocketJobDeleteTest, NotifyHeadersComplete) {
+  static const char kMinimalResponse[] =
+      "HTTP/1.1 101 Switching Protocols\r\n"
+      "Upgrade: websocket\r\n"
+      "Connection: Upgrade\r\n"
+      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
+      "\r\n";
+  job()->Connect();
+  SetDeleteNext();
+  job()->OnReceivedData(
+      socket_.get(), kMinimalResponse, arraysize(kMinimalResponse) - 1);
+  EXPECT_FALSE(job());
+}
+
 // TODO(toyoshim): Add tests to verify throttling, SPDY stream limitation.
 // TODO(toyoshim,yutak): Add tests to verify closing handshake.
 }  // namespace net