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