Bug 1133939 P2 Add tests validating nsPipeOutputStream AsyncWait behavior. r=froydnj

This commit is contained in:
Ben Kelly 2015-02-21 09:51:17 -05:00
parent 6a06acd86c
commit 1b9774edd8
3 changed files with 237 additions and 0 deletions

View File

@ -94,4 +94,22 @@ ConsumeAndValidateStream(nsIInputStream* aStream,
ASSERT_TRUE(aExpectedData.Equals(outputData));
}
NS_IMPL_ISUPPORTS(OutputStreamCallback, nsIOutputStreamCallback);
OutputStreamCallback::OutputStreamCallback()
: mCalled(false)
{
}
OutputStreamCallback::~OutputStreamCallback()
{
}
NS_IMETHODIMP
OutputStreamCallback::OnOutputStreamReady(nsIAsyncOutputStream* aStream)
{
mCalled = true;
return NS_OK;
}
} // namespace testing

View File

@ -7,6 +7,7 @@
#ifndef __Helpers_h
#define __Helpers_h
#include "nsIAsyncOutputStream.h"
#include "nsString.h"
#include <stdint.h>
@ -34,6 +35,22 @@ void
ConsumeAndValidateStream(nsIInputStream* aStream,
const nsACString& aExpectedData);
class OutputStreamCallback MOZ_FINAL : public nsIOutputStreamCallback
{
public:
OutputStreamCallback();
bool Called() const { return mCalled; }
private:
~OutputStreamCallback();
bool mCalled;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOUTPUTSTREAMCALLBACK
};
} // namespace testing
#endif // __Helpers_h

View File

