зеркало из https://github.com/mozilla/gecko-dev.git
279 строки
8.0 KiB
C++
279 строки
8.0 KiB
C++
/* -*- 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 authors: ekr@rtfm.com; ryan@tokbox.com
|
|
|
|
#include <vector>
|
|
#include <numeric>
|
|
|
|
#include "mozilla/net/NeckoChannelParams.h"
|
|
#include "nr_socket_tcp.h"
|
|
#include "WebrtcTCPSocketWrapper.h"
|
|
|
|
#define GTEST_HAS_RTTI 0
|
|
#include "gtest/gtest.h"
|
|
#include "gtest_utils.h"
|
|
|
|
using namespace mozilla;
|
|
|
|
// update TestReadMultipleSizes if you change this
|
|
const std::string kHelloMessage = "HELLO IS IT ME YOU'RE LOOKING FOR?";
|
|
|
|
class NrTcpSocketTest : public MtransportTest {
|
|
public:
|
|
NrTcpSocketTest()
|
|
: mSProxy(nullptr),
|
|
nr_socket_(nullptr),
|
|
mEmptyArray(0),
|
|
mReadChunkSize(0),
|
|
mReadChunkSizeIncrement(1),
|
|
mReadAllowance(-1),
|
|
mConnected(false) {}
|
|
|
|
void SetUp() override {
|
|
mSProxy = new NrTcpSocket(nullptr);
|
|
int r = nr_socket_create_int((void*)mSProxy.get(), mSProxy->vtbl(),
|
|
&nr_socket_);
|
|
ASSERT_EQ(0, r);
|
|
|
|
// fake calling AsyncOpen() due to IPC calls. must be non-null
|
|
mSProxy->AssignChannel_DoNotUse(new WebrtcTCPSocketWrapper(nullptr));
|
|
}
|
|
|
|
void TearDown() override { mSProxy->close(); }
|
|
|
|
static void readable_cb(NR_SOCKET s, int how, void* cb_arg) {
|
|
NrTcpSocketTest* test = (NrTcpSocketTest*)cb_arg;
|
|
size_t capacity = std::min(test->mReadChunkSize, test->mReadAllowance);
|
|
nsTArray<uint8_t> array(capacity);
|
|
size_t read;
|
|
|
|
nr_socket_read(test->nr_socket_, (char*)array.Elements(), array.Capacity(),
|
|
&read, 0);
|
|
|
|
ASSERT_TRUE(read <= array.Capacity());
|
|
ASSERT_TRUE(test->mReadAllowance >= read);
|
|
|
|
array.SetLength(read);
|
|
test->mData.AppendElements(array);
|
|
test->mReadAllowance -= read;
|
|
|
|
// We may read more bytes each time we're called. This way we can ensure we
|
|
// consume buffers partially and across multiple buffers.
|
|
test->mReadChunkSize += test->mReadChunkSizeIncrement;
|
|
|
|
if (test->mReadAllowance > 0) {
|
|
NR_ASYNC_WAIT(s, how, &NrTcpSocketTest::readable_cb, cb_arg);
|
|
}
|
|
}
|
|
|
|
static void writable_cb(NR_SOCKET s, int how, void* cb_arg) {
|
|
NrTcpSocketTest* test = (NrTcpSocketTest*)cb_arg;
|
|
test->mConnected = true;
|
|
}
|
|
|
|
const std::string DataString() {
|
|
return std::string((char*)mData.Elements(), mData.Length());
|
|
}
|
|
|
|
protected:
|
|
RefPtr<NrTcpSocket> mSProxy;
|
|
nr_socket* nr_socket_;
|
|
|
|
nsTArray<uint8_t> mData;
|
|
nsTArray<uint8_t> mEmptyArray;
|
|
|
|
uint32_t mReadChunkSize;
|
|
uint32_t mReadChunkSizeIncrement;
|
|
uint32_t mReadAllowance;
|
|
|
|
bool mConnected;
|
|
};
|
|
|
|
TEST_F(NrTcpSocketTest, TestCreate) {}
|
|
|
|
TEST_F(NrTcpSocketTest, TestConnected) {
|
|
ASSERT_TRUE(!mConnected);
|
|
|
|
NR_ASYNC_WAIT(mSProxy, NR_ASYNC_WAIT_WRITE, &NrTcpSocketTest::writable_cb,
|
|
this);
|
|
|
|
// still not connected just registered for writes...
|
|
ASSERT_TRUE(!mConnected);
|
|
|
|
mSProxy->OnConnected(NS_LITERAL_CSTRING("http"));
|
|
|
|
ASSERT_TRUE(mConnected);
|
|
}
|
|
|
|
TEST_F(NrTcpSocketTest, TestRead) {
|
|
nsTArray<uint8_t> array;
|
|
array.AppendElements(kHelloMessage.c_str(), kHelloMessage.length());
|
|
|
|
NR_ASYNC_WAIT(mSProxy, NR_ASYNC_WAIT_READ, &NrTcpSocketTest::readable_cb,
|
|
this);
|
|
// this will read 0 bytes here
|
|
mSProxy->OnRead(std::move(array));
|
|
|
|
ASSERT_EQ(kHelloMessage.length(), mSProxy->CountUnreadBytes());
|
|
|
|
// callback is still set but terminated due to 0 byte read
|
|
// start callbacks again (first read is 0 then 1,2,3,...)
|
|
mSProxy->OnRead(std::move(mEmptyArray));
|
|
|
|
ASSERT_EQ(kHelloMessage.length(), mData.Length());
|
|
ASSERT_EQ(kHelloMessage, DataString());
|
|
}
|
|
|
|
TEST_F(NrTcpSocketTest, TestReadConstantConsumeSize) {
|
|
std::string data;
|
|
|
|
// triangle number
|
|
const int kCount = 32;
|
|
|
|
// ~17kb
|
|
// triangle number formula n*(n+1)/2
|
|
for (int i = 0; i < kCount * (kCount + 1) / 2; ++i) {
|
|
data += kHelloMessage;
|
|
}
|
|
|
|
// decreasing buffer sizes
|
|
for (int i = 0, start = 0; i < kCount; ++i) {
|
|
int length = (kCount - i) * kHelloMessage.length();
|
|
|
|
nsTArray<uint8_t> array;
|
|
array.AppendElements(data.c_str() + start, length);
|
|
start += length;
|
|
|
|
mSProxy->OnRead(std::move(array));
|
|
}
|
|
|
|
ASSERT_EQ(data.length(), mSProxy->CountUnreadBytes());
|
|
|
|
// read same amount each callback
|
|
mReadChunkSize = 128;
|
|
mReadChunkSizeIncrement = 0;
|
|
NR_ASYNC_WAIT(mSProxy, NR_ASYNC_WAIT_READ, &NrTcpSocketTest::readable_cb,
|
|
this);
|
|
|
|
ASSERT_EQ(data.length(), mSProxy->CountUnreadBytes());
|
|
|
|
// start callbacks
|
|
mSProxy->OnRead(std::move(mEmptyArray));
|
|
|
|
ASSERT_EQ(data.length(), mData.Length());
|
|
ASSERT_EQ(data, DataString());
|
|
}
|
|
|
|
TEST_F(NrTcpSocketTest, TestReadNone) {
|
|
char buf[4096];
|
|
size_t read = 0;
|
|
int r = nr_socket_read(nr_socket_, buf, sizeof(buf), &read, 0);
|
|
|
|
ASSERT_EQ(R_WOULDBLOCK, r);
|
|
|
|
nsTArray<uint8_t> array;
|
|
array.AppendElements(kHelloMessage.c_str(), kHelloMessage.length());
|
|
mSProxy->OnRead(std::move(array));
|
|
|
|
ASSERT_EQ(kHelloMessage.length(), mSProxy->CountUnreadBytes());
|
|
|
|
r = nr_socket_read(nr_socket_, buf, sizeof(buf), &read, 0);
|
|
|
|
ASSERT_EQ(0, r);
|
|
ASSERT_EQ(kHelloMessage.length(), read);
|
|
ASSERT_EQ(kHelloMessage, std::string(buf, read));
|
|
}
|
|
|
|
TEST_F(NrTcpSocketTest, TestReadMultipleSizes) {
|
|
using namespace std;
|
|
|
|
string data;
|
|
// 515 * kHelloMessage.length() == 17510
|
|
const size_t kCount = 515;
|
|
// randomly generated numbers, sums to 17510, 20 numbers
|
|
vector<int> varyingSizes = {404, 622, 1463, 1597, 1676, 389, 389,
|
|
1272, 781, 81, 1030, 1450, 256, 812,
|
|
1571, 29, 1045, 911, 643, 1089};
|
|
|
|
// changing varyingSizes or the test message breaks this so check here
|
|
ASSERT_EQ(kCount, 17510 / kHelloMessage.length());
|
|
ASSERT_EQ(17510, accumulate(varyingSizes.begin(), varyingSizes.end(), 0));
|
|
|
|
// ~17kb
|
|
for (size_t i = 0; i < kCount; ++i) {
|
|
data += kHelloMessage;
|
|
}
|
|
|
|
nsTArray<uint8_t> array;
|
|
array.AppendElements(data.c_str(), data.length());
|
|
|
|
for (int amountToRead : varyingSizes) {
|
|
nsTArray<uint8_t> buffer;
|
|
buffer.AppendElements(array.Elements(), amountToRead);
|
|
array.RemoveElementsAt(0, amountToRead);
|
|
mSProxy->OnRead(std::move(buffer));
|
|
}
|
|
|
|
ASSERT_EQ(data.length(), mSProxy->CountUnreadBytes());
|
|
|
|
// don't need to read 0 on the first read, so start at 1 and keep going
|
|
mReadChunkSize = 1;
|
|
NR_ASYNC_WAIT(mSProxy, NR_ASYNC_WAIT_READ, &NrTcpSocketTest::readable_cb,
|
|
this);
|
|
// start callbacks
|
|
mSProxy->OnRead(std::move(mEmptyArray));
|
|
|
|
ASSERT_EQ(data.length(), mData.Length());
|
|
ASSERT_EQ(data, DataString());
|
|
}
|
|
|
|
TEST_F(NrTcpSocketTest, TestReadConsumeReadDrain) {
|
|
std::string data;
|
|
// ~26kb total; should be even
|
|
const int kCount = 512;
|
|
|
|
// there's some division by 2 here so check that kCount is even
|
|
ASSERT_EQ(0, kCount % 2);
|
|
|
|
for (int i = 0; i < kCount; ++i) {
|
|
data += kHelloMessage;
|
|
nsTArray<uint8_t> array;
|
|
array.AppendElements(kHelloMessage.c_str(), kHelloMessage.length());
|
|
mSProxy->OnRead(std::move(array));
|
|
}
|
|
|
|
// read half at first
|
|
mReadAllowance = kCount / 2 * kHelloMessage.length();
|
|
// start by reading 1 byte
|
|
mReadChunkSize = 1;
|
|
NR_ASYNC_WAIT(mSProxy, NR_ASYNC_WAIT_READ, &NrTcpSocketTest::readable_cb,
|
|
this);
|
|
mSProxy->OnRead(std::move(mEmptyArray));
|
|
|
|
ASSERT_EQ(data.length() / 2, mSProxy->CountUnreadBytes());
|
|
ASSERT_EQ(data.length() / 2, mData.Length());
|
|
|
|
// fill read buffer back up
|
|
for (int i = 0; i < kCount / 2; ++i) {
|
|
data += kHelloMessage;
|
|
nsTArray<uint8_t> array;
|
|
array.AppendElements(kHelloMessage.c_str(), kHelloMessage.length());
|
|
mSProxy->OnRead(std::move(array));
|
|
}
|
|
|
|
// remove read limit
|
|
mReadAllowance = -1;
|
|
// used entire read allowance so we need to setup a new await
|
|
NR_ASYNC_WAIT(mSProxy, NR_ASYNC_WAIT_READ, &NrTcpSocketTest::readable_cb,
|
|
this);
|
|
// start callbacks
|
|
mSProxy->OnRead(std::move(mEmptyArray));
|
|
|
|
ASSERT_EQ(data.length(), mData.Length());
|
|
ASSERT_EQ(data, DataString());
|
|
}
|