michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // Original author: ekr@rtfm.com michael@0: #include michael@0: michael@0: #include "prio.h" michael@0: michael@0: #include "nsCOMPtr.h" michael@0: #include "nsNetCID.h" michael@0: #include "nsXPCOM.h" michael@0: #include "nsXPCOMGlue.h" michael@0: michael@0: #include "nsIComponentManager.h" michael@0: #include "nsIComponentRegistrar.h" michael@0: #include "nsIIOService.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsISocketTransportService.h" michael@0: michael@0: #include "nsASocketHandler.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: #include "mtransport_test_utils.h" michael@0: michael@0: #define GTEST_HAS_RTTI 0 michael@0: #include "gtest/gtest.h" michael@0: #include "gtest_utils.h" michael@0: michael@0: MtransportTestUtils *test_utils; michael@0: michael@0: namespace { michael@0: class SocketTransportServiceTest : public ::testing::Test { michael@0: public: michael@0: SocketTransportServiceTest() : received_(0), michael@0: readpipe_(nullptr), michael@0: writepipe_(nullptr), michael@0: registered_(false) { michael@0: } michael@0: michael@0: ~SocketTransportServiceTest() { michael@0: if (readpipe_) michael@0: PR_Close(readpipe_); michael@0: if (writepipe_) michael@0: PR_Close(writepipe_); michael@0: } michael@0: michael@0: void SetUp(); michael@0: void RegisterHandler(); michael@0: void SendEvent(); michael@0: void SendPacket(); michael@0: michael@0: void ReceivePacket() { michael@0: ++received_; michael@0: } michael@0: michael@0: void ReceiveEvent() { michael@0: ++received_; michael@0: } michael@0: michael@0: size_t Received() { michael@0: return received_; michael@0: } michael@0: michael@0: private: michael@0: nsCOMPtr stservice_; michael@0: nsCOMPtr target_; michael@0: size_t received_; michael@0: PRFileDesc *readpipe_; michael@0: PRFileDesc *writepipe_; michael@0: bool registered_; michael@0: }; michael@0: michael@0: michael@0: // Received an event. michael@0: class EventReceived : public nsRunnable { michael@0: public: michael@0: EventReceived(SocketTransportServiceTest *test) : michael@0: test_(test) {} michael@0: michael@0: NS_IMETHOD Run() { michael@0: test_->ReceiveEvent(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: SocketTransportServiceTest *test_; michael@0: }; michael@0: michael@0: michael@0: // Register our listener on the socket michael@0: class RegisterEvent : public nsRunnable { michael@0: public: michael@0: RegisterEvent(SocketTransportServiceTest *test) : michael@0: test_(test) {} michael@0: michael@0: NS_IMETHOD Run() { michael@0: test_->RegisterHandler(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: SocketTransportServiceTest *test_; michael@0: }; michael@0: michael@0: michael@0: class SocketHandler : public nsASocketHandler { michael@0: public: michael@0: SocketHandler(SocketTransportServiceTest *test) : test_(test) { michael@0: } michael@0: virtual ~SocketHandler() {} michael@0: michael@0: void OnSocketReady(PRFileDesc *fd, int16_t outflags) { michael@0: unsigned char buf[1600]; michael@0: michael@0: int32_t rv; michael@0: rv = PR_Recv(fd, buf, sizeof(buf), 0, PR_INTERVAL_NO_WAIT); michael@0: if (rv > 0) { michael@0: std::cerr << "Read " << rv << " bytes" << std::endl; michael@0: test_->ReceivePacket(); michael@0: } michael@0: } michael@0: michael@0: void OnSocketDetached(PRFileDesc *fd) {} michael@0: michael@0: void IsLocal(bool *aIsLocal) { michael@0: // TODO(jesup): better check? Does it matter? (likely no) michael@0: *aIsLocal = false; michael@0: } michael@0: michael@0: virtual uint64_t ByteCountSent() { return 0; } michael@0: virtual uint64_t ByteCountReceived() { return 0; } michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: private: michael@0: SocketTransportServiceTest *test_; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS0(SocketHandler) michael@0: michael@0: void SocketTransportServiceTest::SetUp() { michael@0: // Get the transport service as a dispatch target michael@0: nsresult rv; michael@0: target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); michael@0: ASSERT_TRUE(NS_SUCCEEDED(rv)); michael@0: michael@0: // Get the transport service as a transport service michael@0: stservice_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); michael@0: ASSERT_TRUE(NS_SUCCEEDED(rv)); michael@0: michael@0: // Create a loopback pipe michael@0: PRStatus status = PR_CreatePipe(&readpipe_, &writepipe_); michael@0: ASSERT_EQ(status, PR_SUCCESS); michael@0: michael@0: // Register ourselves as a listener for the read side of the michael@0: // socket. The registration has to happen on the STS thread, michael@0: // hence this event stuff. michael@0: rv = target_->Dispatch(new RegisterEvent(this), 0); michael@0: ASSERT_TRUE(NS_SUCCEEDED(rv)); michael@0: ASSERT_TRUE_WAIT(registered_, 10000); michael@0: michael@0: } michael@0: michael@0: void SocketTransportServiceTest::RegisterHandler() { michael@0: nsresult rv; michael@0: michael@0: rv = stservice_->AttachSocket(readpipe_, new SocketHandler(this)); michael@0: ASSERT_TRUE(NS_SUCCEEDED(rv)); michael@0: michael@0: registered_ = true; michael@0: } michael@0: michael@0: void SocketTransportServiceTest::SendEvent() { michael@0: nsresult rv; michael@0: michael@0: rv = target_->Dispatch(new EventReceived(this), 0); michael@0: ASSERT_TRUE(NS_SUCCEEDED(rv)); michael@0: ASSERT_TRUE_WAIT(Received() == 1, 10000); michael@0: } michael@0: michael@0: void SocketTransportServiceTest::SendPacket() { michael@0: unsigned char buffer[1024]; michael@0: memset(buffer, 0, sizeof(buffer)); michael@0: michael@0: int32_t status = PR_Write(writepipe_, buffer, sizeof(buffer)); michael@0: uint32_t size = status & 0xffff; michael@0: ASSERT_EQ(sizeof(buffer), size); michael@0: } michael@0: michael@0: michael@0: michael@0: // The unit tests themselves michael@0: TEST_F(SocketTransportServiceTest, SendEvent) { michael@0: SendEvent(); michael@0: } michael@0: michael@0: TEST_F(SocketTransportServiceTest, SendPacket) { michael@0: SendPacket(); michael@0: } michael@0: michael@0: michael@0: } // end namespace michael@0: michael@0: michael@0: int main(int argc, char **argv) { michael@0: test_utils = new MtransportTestUtils(); michael@0: michael@0: // Start the tests michael@0: ::testing::InitGoogleTest(&argc, argv); michael@0: michael@0: int rv = RUN_ALL_TESTS(); michael@0: delete test_utils; michael@0: return rv; michael@0: }