@ -660,3 +660,205 @@ TEST(Pipes, Clone_DuringWrite_ReadDuringWrite_CloseDuringWrite)
2, // num clones to add after each write
3); // num streams to read after each write
}
TEST(Pipes, Write_AsyncWait)
{
nsCOMPtr<nsIAsyncInputStream> reader;
nsCOMPtr<nsIAsyncOutputStream> writer;
const uint32_t segmentSize = 1024;
const uint32_t numSegments = 1;
nsresult rv = NS_NewPipe2(getter_AddRefs(reader), getter_AddRefs(writer),
true, true, // non-blocking - reader, writer
segmentSize, numSegments);
ASSERT_TRUE(NS_SUCCEEDED(rv));
nsTArray<char> inputData;
testing::CreateData(segmentSize, inputData);
uint32_t numWritten = 0;
rv = writer->Write(inputData.Elements(), inputData.Length(), &numWritten);
ASSERT_TRUE(NS_SUCCEEDED(rv));
rv = writer->Write(inputData.Elements(), inputData.Length(), &numWritten);
ASSERT_EQ(NS_BASE_STREAM_WOULD_BLOCK, rv);
nsRefPtr<testing::OutputStreamCallback> cb =
new testing::OutputStreamCallback();
rv = writer->AsyncWait(cb, 0, 0, nullptr);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_FALSE(cb->Called());
testing::ConsumeAndValidateStream(reader, inputData);
ASSERT_TRUE(cb->Called());
}
TEST(Pipes, Write_AsyncWait_Clone)
{
nsCOMPtr<nsIAsyncInputStream> reader;
nsCOMPtr<nsIAsyncOutputStream> writer;
const uint32_t segmentSize = 1024;
const uint32_t numSegments = 1;
nsresult rv = NS_NewPipe2(getter_AddRefs(reader), getter_AddRefs(writer),
true, true, // non-blocking - reader, writer
segmentSize, numSegments);
ASSERT_TRUE(NS_SUCCEEDED(rv));
nsCOMPtr<nsIInputStream> clone;
rv = NS_CloneInputStream(reader, getter_AddRefs(clone));
ASSERT_TRUE(NS_SUCCEEDED(rv));
nsTArray<char> inputData;
testing::CreateData(segmentSize, inputData);
uint32_t numWritten = 0;
rv = writer->Write(inputData.Elements(), inputData.Length(), &numWritten);
ASSERT_TRUE(NS_SUCCEEDED(rv));
rv = writer->Write(inputData.Elements(), inputData.Length(), &numWritten);
ASSERT_EQ(NS_BASE_STREAM_WOULD_BLOCK, rv);
nsRefPtr<testing::OutputStreamCallback> cb =
new testing::OutputStreamCallback();
rv = writer->AsyncWait(cb, 0, 0, nullptr);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_FALSE(cb->Called());
testing::ConsumeAndValidateStream(reader, inputData);
ASSERT_FALSE(cb->Called());
testing::ConsumeAndValidateStream(clone, inputData);
ASSERT_TRUE(cb->Called());
}
TEST(Pipes, Write_AsyncWait_Clone_CloseOriginal)
{
nsCOMPtr<nsIAsyncInputStream> reader;
nsCOMPtr<nsIAsyncOutputStream> writer;
const uint32_t segmentSize = 1024;
const uint32_t numSegments = 1;
nsresult rv = NS_NewPipe2(getter_AddRefs(reader), getter_AddRefs(writer),
true, true, // non-blocking - reader, writer
segmentSize, numSegments);
ASSERT_TRUE(NS_SUCCEEDED(rv));
nsCOMPtr<nsIInputStream> clone;
rv = NS_CloneInputStream(reader, getter_AddRefs(clone));
ASSERT_TRUE(NS_SUCCEEDED(rv));
nsTArray<char> inputData;
testing::CreateData(segmentSize, inputData);
uint32_t numWritten = 0;
rv = writer->Write(inputData.Elements(), inputData.Length(), &numWritten);
ASSERT_TRUE(NS_SUCCEEDED(rv));
rv = writer->Write(inputData.Elements(), inputData.Length(), &numWritten);
ASSERT_EQ(NS_BASE_STREAM_WOULD_BLOCK, rv);
nsRefPtr<testing::OutputStreamCallback> cb =
new testing::OutputStreamCallback();
rv = writer->AsyncWait(cb, 0, 0, nullptr);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_FALSE(cb->Called());
testing::ConsumeAndValidateStream(clone, inputData);
ASSERT_FALSE(cb->Called());
reader->Close();
ASSERT_TRUE(cb->Called());
}
namespace {
NS_METHOD
CloseDuringReadFunc(nsIInputStream *aReader,
void* aClosure,
const char* aFromSegment,
uint32_t aToOffset,
uint32_t aCount,
uint32_t* aWriteCountOut)
{
MOZ_ASSERT(aReader);
MOZ_ASSERT(aClosure);
MOZ_ASSERT(aFromSegment);
MOZ_ASSERT(aWriteCountOut);
MOZ_ASSERT(aToOffset == 0);
// This is insanity and you probably should not do this under normal
// conditions. We want to simulate the case where the pipe is closed
// (possibly from other end on another thread) simultaneously with the
// read. This is the easiest way to do trigger this case in a synchronous
// gtest.
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aReader->Close()));
nsTArray<char>* buffer = static_cast<nsTArray<char>*>(aClosure);
buffer->AppendElements(aFromSegment, aCount);
*aWriteCountOut = aCount;
return NS_OK;
}
void
TestCloseDuringRead(uint32_t aSegmentSize, uint32_t aDataSize)
{
nsCOMPtr<nsIInputStream> reader;
nsCOMPtr<nsIOutputStream> writer;
const uint32_t maxSize = aSegmentSize;
nsresult rv = NS_NewPipe(getter_AddRefs(reader), getter_AddRefs(writer),
aSegmentSize, maxSize);
ASSERT_TRUE(NS_SUCCEEDED(rv));
nsTArray<char> inputData;
testing::CreateData(aDataSize, inputData);
uint32_t numWritten = 0;
rv = writer->Write(inputData.Elements(), inputData.Length(), &numWritten);
ASSERT_TRUE(NS_SUCCEEDED(rv));
nsTArray<char> outputData;
uint32_t numRead = 0;
rv = reader->ReadSegments(CloseDuringReadFunc, &outputData,
inputData.Length(), &numRead);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_EQ(inputData.Length(), numRead);
ASSERT_EQ(inputData, outputData);
uint64_t available;
rv = reader->Available(&available);
ASSERT_EQ(NS_BASE_STREAM_CLOSED, rv);
}
} // anonymous namespace
TEST(Pipes, Close_During_Read_Partial_Segment)
{
TestCloseDuringRead(1024, 512);
}
TEST(Pipes, Close_During_Read_Full_Segment)
{
TestCloseDuringRead(1024, 1024);
}