Index: remoting/host/security_key/security_key_auth_handler_linux_unittest.cc |
diff --git a/remoting/host/security_key/security_key_auth_handler_linux_unittest.cc b/remoting/host/security_key/security_key_auth_handler_linux_unittest.cc |
index 1d36b286f5ff2c99241924b8ff2607afa4415bb7..85798f88123a071dc9f1988f7b4ca9574c12db1b 100644 |
--- a/remoting/host/security_key/security_key_auth_handler_linux_unittest.cc |
+++ b/remoting/host/security_key/security_key_auth_handler_linux_unittest.cc |
@@ -4,12 +4,15 @@ |
#include <stddef.h> |
+#include "base/bind.h" |
+#include "base/bind_helpers.h" |
#include "base/files/file_path.h" |
#include "base/files/scoped_temp_dir.h" |
#include "base/macros.h" |
#include "base/message_loop/message_loop.h" |
#include "base/run_loop.h" |
#include "base/strings/stringprintf.h" |
+#include "base/threading/thread.h" |
#include "base/timer/mock_timer.h" |
#include "base/values.h" |
#include "net/base/io_buffer.h" |
@@ -25,6 +28,8 @@ namespace remoting { |
namespace { |
+const size_t kReadBufferSize = 1; |
+ |
const char kSocketFilename[] = "socket_for_testing"; |
// Test security key request data. |
@@ -48,75 +53,38 @@ const unsigned char kRequestData[] = { |
class SecurityKeyAuthHandlerLinuxTest : public testing::Test { |
public: |
- SecurityKeyAuthHandlerLinuxTest() |
- : run_loop_(new base::RunLoop()), last_connection_id_received_(-1) { |
- EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); |
- socket_path_ = temp_dir_.path().Append(kSocketFilename); |
- remoting::SecurityKeyAuthHandler::SetSecurityKeySocketName(socket_path_); |
- |
- send_message_callback_ = |
- base::Bind(&SecurityKeyAuthHandlerLinuxTest::SendMessageToClient, |
- base::Unretained(this)); |
- auth_handler_ = remoting::SecurityKeyAuthHandler::Create( |
- nullptr, send_message_callback_); |
- } |
+ SecurityKeyAuthHandlerLinuxTest(); |
- void WaitForSendMessageToClient() { |
- run_loop_->Run(); |
- run_loop_.reset(new base::RunLoop); |
- } |
- |
- void SendMessageToClient(int connection_id, const std::string& data) { |
- last_connection_id_received_ = connection_id; |
- last_message_received_ = data; |
- run_loop_->Quit(); |
- } |
+ // Creates a new socket and waits until it is ready to accept new connections. |
+ void CreateSocketAndWait(); |
- void CheckHostDataMessage(int id, const std::string& expected_data) { |
- ASSERT_EQ(id, last_connection_id_received_); |
- ASSERT_EQ(expected_data.length(), last_message_received_.length()); |
- ASSERT_EQ(expected_data, last_message_received_); |
- } |
+ // Used as a callback |auth_handler_|, stores the values received. |
+ void SendMessageToClient(int connection_id, const std::string& data); |
- void WriteRequestData(net::UnixDomainClientSocket* client_socket) { |
- int request_len = sizeof(kRequestData); |
- scoped_refptr<net::DrainableIOBuffer> request_buffer( |
- new net::DrainableIOBuffer( |
- new net::WrappedIOBuffer( |
- reinterpret_cast<const char*>(kRequestData)), |
- request_len)); |
- net::TestCompletionCallback write_callback; |
- int bytes_written = 0; |
- while (bytes_written < request_len) { |
- int write_result = client_socket->Write(request_buffer.get(), |
- request_buffer->BytesRemaining(), |
- write_callback.callback()); |
- write_result = write_callback.GetResult(write_result); |
- ASSERT_GT(write_result, 0); |
- bytes_written += write_result; |
- ASSERT_LE(bytes_written, request_len); |
- request_buffer->DidConsume(write_result); |
- } |
- ASSERT_EQ(request_len, bytes_written); |
- } |
+ // Writes |kRequestData| to |client_socket|. |
+ void WriteRequestData(net::UnixDomainClientSocket* client_socket); |
- void WaitForAndVerifyHostMessage(int connection_id) { |
- WaitForSendMessageToClient(); |
- std::string expected_data; |
- expected_data.reserve(sizeof(kRequestData) - 4); |
+ // Helper method which validates message data once it has been received. |
+ void WaitForAndVerifyHostMessage(int connection_id); |
- // Skip first four bytes and build up the response string. |
- for (size_t i = 4; i < sizeof(kRequestData); ++i) { |
- expected_data.append(1, static_cast<unsigned char>(kRequestData[i])); |
- } |
+ // Waits until all existing posted tasks on |file_thread_| have been run. |
+ void WaitForExistingSocketOperations(); |
- CheckHostDataMessage(connection_id, expected_data); |
- } |
+ // Waits until |client_socket| has been closed. |
+ void WaitForConnectionClosed(net::UnixDomainClientSocket* client_socket); |
protected: |
+ // Waits for |SendMessageToClient()| to be signaled. |
+ void WaitForSendMessageToClient(); |
+ |
+ // Verfies the data passed to the |SendMessageToClient| callback was valid. |
+ void CheckHostDataMessage(int id, const std::string& expected_data); |
+ |
base::MessageLoopForIO message_loop_; |
std::unique_ptr<base::RunLoop> run_loop_; |
+ base::Thread file_thread_; |
+ |
// Object under test. |
std::unique_ptr<SecurityKeyAuthHandler> auth_handler_; |
@@ -133,16 +101,127 @@ class SecurityKeyAuthHandlerLinuxTest : public testing::Test { |
DISALLOW_COPY_AND_ASSIGN(SecurityKeyAuthHandlerLinuxTest); |
}; |
-TEST_F(SecurityKeyAuthHandlerLinuxTest, NotClosedAfterRequest) { |
+SecurityKeyAuthHandlerLinuxTest::SecurityKeyAuthHandlerLinuxTest() |
+ : run_loop_(new base::RunLoop()), |
+ file_thread_("SecurityKeyAuthHandlerLinuxTest_FileThread"), |
+ last_connection_id_received_(-1) { |
+ EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); |
+ socket_path_ = temp_dir_.path().Append(kSocketFilename); |
+ remoting::SecurityKeyAuthHandler::SetSecurityKeySocketName(socket_path_); |
+ |
+ file_thread_.StartWithOptions( |
+ base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); |
+ |
+ send_message_callback_ = |
+ base::Bind(&SecurityKeyAuthHandlerLinuxTest::SendMessageToClient, |
+ base::Unretained(this)); |
+ |
+ auth_handler_ = remoting::SecurityKeyAuthHandler::Create( |
+ /*client_session_details=*/nullptr, send_message_callback_, |
+ file_thread_.task_runner()); |
+} |
+ |
+void SecurityKeyAuthHandlerLinuxTest::WaitForExistingSocketOperations() { |
+ ASSERT_TRUE(file_thread_.task_runner()->PostTaskAndReply( |
+ FROM_HERE, base::Bind(&base::DoNothing), run_loop_->QuitClosure())); |
+ run_loop_->Run(); |
+ run_loop_.reset(new base::RunLoop); |
+} |
+ |
+void SecurityKeyAuthHandlerLinuxTest::CreateSocketAndWait() { |
ASSERT_EQ(0u, auth_handler_->GetActiveConnectionCountForTest()); |
auth_handler_->CreateSecurityKeyConnection(); |
+ WaitForExistingSocketOperations(); |
+ |
+ ASSERT_EQ(0u, auth_handler_->GetActiveConnectionCountForTest()); |
+} |
+ |
+void SecurityKeyAuthHandlerLinuxTest::SendMessageToClient( |
+ int connection_id, |
+ const std::string& data) { |
+ last_connection_id_received_ = connection_id; |
+ last_message_received_ = data; |
+ run_loop_->Quit(); |
+} |
+ |
+void SecurityKeyAuthHandlerLinuxTest::WaitForSendMessageToClient() { |
+ run_loop_->Run(); |
+ run_loop_.reset(new base::RunLoop); |
+} |
+ |
+void SecurityKeyAuthHandlerLinuxTest::WriteRequestData( |
+ net::UnixDomainClientSocket* client_socket) { |
+ int request_len = sizeof(kRequestData); |
+ scoped_refptr<net::DrainableIOBuffer> request_buffer( |
+ new net::DrainableIOBuffer( |
+ new net::WrappedIOBuffer(reinterpret_cast<const char*>(kRequestData)), |
+ request_len)); |
+ net::TestCompletionCallback write_callback; |
+ int bytes_written = 0; |
+ while (bytes_written < request_len) { |
+ int write_result = client_socket->Write(request_buffer.get(), |
+ request_buffer->BytesRemaining(), |
+ write_callback.callback()); |
+ write_result = write_callback.GetResult(write_result); |
+ ASSERT_GT(write_result, 0); |
+ bytes_written += write_result; |
+ ASSERT_LE(bytes_written, request_len); |
+ request_buffer->DidConsume(write_result); |
+ } |
+ ASSERT_EQ(request_len, bytes_written); |
+} |
+ |
+void SecurityKeyAuthHandlerLinuxTest::CheckHostDataMessage( |
+ int id, |
+ const std::string& expected_data) { |
+ ASSERT_EQ(id, last_connection_id_received_); |
+ ASSERT_EQ(expected_data.length(), last_message_received_.length()); |
+ ASSERT_EQ(expected_data, last_message_received_); |
+} |
+ |
+void SecurityKeyAuthHandlerLinuxTest::WaitForAndVerifyHostMessage( |
+ int connection_id) { |
+ WaitForSendMessageToClient(); |
+ std::string expected_data; |
+ expected_data.reserve(sizeof(kRequestData) - 4); |
+ |
+ // Skip first four bytes and build up the response string. |
+ for (size_t i = 4; i < sizeof(kRequestData); ++i) { |
+ expected_data.append(1, static_cast<unsigned char>(kRequestData[i])); |
+ } |
+ |
+ CheckHostDataMessage(connection_id, expected_data); |
+} |
+ |
+void SecurityKeyAuthHandlerLinuxTest::WaitForConnectionClosed( |
+ net::UnixDomainClientSocket* client_socket) { |
+ // Ensure there are no pending operations. |
+ WaitForExistingSocketOperations(); |
+ |
+ // Create a blocking read operation to wait until the socket has been closed. |
+ scoped_refptr<net::IOBuffer> read_buffer(new net::IOBuffer(kReadBufferSize)); |
+ net::TestCompletionCallback read_callback; |
+ int read_result = client_socket->Read(read_buffer.get(), kReadBufferSize, |
+ read_callback.callback()); |
+ |
+ // GetResult blocks until the IO is no longer pending. |
+ read_result = read_callback.GetResult(read_result); |
+ ASSERT_EQ(read_result, static_cast<int>(kReadBufferSize)); |
+ ASSERT_TRUE(std::string(read_buffer->data()).empty()); |
+ |
+ // Ensure all current and pending operations are complete. |
+ WaitForExistingSocketOperations(); |
+} |
+ |
+TEST_F(SecurityKeyAuthHandlerLinuxTest, NotClosedAfterRequest) { |
+ CreateSocketAndWait(); |
net::UnixDomainClientSocket client_socket(socket_path_.value(), false); |
net::TestCompletionCallback connect_callback; |
- |
int rv = client_socket.Connect(connect_callback.callback()); |
ASSERT_EQ(net::OK, connect_callback.GetResult(rv)); |
+ WaitForExistingSocketOperations(); |
// Write the request and verify the response. |
WriteRequestData(&client_socket); |
@@ -156,15 +235,13 @@ TEST_F(SecurityKeyAuthHandlerLinuxTest, NotClosedAfterRequest) { |
} |
TEST_F(SecurityKeyAuthHandlerLinuxTest, HandleTwoRequests) { |
- ASSERT_EQ(0u, auth_handler_->GetActiveConnectionCountForTest()); |
- |
- auth_handler_->CreateSecurityKeyConnection(); |
+ CreateSocketAndWait(); |
net::UnixDomainClientSocket client_socket(socket_path_.value(), false); |
net::TestCompletionCallback connect_callback; |
- |
int rv = client_socket.Connect(connect_callback.callback()); |
ASSERT_EQ(net::OK, connect_callback.GetResult(rv)); |
+ WaitForExistingSocketOperations(); |
// Write the request and verify the response. |
WriteRequestData(&client_socket); |
@@ -186,15 +263,13 @@ TEST_F(SecurityKeyAuthHandlerLinuxTest, HandleTwoRequests) { |
} |
TEST_F(SecurityKeyAuthHandlerLinuxTest, HandleTwoIndependentRequests) { |
- ASSERT_EQ(0u, auth_handler_->GetActiveConnectionCountForTest()); |
- |
- auth_handler_->CreateSecurityKeyConnection(); |
+ CreateSocketAndWait(); |
net::UnixDomainClientSocket client_socket(socket_path_.value(), false); |
net::TestCompletionCallback connect_callback; |
- |
int rv = client_socket.Connect(connect_callback.callback()); |
ASSERT_EQ(net::OK, connect_callback.GetResult(rv)); |
+ WaitForExistingSocketOperations(); |
// Write the request and verify the response. |
WriteRequestData(&client_socket); |
@@ -207,6 +282,7 @@ TEST_F(SecurityKeyAuthHandlerLinuxTest, HandleTwoIndependentRequests) { |
client_socket.Disconnect(); |
rv = client_socket.Connect(connect_callback.callback()); |
ASSERT_EQ(net::OK, connect_callback.GetResult(rv)); |
+ WaitForExistingSocketOperations(); |
// Repeat the request/response cycle. |
WriteRequestData(&client_socket); |
@@ -220,28 +296,64 @@ TEST_F(SecurityKeyAuthHandlerLinuxTest, HandleTwoIndependentRequests) { |
ASSERT_EQ(1u, auth_handler_->GetActiveConnectionCountForTest()); |
} |
-TEST_F(SecurityKeyAuthHandlerLinuxTest, DidReadTimeout) { |
+TEST_F(SecurityKeyAuthHandlerLinuxTest, HandleNumerousIndependentRequests) { |
+ CreateSocketAndWait(); |
+ |
+ net::UnixDomainClientSocket client_socket(socket_path_.value(), false); |
+ net::TestCompletionCallback connect_callback; |
+ |
+ // Connection IDs start at 1 so start there to simplify the rest of the code. |
+ for (int i = 1; i < 11; i++) { |
+ int rv = client_socket.Connect(connect_callback.callback()); |
+ ASSERT_EQ(net::OK, connect_callback.GetResult(rv)); |
+ WaitForExistingSocketOperations(); |
+ |
+ // Verify the connection is now valid. |
+ ASSERT_TRUE(auth_handler_->IsValidConnectionId(i)); |
+ |
+ // Write the request and verify the response. |
+ WriteRequestData(&client_socket); |
+ WaitForAndVerifyHostMessage(i); |
+ |
+ // Disconnect and establish a new connection. |
+ client_socket.Disconnect(); |
+ WaitForExistingSocketOperations(); |
+ |
+ ASSERT_FALSE(auth_handler_->IsValidConnectionId(i)); |
+ } |
+ |
+ // Verify that the initial sockets were released properly. |
ASSERT_EQ(0u, auth_handler_->GetActiveConnectionCountForTest()); |
- auth_handler_->CreateSecurityKeyConnection(); |
+} |
+ |
+TEST_F(SecurityKeyAuthHandlerLinuxTest, DidReadTimeout) { |
+ auth_handler_->SetRequestTimeoutForTest(base::TimeDelta()); |
+ |
+ CreateSocketAndWait(); |
net::UnixDomainClientSocket client_socket(socket_path_.value(), false); |
net::TestCompletionCallback connect_callback; |
int rv = client_socket.Connect(connect_callback.callback()); |
ASSERT_EQ(net::OK, connect_callback.GetResult(rv)); |
- auth_handler_->SetRequestTimeoutForTest(base::TimeDelta()); |
+ WaitForConnectionClosed(&client_socket); |
+ |
ASSERT_EQ(0u, auth_handler_->GetActiveConnectionCountForTest()); |
} |
TEST_F(SecurityKeyAuthHandlerLinuxTest, ClientErrorMessageDelivered) { |
- ASSERT_EQ(0u, auth_handler_->GetActiveConnectionCountForTest()); |
- auth_handler_->CreateSecurityKeyConnection(); |
+ CreateSocketAndWait(); |
net::UnixDomainClientSocket client_socket(socket_path_.value(), false); |
net::TestCompletionCallback connect_callback; |
int rv = client_socket.Connect(connect_callback.callback()); |
ASSERT_EQ(net::OK, connect_callback.GetResult(rv)); |
+ WaitForExistingSocketOperations(); |
+ |
+ ASSERT_EQ(1u, auth_handler_->GetActiveConnectionCountForTest()); |
auth_handler_->SendErrorAndCloseConnection(1); |
+ WaitForConnectionClosed(&client_socket); |
+ |
ASSERT_EQ(0u, auth_handler_->GetActiveConnectionCountForTest()); |
} |