TestInputStreamTransport.cpp (5306B)
1 #include "gtest/gtest.h" 2 3 #include "nsIStreamTransportService.h" 4 #include "nsStreamUtils.h" 5 #include "nsThreadUtils.h" 6 #include "Helpers.h" 7 #include "nsNetCID.h" 8 #include "nsServiceManagerUtils.h" 9 #include "nsITransport.h" 10 #include "nsNetUtil.h" 11 12 static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID); 13 14 void CreateStream(already_AddRefed<nsIInputStream> aSource, 15 nsIAsyncInputStream** aStream) { 16 nsCOMPtr<nsIInputStream> source = std::move(aSource); 17 18 nsresult rv; 19 nsCOMPtr<nsIStreamTransportService> sts = 20 do_GetService(kStreamTransportServiceCID, &rv); 21 ASSERT_EQ(NS_OK, rv); 22 23 nsCOMPtr<nsITransport> transport; 24 rv = sts->CreateInputTransport(source, true, getter_AddRefs(transport)); 25 ASSERT_EQ(NS_OK, rv); 26 27 nsCOMPtr<nsIInputStream> wrapper; 28 rv = transport->OpenInputStream(0, 0, 0, getter_AddRefs(wrapper)); 29 ASSERT_EQ(NS_OK, rv); 30 31 nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(wrapper); 32 MOZ_RELEASE_ASSERT(asyncStream); 33 34 asyncStream.forget(aStream); 35 } 36 37 class BlockingSyncStream final : public nsIInputStream { 38 nsCOMPtr<nsIInputStream> mStream; 39 40 public: 41 NS_DECL_THREADSAFE_ISUPPORTS 42 43 explicit BlockingSyncStream(const nsACString& aBuffer) { 44 NS_NewCStringInputStream(getter_AddRefs(mStream), aBuffer); 45 } 46 47 NS_IMETHOD 48 Available(uint64_t* aLength) override { return mStream->Available(aLength); } 49 50 NS_IMETHOD 51 StreamStatus() override { return mStream->StreamStatus(); } 52 53 NS_IMETHOD 54 Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount) override { 55 return mStream->Read(aBuffer, aCount, aReadCount); 56 } 57 58 NS_IMETHOD 59 ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, uint32_t aCount, 60 uint32_t* aResult) override { 61 return mStream->ReadSegments(aWriter, aClosure, aCount, aResult); 62 } 63 64 NS_IMETHOD 65 Close() override { return mStream->Close(); } 66 67 NS_IMETHOD 68 IsNonBlocking(bool* aNonBlocking) override { 69 *aNonBlocking = false; 70 return NS_OK; 71 } 72 73 private: 74 ~BlockingSyncStream() = default; 75 }; 76 77 NS_IMPL_ISUPPORTS(BlockingSyncStream, nsIInputStream) 78 79 // Testing a simple blocking stream. 80 TEST(TestInputStreamTransport, BlockingNotAsync) 81 { 82 RefPtr<BlockingSyncStream> stream = new BlockingSyncStream("Hello world"_ns); 83 84 nsCOMPtr<nsIAsyncInputStream> ais; 85 CreateStream(stream.forget(), getter_AddRefs(ais)); 86 ASSERT_TRUE(!!ais); 87 88 nsAutoCString data; 89 nsresult rv = NS_ReadInputStreamToString(ais, data, -1); 90 ASSERT_EQ(NS_OK, rv); 91 92 ASSERT_TRUE(data.EqualsLiteral("Hello world")); 93 } 94 95 class BlockingAsyncStream final : public nsIAsyncInputStream { 96 nsCOMPtr<nsIInputStream> mStream; 97 bool mPending; 98 99 public: 100 NS_DECL_THREADSAFE_ISUPPORTS 101 102 explicit BlockingAsyncStream(const nsACString& aBuffer) : mPending(false) { 103 NS_NewCStringInputStream(getter_AddRefs(mStream), aBuffer); 104 } 105 106 NS_IMETHOD 107 Available(uint64_t* aLength) override { 108 mStream->Available(aLength); 109 110 // 1 char at the time, just to test the asyncWait+Read loop a bit more. 111 if (*aLength > 0) { 112 *aLength = 1; 113 } 114 115 return NS_OK; 116 } 117 118 NS_IMETHOD 119 StreamStatus() override { return mStream->StreamStatus(); } 120 121 NS_IMETHOD 122 Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount) override { 123 mPending = !mPending; 124 if (mPending) { 125 return NS_BASE_STREAM_WOULD_BLOCK; 126 } 127 128 // 1 char at the time, just to test the asyncWait+Read loop a bit more. 129 aCount = 1; 130 131 return mStream->Read(aBuffer, aCount, aReadCount); 132 } 133 134 NS_IMETHOD 135 ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, uint32_t aCount, 136 uint32_t* aResult) override { 137 mPending = !mPending; 138 if (mPending) { 139 return NS_BASE_STREAM_WOULD_BLOCK; 140 } 141 142 // 1 char at the time, just to test the asyncWait+Read loop a bit more. 143 aCount = 1; 144 145 return mStream->ReadSegments(aWriter, aClosure, aCount, aResult); 146 } 147 148 NS_IMETHOD 149 Close() override { return mStream->Close(); } 150 151 NS_IMETHOD 152 IsNonBlocking(bool* aNonBlocking) override { 153 *aNonBlocking = false; 154 return NS_OK; 155 } 156 157 NS_IMETHOD 158 CloseWithStatus(nsresult aStatus) override { return Close(); } 159 160 NS_IMETHOD 161 AsyncWait(nsIInputStreamCallback* aCallback, uint32_t aFlags, 162 uint32_t aRequestedCount, nsIEventTarget* aEventTarget) override { 163 if (!aCallback) { 164 return NS_OK; 165 } 166 167 RefPtr<BlockingAsyncStream> self = this; 168 nsCOMPtr<nsIInputStreamCallback> callback = aCallback; 169 170 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction( 171 "gtest-asyncwait", 172 [self, callback]() { callback->OnInputStreamReady(self); }); 173 174 if (aEventTarget) { 175 aEventTarget->Dispatch(r.forget()); 176 } else { 177 r->Run(); 178 } 179 180 return NS_OK; 181 } 182 183 private: 184 ~BlockingAsyncStream() = default; 185 }; 186 187 NS_IMPL_ISUPPORTS(BlockingAsyncStream, nsIInputStream, nsIAsyncInputStream) 188 189 // Testing an async blocking stream. 190 TEST(TestInputStreamTransport, BlockingAsync) 191 { 192 RefPtr<BlockingAsyncStream> stream = 193 new BlockingAsyncStream("Hello world"_ns); 194 195 nsCOMPtr<nsIAsyncInputStream> ais; 196 CreateStream(stream.forget(), getter_AddRefs(ais)); 197 ASSERT_TRUE(!!ais); 198 199 nsAutoCString data; 200 nsresult rv = NS_ReadInputStreamToString(ais, data, -1); 201 ASSERT_EQ(NS_OK, rv); 202 203 ASSERT_TRUE(data.EqualsLiteral("Hello world")); 204 }