| Index: net/socket_stream/socket_stream_unittest.cc
|
| diff --git a/net/socket_stream/socket_stream_unittest.cc b/net/socket_stream/socket_stream_unittest.cc
|
| index b0734fc5fb5b0bd7d98e04fca93560e40458993e..aed80f28ba2891c8ce191377dd0ed9e7e94dcd6f 100644
|
| --- a/net/socket_stream/socket_stream_unittest.cc
|
| +++ b/net/socket_stream/socket_stream_unittest.cc
|
| @@ -181,6 +181,54 @@ class SocketStreamEventRecorder : public SocketStream::Delegate {
|
| DISALLOW_COPY_AND_ASSIGN(SocketStreamEventRecorder);
|
| };
|
|
|
| +// This is used for the test OnErrorDetachDelegate.
|
| +class SelfDeletingDelegate : public SocketStream::Delegate {
|
| + public:
|
| + // |callback| must cause the test message loop to exit when called.
|
| + explicit SelfDeletingDelegate(const CompletionCallback& callback)
|
| + : socket_stream_(), callback_(callback) {}
|
| +
|
| + virtual ~SelfDeletingDelegate() {}
|
| +
|
| + // Call DetachDelegate(), delete |this|, then run the callback.
|
| + virtual void OnError(const SocketStream* socket, int error) OVERRIDE {
|
| + // callback_ will be deleted when we delete |this|, so copy it to call it
|
| + // afterwards.
|
| + CompletionCallback callback = callback_;
|
| + socket_stream_->DetachDelegate();
|
| + delete this;
|
| + callback.Run(OK);
|
| + }
|
| +
|
| + // This can't be passed in the constructor because this object needs to be
|
| + // created before SocketStream.
|
| + void set_socket_stream(const scoped_refptr<SocketStream>& socket_stream) {
|
| + socket_stream_ = socket_stream;
|
| + EXPECT_EQ(socket_stream_->delegate(), this);
|
| + }
|
| +
|
| + virtual void OnConnected(SocketStream* socket, int max_pending_send_allowed)
|
| + OVERRIDE {
|
| + ADD_FAILURE() << "OnConnected() should not be called";
|
| + }
|
| + virtual void OnSentData(SocketStream* socket, int amount_sent) OVERRIDE {
|
| + ADD_FAILURE() << "OnSentData() should not be called";
|
| + }
|
| + virtual void OnReceivedData(SocketStream* socket, const char* data, int len)
|
| + OVERRIDE {
|
| + ADD_FAILURE() << "OnReceivedData() should not be called";
|
| + }
|
| + virtual void OnClose(SocketStream* socket) OVERRIDE {
|
| + ADD_FAILURE() << "OnClose() should not be called";
|
| + }
|
| +
|
| + private:
|
| + scoped_refptr<SocketStream> socket_stream_;
|
| + const CompletionCallback callback_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(SelfDeletingDelegate);
|
| +};
|
| +
|
| class TestURLRequestContextWithProxy : public TestURLRequestContext {
|
| public:
|
| explicit TestURLRequestContextWithProxy(const std::string& proxy)
|
| @@ -846,4 +894,34 @@ TEST_F(SocketStreamTest, BeforeConnectFailed) {
|
| EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[1].event_type);
|
| }
|
|
|
| +// Check that a connect failure, followed by the delegate calling DetachDelegate
|
| +// and deleting itself in the OnError callback, is handled correctly.
|
| +TEST_F(SocketStreamTest, OnErrorDetachDelegate) {
|
| + MockClientSocketFactory mock_socket_factory;
|
| + TestCompletionCallback test_callback;
|
| +
|
| + // SelfDeletingDelegate is self-owning; we just need a pointer to it to
|
| + // connect it and the SocketStream.
|
| + SelfDeletingDelegate* delegate =
|
| + new SelfDeletingDelegate(test_callback.callback());
|
| + MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED);
|
| + StaticSocketDataProvider data;
|
| + data.set_connect_data(mock_connect);
|
| + mock_socket_factory.AddSocketDataProvider(&data);
|
| +
|
| + TestURLRequestContext context;
|
| + scoped_refptr<SocketStream> socket_stream(
|
| + new SocketStream(GURL("ws://localhost:9998/echo"), delegate));
|
| + socket_stream->set_context(&context);
|
| + socket_stream->SetClientSocketFactory(&mock_socket_factory);
|
| + delegate->set_socket_stream(socket_stream);
|
| + // The delegate pointer will become invalid during the test. Set it to NULL to
|
| + // avoid holding a dangling pointer.
|
| + delegate = NULL;
|
| +
|
| + socket_stream->Connect();
|
| +
|
| + EXPECT_EQ(OK, test_callback.WaitForResult());
|
| +}
|
| +
|
| } // namespace net
|
|
|