// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "base/basictypes.h" #include "base/message_loop.h" #include "base/metrics/statistics_recorder.h" #include "net/base/net_test_suite.h" #include "net/base/test_completion_callback.h" #include "net/curvecp/circular_buffer.h" #include "net/curvecp/received_block_list.h" #include "net/curvecp/rtt_and_send_rate_calculator.h" #include "net/curvecp/test_client.h" #include "net/curvecp/test_server.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" namespace net { class CurveCPTransferTest : public PlatformTest { public: CurveCPTransferTest() {} }; void RunEchoTest(int bytes) { TestServer server; TestClient client; EXPECT_TRUE(server.Start(1234)); HostPortPair server_address("localhost", 1234); TestCompletionCallback cb; EXPECT_TRUE(client.Start(server_address, bytes, cb.callback())); int rv = cb.WaitForResult(); EXPECT_EQ(0, rv); EXPECT_EQ(0, server.error_count()); EXPECT_EQ(0, client.error_count()); } /* TEST_F(CurveCPTransferTest, Echo_50B_Of_Data) { RunEchoTest(50); } TEST_F(CurveCPTransferTest, Echo_1KB_Of_Data) { RunEchoTest(1024); } TEST_F(CurveCPTransferTest, Echo_4KB_Of_Data) { RunEchoTest(4096); } */ // XXXMB TEST_F(CurveCPTransferTest, Echo_1MB_Of_Data) { RunEchoTest(1024*1024); } // TODO(mbelshe): Do something meaningful with this test. TEST_F(CurveCPTransferTest, RTTIntial) { RttAndSendRateCalculator rate; printf("initial %d (%d, %d/%d)\n", rate.send_rate(), rate.rtt_average(), rate.rtt_lo(), rate.rtt_hi()); for (int i = 0; i < 10; ++i) { rate.OnMessage(100*1000); printf("%d: %d (%d, %d/%d)\n", i, rate.send_rate(), rate.rtt_average(), rate.rtt_lo(), rate.rtt_hi()); usleep(200000); } rate.OnTimeout(); rate.OnTimeout(); rate.OnTimeout(); rate.OnTimeout(); // Get worse for (int i = 0; i < 10; ++i) { rate.OnMessage((500 + i)*1000); printf("%d: %d (%d, %d/%d)\n", i, rate.send_rate(), rate.rtt_average(), rate.rtt_lo(), rate.rtt_hi()); usleep(200000); } // Get better for (int i = 0; i < 10; ++i) { rate.OnMessage((100 - i)*1000); printf("%d: %d (%d, %d/%d)\n", i, rate.send_rate(), rate.rtt_average(), rate.rtt_lo(), rate.rtt_hi()); usleep(200000); } } TEST_F(CurveCPTransferTest, CircularBufferFillAndDrain) { CircularBuffer buffer(10); for (int i = 0; i < 30; ++i) { EXPECT_EQ(0, buffer.length()); EXPECT_EQ(3, buffer.write("abc", 3)); EXPECT_EQ(3, buffer.length()); char read_data[3]; EXPECT_EQ(3, buffer.read(read_data, 3)); EXPECT_EQ(0, memcmp(read_data, "abc", 3)); } } TEST_F(CurveCPTransferTest, CircularBufferTooLargeFill) { CircularBuffer buffer(10); EXPECT_EQ(10, buffer.write("abcdefghijklm", 13)); EXPECT_EQ(0, buffer.write("a", 1)); char read_data[10]; EXPECT_EQ(10, buffer.read(read_data, 10)); EXPECT_EQ(0, memcmp(read_data, "abcdefghij", 10)); EXPECT_EQ(1, buffer.write("a", 1)); } TEST_F(CurveCPTransferTest, CircularBufferEdgeCases) { CircularBuffer buffer(10); char read_data[10]; EXPECT_EQ(9, buffer.write("abcdefghi", 9)); EXPECT_EQ(9, buffer.read(read_data, 10)); EXPECT_EQ(0, memcmp(read_data, "abcdefghi", 9)); EXPECT_EQ(1, buffer.write("a", 1)); EXPECT_EQ(1, buffer.write("b", 1)); EXPECT_EQ(2, buffer.read(read_data, 10)); EXPECT_EQ(0, memcmp(read_data, "ab", 2)); } TEST_F(CurveCPTransferTest, CircularBufferOneWriteTwoReads) { CircularBuffer buffer(1000); char read_data[10]; EXPECT_EQ(13, buffer.write("abcdefghijklm", 13)); EXPECT_EQ(10, buffer.read(read_data, 10)); EXPECT_EQ(0, memcmp(read_data, "abcdefghij", 10)); EXPECT_EQ(3, buffer.read(read_data, 10)); EXPECT_EQ(0, memcmp(read_data, "klm", 3)); } TEST_F(CurveCPTransferTest, CircularBufferTwoWritesOneRead) { CircularBuffer buffer(1000); char read_data[10]; EXPECT_EQ(6, buffer.write("abcdef", 6)); EXPECT_EQ(4, buffer.write("ghij", 4)); EXPECT_EQ(10, buffer.read(read_data, 10)); EXPECT_EQ(0, memcmp(read_data, "abcdefghij", 10)); } TEST_F(CurveCPTransferTest, CircularBufferFillOnSpill) { CircularBuffer buffer(10); char read_data[10]; EXPECT_EQ(10, buffer.write("abcdefghij", 10)); EXPECT_EQ(3, buffer.read(read_data, 3)); EXPECT_EQ(0, memcmp(read_data, "abc", 3)); // We now have a hole at the head of the circular buffer. EXPECT_EQ(1, buffer.write("x", 1)); EXPECT_EQ(1, buffer.write("y", 1)); EXPECT_EQ(1, buffer.write("z", 1)); EXPECT_EQ(0, buffer.write("q", 1)); // Overflow EXPECT_EQ(10, buffer.read(read_data, 10)); EXPECT_EQ(0, memcmp(read_data, "defghijxyz", 10)); } TEST_F(CurveCPTransferTest, ReceivedBlockList) { scoped_refptr buffer(new IOBufferWithSize(16)); memcpy(buffer->data(), "abcdefghijklmnop", 16); scoped_refptr read_buffer(new IOBufferWithSize(100)); ReceivedBlockList list; EXPECT_EQ(0, list.current_position()); list.AddBlock(0, buffer, 16); EXPECT_EQ(0, list.current_position()); list.AddBlock(0, buffer, 16); EXPECT_EQ(16, list.ReadBytes(read_buffer.get(), read_buffer->size())); EXPECT_EQ(0, memcmp(buffer->data(), read_buffer->data(), 16)); EXPECT_EQ(16, list.current_position()); } TEST_F(CurveCPTransferTest, ReceivedBlockListCoalesce) { scoped_refptr buffer(new IOBufferWithSize(8)); memcpy(buffer->data(), "abcdefgh", 8); scoped_refptr read_buffer(new IOBufferWithSize(100)); ReceivedBlockList list; EXPECT_EQ(0, list.current_position()); list.AddBlock(0, buffer, 8); EXPECT_EQ(0, list.current_position()); list.AddBlock(8, buffer, 8); EXPECT_EQ(16, list.ReadBytes(read_buffer.get(), read_buffer->size())); EXPECT_EQ(0, memcmp(buffer->data(), read_buffer->data(), 8)); EXPECT_EQ(0, memcmp(buffer->data(), read_buffer->data() + 8, 8)); EXPECT_EQ(16, list.current_position()); } TEST_F(CurveCPTransferTest, ReceivedBlockListGap) { scoped_refptr buffer(new IOBufferWithSize(8)); memcpy(buffer->data(), "abcdefgh", 8); scoped_refptr read_buffer(new IOBufferWithSize(100)); ReceivedBlockList list; EXPECT_EQ(0, list.current_position()); list.AddBlock(0, buffer, 8); EXPECT_EQ(0, list.current_position()); // Leaves a gap list.AddBlock(16, buffer, 8); EXPECT_EQ(8, list.ReadBytes(read_buffer.get(), read_buffer->size())); EXPECT_EQ(0, list.ReadBytes(read_buffer.get(), read_buffer->size())); EXPECT_EQ(8, list.current_position()); // Fill the gap list.AddBlock(8, buffer, 8); EXPECT_EQ(16, list.ReadBytes(read_buffer.get(), read_buffer->size())); EXPECT_EQ(0, memcmp(buffer->data(), read_buffer->data(), 8)); EXPECT_EQ(0, memcmp(buffer->data(), read_buffer->data() + 8, 8)); EXPECT_EQ(24, list.current_position()); } TEST_F(CurveCPTransferTest, ReceivedBlockListPartialRead) { scoped_refptr buffer(new IOBufferWithSize(8)); memcpy(buffer->data(), "abcdefgh", 8); scoped_refptr read_buffer(new IOBufferWithSize(100)); ReceivedBlockList list; EXPECT_EQ(0, list.current_position()); list.AddBlock(0, buffer, 8); EXPECT_EQ(0, list.current_position()); list.AddBlock(8, buffer, 8); EXPECT_EQ(3, list.ReadBytes(read_buffer.get(), 3)); EXPECT_EQ(0, memcmp("abc", read_buffer->data(), 3)); EXPECT_EQ(3, list.ReadBytes(read_buffer.get(), 3)); EXPECT_EQ(0, memcmp("def", read_buffer->data(), 3)); EXPECT_EQ(3, list.ReadBytes(read_buffer.get(), 3)); EXPECT_EQ(0, memcmp("gha", read_buffer->data(), 3)); EXPECT_EQ(3, list.ReadBytes(read_buffer.get(), 3)); EXPECT_EQ(0, memcmp("bcd", read_buffer->data(), 3)); EXPECT_EQ(3, list.ReadBytes(read_buffer.get(), 3)); EXPECT_EQ(0, memcmp("efg", read_buffer->data(), 3)); EXPECT_EQ(1, list.ReadBytes(read_buffer.get(), 3)); EXPECT_EQ(0, memcmp("h", read_buffer->data(), 1)); EXPECT_EQ(16, list.current_position()); } /* class PollTimerTester { public: PollTimerTester() { Test(); } void Test() { struct pollfd fds[3]; memset(fds, 0, sizeof(struct pollfd) * 3); while(true) { (void)poll(fds, 1, 2); base::TimeTicks now(base::TimeTicks::Now()); if (!last_.is_null()) { LOG(ERROR) << "Time was " << (now - last_).InMicroseconds(); LOG(ERROR) << "Time was " << (now - last_).InMilliseconds(); } last_ = now; } } base::TimeTicks last_; }; class TimerTester { public: TimerTester() { timer_.Start(base::TimeDelta(), this, &TimerTester::OnTimer); } void OnTimer() { base::TimeTicks now(base::TimeTicks::Now()); if (!last_.is_null()) { LOG(ERROR) << "Time was " << (now - last_).InMicroseconds(); LOG(ERROR) << "Time was " << (now - last_).InMilliseconds(); } last_ = now; //timer_.Start(base::TimeDelta(), this, &TimerTester::OnTimer); timer_.Start(base::TimeDelta::FromMicroseconds(150), this, &TimerTester::OnTimer); } base::TimeTicks last_; base::OneShotTimer timer_; }; TEST_F(CurveCPTransferTest, MinTimer) { PollTimerTester tester; MessageLoop::current()->Run(); } */ } // namespace net int main(int argc, char**argv) { base::StatisticsRecorder::Initialize(); NetTestSuite test_suite(argc, argv); return test_suite.Run(); }