/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013 Bolton Software Ltd. * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file COPYING that should have accompanied this file. * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // TODO: fix, tests failing intermittently on mac. #ifndef WINAPI_CARBON #include #include #include #include #include #include #define TEST_ENV #include "CLog.h" #include "CServer.h" #include "CClient.h" #include "TMethodEventJob.h" #include "server/CMockConfig.h" #include "server/CMockPrimaryClient.h" #include "synergy/CMockScreen.h" #include "CClientListener.h" #include "CNetworkAddress.h" #include "CTCPSocketFactory.h" #include "CCryptoOptions.h" #include "CSocketMultiplexer.h" #include "CTestEventQueue.h" #include "server/CMockInputFilter.h" #include "TMethodJob.h" #include "CThread.h" #include "CFileChunker.h" using namespace std; using ::testing::_; using ::testing::NiceMock; using ::testing::Return; using ::testing::Invoke; #define TEST_PORT 24803 #define TEST_HOST "localhost" const size_t kMockDataSize = 1024 * 1024 * 10; // 10MB const UInt16 kMockDataChunkIncrement = 1024; // 1KB const char* kMockFilename = "NetworkTests.mock"; const size_t kMockFileSize = 1024 * 1024 * 10; // 10MB void getScreenShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h); void getCursorPos(SInt32& x, SInt32& y); CString intToString(size_t i); UInt8* newMockData(size_t size); void createFile(fstream& file, const char* filename, size_t size); class NetworkTests : public ::testing::Test { public: NetworkTests() : m_mockData(NULL), m_mockDataSize(0), m_mockFileSize(0) { m_mockData = newMockData(kMockDataSize); createFile(m_mockFile, kMockFilename, kMockFileSize); } ~NetworkTests() { remove(kMockFilename); delete[] m_mockData; } void sendMockData(void* eventTarget); void sendToClient_mockData_handleClientConnected(const CEvent&, void* vlistener); void sendToClient_mockData_fileRecieveCompleted(const CEvent&, void*); void sendToClient_mockFile_handleClientConnected(const CEvent&, void* vlistener); void sendToClient_mockFile_fileRecieveCompleted(const CEvent& event, void*); void sendToServer_mockData_handleClientConnected(const CEvent&, void* vlistener); void sendToServer_mockData_fileRecieveCompleted(const CEvent& event, void*); void sendToServer_mockFile_handleClientConnected(const CEvent&, void* vlistener); void sendToServer_mockFile_fileRecieveCompleted(const CEvent& event, void*); public: CTestEventQueue m_events; UInt8* m_mockData; size_t m_mockDataSize; fstream m_mockFile; size_t m_mockFileSize; }; TEST_F(NetworkTests, sendToClient_mockData) { // server and client CNetworkAddress serverAddress(TEST_HOST, TEST_PORT); CCryptoOptions cryptoOptions; serverAddress.resolve(); // server CSocketMultiplexer serverSocketMultiplexer; CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer); CClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events); NiceMock serverScreen; NiceMock primaryClient; NiceMock serverConfig; NiceMock serverInputFilter; m_events.adoptHandler( m_events.forCClientListener().connected(), &listener, new TMethodEventJob( this, &NetworkTests::sendToClient_mockData_handleClientConnected, &listener)); ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); CServer server(serverConfig, &primaryClient, &serverScreen, &m_events, true); server.m_mock = true; listener.setServer(&server); // client NiceMock clientScreen; CSocketMultiplexer clientSocketMultiplexer; CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions, true); m_events.adoptHandler( m_events.forIScreen().fileRecieveCompleted(), &client, new TMethodEventJob( this, &NetworkTests::sendToClient_mockData_fileRecieveCompleted)); client.connect(); m_events.initQuitTimeout(10); m_events.loop(); m_events.removeHandler(m_events.forCClientListener().connected(), &listener); m_events.removeHandler(m_events.forIScreen().fileRecieveCompleted(), &client); m_events.cleanupQuitTimeout(); } TEST_F(NetworkTests, sendToClient_mockFile) { // server and client CNetworkAddress serverAddress(TEST_HOST, TEST_PORT); CCryptoOptions cryptoOptions; serverAddress.resolve(); // server CSocketMultiplexer serverSocketMultiplexer; CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer); CClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events); NiceMock serverScreen; NiceMock primaryClient; NiceMock serverConfig; NiceMock serverInputFilter; m_events.adoptHandler( m_events.forCClientListener().connected(), &listener, new TMethodEventJob( this, &NetworkTests::sendToClient_mockFile_handleClientConnected, &listener)); ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); CServer server(serverConfig, &primaryClient, &serverScreen, &m_events, true); server.m_mock = true; listener.setServer(&server); // client NiceMock clientScreen; CSocketMultiplexer clientSocketMultiplexer; CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions, true); m_events.adoptHandler( m_events.forIScreen().fileRecieveCompleted(), &client, new TMethodEventJob( this, &NetworkTests::sendToClient_mockFile_fileRecieveCompleted)); client.connect(); m_events.initQuitTimeout(10); m_events.loop(); m_events.removeHandler(m_events.forCClientListener().connected(), &listener); m_events.removeHandler(m_events.forIScreen().fileRecieveCompleted(), &client); m_events.cleanupQuitTimeout(); } TEST_F(NetworkTests, sendToServer_mockData) { // server and client CNetworkAddress serverAddress(TEST_HOST, TEST_PORT); CCryptoOptions cryptoOptions; serverAddress.resolve(); // server CSocketMultiplexer serverSocketMultiplexer; CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer); CClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events); NiceMock serverScreen; NiceMock primaryClient; NiceMock serverConfig; NiceMock serverInputFilter; ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); CServer server(serverConfig, &primaryClient, &serverScreen, &m_events, true); server.m_mock = true; listener.setServer(&server); // client NiceMock clientScreen; CSocketMultiplexer clientSocketMultiplexer; CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions, true); m_events.adoptHandler( m_events.forCClientListener().connected(), &listener, new TMethodEventJob( this, &NetworkTests::sendToServer_mockData_handleClientConnected, &client)); m_events.adoptHandler( m_events.forIScreen().fileRecieveCompleted(), &server, new TMethodEventJob( this, &NetworkTests::sendToServer_mockData_fileRecieveCompleted)); client.connect(); m_events.initQuitTimeout(10); m_events.loop(); m_events.removeHandler(m_events.forCClientListener().connected(), &listener); m_events.removeHandler(m_events.forIScreen().fileRecieveCompleted(), &server); m_events.cleanupQuitTimeout(); } TEST_F(NetworkTests, sendToServer_mockFile) { // server and client CNetworkAddress serverAddress(TEST_HOST, TEST_PORT); CCryptoOptions cryptoOptions; serverAddress.resolve(); // server CSocketMultiplexer serverSocketMultiplexer; CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer); CClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events); NiceMock serverScreen; NiceMock primaryClient; NiceMock serverConfig; NiceMock serverInputFilter; ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); CServer server(serverConfig, &primaryClient, &serverScreen, &m_events, true); server.m_mock = true; listener.setServer(&server); // client NiceMock clientScreen; CSocketMultiplexer clientSocketMultiplexer; CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions, true); m_events.adoptHandler( m_events.forCClientListener().connected(), &listener, new TMethodEventJob( this, &NetworkTests::sendToServer_mockFile_handleClientConnected, &client)); m_events.adoptHandler( m_events.forIScreen().fileRecieveCompleted(), &server, new TMethodEventJob( this, &NetworkTests::sendToServer_mockFile_fileRecieveCompleted)); client.connect(); m_events.initQuitTimeout(10); m_events.loop(); m_events.removeHandler(m_events.forCClientListener().connected(), &listener); m_events.removeHandler(m_events.forIScreen().fileRecieveCompleted(), &server); m_events.cleanupQuitTimeout(); } void NetworkTests::sendToClient_mockData_handleClientConnected(const CEvent&, void* vlistener) { CClientListener* listener = reinterpret_cast(vlistener); CServer* server = listener->getServer(); CClientProxy* client = listener->getNextClient(); if (client == NULL) { throw runtime_error("client is null"); } CBaseClientProxy* bcp = reinterpret_cast(client); server->adoptClient(bcp); server->setActive(bcp); sendMockData(server); } void NetworkTests::sendToClient_mockData_fileRecieveCompleted(const CEvent& event, void*) { CClient* client = reinterpret_cast(event.getTarget()); EXPECT_TRUE(client->isReceivedFileSizeValid()); m_events.raiseQuitEvent(); } void NetworkTests::sendToClient_mockFile_handleClientConnected(const CEvent&, void* vlistener) { CClientListener* listener = reinterpret_cast(vlistener); CServer* server = listener->getServer(); CClientProxy* client = listener->getNextClient(); if (client == NULL) { throw runtime_error("client is null"); } CBaseClientProxy* bcp = reinterpret_cast(client); server->adoptClient(bcp); server->setActive(bcp); server->sendFileToClient(kMockFilename); } void NetworkTests::sendToClient_mockFile_fileRecieveCompleted(const CEvent& event, void*) { CClient* client = reinterpret_cast(event.getTarget()); EXPECT_TRUE(client->isReceivedFileSizeValid()); m_events.raiseQuitEvent(); } void NetworkTests::sendToServer_mockData_handleClientConnected(const CEvent&, void* vclient) { CClient* client = reinterpret_cast(vclient); sendMockData(client); } void NetworkTests::sendToServer_mockData_fileRecieveCompleted(const CEvent& event, void*) { CServer* server = reinterpret_cast(event.getTarget()); EXPECT_TRUE(server->isReceivedFileSizeValid()); m_events.raiseQuitEvent(); } void NetworkTests::sendToServer_mockFile_handleClientConnected(const CEvent&, void* vclient) { CClient* client = reinterpret_cast(vclient); client->sendFileToServer(kMockFilename); } void NetworkTests::sendToServer_mockFile_fileRecieveCompleted(const CEvent& event, void*) { CServer* server = reinterpret_cast(event.getTarget()); EXPECT_TRUE(server->isReceivedFileSizeValid()); m_events.raiseQuitEvent(); } void NetworkTests::sendMockData(void* eventTarget) { // send first message (file size) CString size = intToString(kMockDataSize); size_t sizeLength = size.size(); CFileChunker::CFileChunk* sizeMessage = new CFileChunker::CFileChunk(sizeLength + 2); char* chunkData = sizeMessage->m_chunk; chunkData[0] = kFileStart; memcpy(&chunkData[1], size.c_str(), sizeLength); chunkData[sizeLength + 1] = '\0'; m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), eventTarget, sizeMessage)); // send chunk messages with incrementing chunk size size_t lastSize = 0; size_t sentLength = 0; while (true) { size_t chunkSize = lastSize + kMockDataChunkIncrement; // make sure we don't read too much from the mock data. if (sentLength + chunkSize > kMockDataSize) { chunkSize = kMockDataSize - sentLength; } // first byte is the chunk mark, last is \0 CFileChunker::CFileChunk* fileChunk = new CFileChunker::CFileChunk(chunkSize + 2); char* chunkData = fileChunk->m_chunk; chunkData[0] = kFileChunk; memcpy(&chunkData[1], &m_mockData[sentLength], chunkSize); chunkData[chunkSize + 1] = '\0'; m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), eventTarget, fileChunk)); sentLength += chunkSize; lastSize = chunkSize; if (sentLength == kMockDataSize) { break; } } // send last message CFileChunker::CFileChunk* transferFinished = new CFileChunker::CFileChunk(2); chunkData = transferFinished->m_chunk; chunkData[0] = kFileEnd; chunkData[1] = '\0'; m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), eventTarget, transferFinished)); } UInt8* newMockData(size_t size) { UInt8* buffer = new UInt8[size]; UInt8* data = buffer; const UInt8 head[] = "mock head... "; size_t headSize = sizeof(head) - 1; const UInt8 tail[] = "... mock tail"; size_t tailSize = sizeof(tail) - 1; const UInt8 synergyRocks[] = "synergy\0 rocks! "; size_t synergyRocksSize = sizeof(synergyRocks) - 1; memcpy(data, head, headSize); data += headSize; size_t times = (size - headSize - tailSize) / synergyRocksSize; for (size_t i = 0; i < times; ++i) { memcpy(data, synergyRocks, synergyRocksSize); data += synergyRocksSize; } size_t remainder = (size - headSize - tailSize) % synergyRocksSize; if (remainder != 0) { memset(data, '.', remainder); data += remainder; } memcpy(data, tail, tailSize); return buffer; } void createFile(fstream& file, const char* filename, size_t size) { UInt8* buffer = newMockData(size); file.open(filename, ios::out | ios::binary); if (!file.is_open()) { throw runtime_error("file not open"); } file.write(reinterpret_cast(buffer), size); file.close(); delete[] buffer; } void getScreenShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) { x = 0; y = 0; w = 1; h = 1; } void getCursorPos(SInt32& x, SInt32& y) { x = 0; y = 0; } CString intToString(size_t i) { stringstream ss; ss << i; return ss.str(); } #endif // WINAPI_CARBON