public void TestSendTinyMessage(bool clientSide) { SetupTestConnections(clientSide); Networking.Send(testLocalSocketState.TheSocket, "a"); Networking.GetData(testRemoteSocketState); WaitForOrTimeout(() => testRemoteSocketState.GetData().Length > 0, timeout); Assert.AreEqual("a", testRemoteSocketState.GetData()); }
public void TestConsecutiveSends(bool clientSide) { SetupTestConnections(clientSide); Networking.Send(testLocalSocketState.TheSocket, "a"); Networking.Send(testLocalSocketState.TheSocket, "b"); StartReceiveLoop(); WaitForOrTimeout(() => testRemoteSocketState.GetData().Length > 1, timeout); Assert.AreEqual("ab", testRemoteSocketState.GetData()); }
public void TestReceiveNewlines(bool clientSide) { SetupTestConnections(clientSide); testLocalSocketState.OnNetworkAction = (x) => { }; string message = "\na\n\nb\n"; Networking.Send(testRemoteSocketState.TheSocket, message); Networking.GetData(testLocalSocketState); WaitForOrTimeout(() => testLocalSocketState.GetData().Length > 1, timeout); Assert.AreEqual(message, testLocalSocketState.GetData()); }
public void TestSendHugeMessage(bool clientSide) { SetupTestConnections(clientSide); StringBuilder message = new StringBuilder(); message.Append('a', (int)(SocketState.BufferSize * 7.5)); Networking.Send(testLocalSocketState.TheSocket, message.ToString()); StartReceiveLoop(); WaitForOrTimeout(() => testRemoteSocketState.GetData().Length == message.Length, timeout); Assert.AreEqual(message.ToString(), testRemoteSocketState.GetData()); }
public void TestSendAndReceiveHugeMessage() { //Set up int sendTimes = 5; StringBuilder ans = new StringBuilder(); for (int i = 0; i < sendTimes; i++) { ans.Append((char)i, (int)(SocketState.BufferSize * 1.5)); } //establish connection NetworkTestHelper.SetupSingleConnectionTest(out TcpListener listener, out SocketState clt, out SocketState svr); // Receive loop in clt clt.OnNetworkAction = x => { //for error checking if (x.ErrorOccured) { return; } Networking.GetData(x); }; //clt start listening messages Networking.GetData(clt); //Start sending for (int i = 0; i < sendTimes; i++) { StringBuilder message = new StringBuilder(); message.Append((char)i, (int)(SocketState.BufferSize * 1.5)); Networking.Send(svr.TheSocket, message.ToString()); } //Wait here NetworkTestHelper.WaitForOrTimeout(() => clt.GetData().Length == SocketState.BufferSize * 1.5 * 5, NetworkTestHelper.timeout); //Check answer Assert.AreEqual(ans.ToString(), clt.GetData()); //clean up StopTestServer(listener, clt, svr); //wait Thread.Sleep(1); Assert.IsTrue(clt.ErrorOccured); }
public void TestNoEventLoop(bool clientSide) { SetupTestConnections(clientSide); int calledCount = 0; // This callMe will not ask for more data after receiving one message, // so it should only ever receive one message testLocalSocketState.OnNetworkAction = (x) => calledCount++; Networking.Send(testRemoteSocketState.TheSocket, "a"); Networking.GetData(testLocalSocketState); WaitForOrTimeout(() => testLocalSocketState.GetData().Length > 0, timeout); Networking.Send(testRemoteSocketState.TheSocket, "a"); WaitForOrTimeout(() => false, timeout); Assert.AreEqual(1, calledCount); }
public void TestReceiveRemovesAll(bool clientSide) { SetupTestConnections(clientSide, out testListener, out testLocalSocketState, out testRemoteSocketState); StringBuilder localCopy = new StringBuilder(); void removeMessage(SocketState state) { if (state.ErrorOccured) { return; } localCopy.Append(state.GetData()); state.RemoveData(0, state.GetData().Length); Networking.GetData(state); } testLocalSocketState.OnNetworkAction = removeMessage; // Start a receive loop Networking.GetData(testLocalSocketState); for (int i = 0; i < 10000; i++) { char c = (char)('a' + (i % 26)); Networking.Send(testRemoteSocketState.TheSocket, "" + c); } NetworkTestHelper.WaitForOrTimeout(() => localCopy.Length == 10000, NetworkTestHelper.timeout); // Reconstruct the original message outside the send loop // to (in theory) make the send operations happen more rapidly. StringBuilder message = new StringBuilder(); for (int i = 0; i < 10000; i++) { char c = (char)('a' + (i % 26)); message.Append(c); } Assert.AreEqual(message.ToString(), localCopy.ToString()); }
public void TestSendTinyMessage(bool clientSide) { SetupTestConnections(clientSide, out testListener, out testLocalSocketState, out testRemoteSocketState, 2117); // Set the action to do nothing testLocalSocketState.OnNetworkAction = x => { }; testRemoteSocketState.OnNetworkAction = x => { }; Networking.Send(testLocalSocketState.TheSocket, "a"); Networking.GetData(testRemoteSocketState); // Note that waiting for data like this is *NOT* how the networking library is // intended to be used. This is only for testing purposes. // Normally, you would provide an OnNetworkAction that handles the data. NetworkTestHelper.WaitForOrTimeout(() => testRemoteSocketState.GetData().Length > 0, NetworkTestHelper.timeout); Assert.AreEqual("a", testRemoteSocketState.GetData()); }
/*** Begin Integration Tests ***/ /* These tests use the student's code for both client and server */ /// <summary> /// Helper to simulate a server loop with one client /// </summary> private StringBuilder SingleClientServerLoop() { Random rand = new Random(0); StringBuilder serverSent = new StringBuilder(); // Start a stopwatch to simulate a game server's tick-rate System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); watch = new System.Diagnostics.Stopwatch(); watch.Start(); int nextChar = 0; // Run for 100 frames for (int frame = 0; frame < 100; frame++) { // Create several messages ranging in size between 0x - 1.5x the buffer size, StringBuilder messages = new StringBuilder(); for (int i = 0; i < 5; i++) { for (int j = 0; j < rand.Next((int)(SocketState.BufferSize * 1.5)); j++) { messages.Append((char)('a' + (nextChar++ % 26))); } // Newline separator indicates end of object messages.Append("\n"); } serverSent.Append(messages); Networking.Send(testRemoteSocketState.TheSocket, messages.ToString()); // Simulate a 60 FPS tick-rate while (watch.ElapsedMilliseconds < 17) { /* just waiting */ } watch.Restart(); } // end frame loop return(serverSent); }
public void TestChangeOnNetworkAction(bool clientSide) { SetupTestConnections(clientSide); int firstCalledCount = 0; int secondCalledCount = 0; void firstOnNetworkAction(SocketState state) { if (state.ErrorOccured) { return; } firstCalledCount++; state.OnNetworkAction = secondOnNetworkAction; Networking.GetData(testLocalSocketState); } void secondOnNetworkAction(SocketState state) { if (state.ErrorOccured) { return; } secondCalledCount++; } // Change the callMe after the first invokation testLocalSocketState.OnNetworkAction = firstOnNetworkAction; Networking.Send(testRemoteSocketState.TheSocket, "a"); Networking.GetData(testLocalSocketState); WaitForOrTimeout(() => firstCalledCount == 1, timeout); Networking.Send(testRemoteSocketState.TheSocket, "a"); WaitForOrTimeout(() => secondCalledCount == 1, timeout); Assert.AreEqual(1, firstCalledCount); Assert.AreEqual(1, secondCalledCount); }
public void TestNoEventLoop(bool clientSide) { SetupTestConnections(clientSide, out testListener, out testLocalSocketState, out testRemoteSocketState, 2115); int calledCount = 0; // This OnNetworkAction will not ask for more data after receiving one message, // so it should only ever receive one message testLocalSocketState.OnNetworkAction = (x) => calledCount++; Networking.Send(testRemoteSocketState.TheSocket, "a"); Networking.GetData(testLocalSocketState); // Note that waiting for data like this is *NOT* how the networking library is // intended to be used. This is only for testing purposes. // Normally, you would provide an OnNetworkAction that handles the data. NetworkTestHelper.WaitForOrTimeout(() => testLocalSocketState.GetData().Length > 0, NetworkTestHelper.timeout); // Send a second message (which should not increment calledCount) Networking.Send(testRemoteSocketState.TheSocket, "a"); NetworkTestHelper.WaitForOrTimeout(() => false, NetworkTestHelper.timeout); Assert.AreEqual(1, calledCount); }
public void TestRapidReceive(bool clientSide) { SetupTestConnections(clientSide); testLocalSocketState.OnNetworkAction = (x) => { if (x.ErrorOccured) { return; } Networking.GetData(x); }; Networking.GetData(testLocalSocketState); for (int i = 0; i < 10000; i++) { char c = (char)('a' + (i % 26)); Networking.Send(testRemoteSocketState.TheSocket, "" + c); } WaitForOrTimeout(() => testLocalSocketState.GetData().Length == 10000, timeout); // Reconstruct the original message outside the send loop // to (in theory) make the send operations happen more rapidly. StringBuilder message = new StringBuilder(); for (int i = 0; i < 10000; i++) { char c = (char)('a' + (i % 26)); message.Append(c); } Assert.AreEqual(message.ToString(), testLocalSocketState.GetData()); }
public void TestSendNullMessage() { NetworkTestHelper.SetupSingleConnectionTest(out testListener, out testLocalSocketState, out testRemoteSocketState); //Sending null value, should causes a Error in the RemoteState Assert.IsFalse(Networking.Send(testRemoteSocketState.TheSocket, null)); }
public void TestSimulateClientAndServer() { // For this test, we will use testRemoteSocketState as the server's SocketState // and testLocalSocketState as the client's SocketState Random rand = new Random(0); StringBuilder serverReceived = new StringBuilder(); StringBuilder clientReceived = new StringBuilder(); StringBuilder clientSent = new StringBuilder(); // Local function to serve as a callMe delegate void serverFirstContact(SocketState state) { if (state.ErrorOccured) { return; } // Save the socket state globally so that the Cleanup method can close it testRemoteSocketState = state; // Start a receive loop from the client state.OnNetworkAction = removeMessage; Networking.GetData(state); } // Local function to serve as a callMe delegate // Receive loop for the server that just removes and saves the client's messages void removeMessage(SocketState state) { if (state.ErrorOccured) { return; } serverReceived.Append(state.GetData()); state.RemoveData(0, state.GetData().Length); Networking.GetData(state); } // Local function to serve as a callMe delegate void clientFirstContact(SocketState state) { if (state.ErrorOccured) { return; } // Save the socket state globally so that the Cleanup method can close it testLocalSocketState = state; // Start a receive loop from the server state.OnNetworkAction = handleMessage; Networking.GetData(state); } // Local function to serve as a callMe delegate // Receive loop for the client that simualtes "processing" a message by // looking for a newline separator void handleMessage(SocketState state) { if (state.ErrorOccured) { return; } ProcessMessage(state, clientReceived); // Reply to the server about half of the time if (rand.Next(2) == 0) { StringBuilder reply = new StringBuilder(); for (int i = 0; i < rand.Next(10); i++) { reply.Append((char)('a' + rand.Next(26))); } reply.Append("\n"); clientSent.Append(reply); Networking.Send(state.TheSocket, reply.ToString()); } // Continue the receive loop Networking.GetData(state); } // Start the listener testListener = Networking.StartServer(serverFirstContact, 2112); // Start the client Networking.ConnectToServer(clientFirstContact, "localhost", 2112); // Wait for both sides to connect WaitForOrTimeout(() => testLocalSocketState != null && testRemoteSocketState != null, timeout); // Run the server loop StringBuilder serverSent = SingleClientServerLoop(); WaitForOrTimeout(() => clientReceived.Length == serverSent.Length, timeout); WaitForOrTimeout(() => clientSent.Length == serverReceived.Length, timeout); Assert.AreEqual(clientReceived.ToString(), serverSent.ToString()); Assert.AreEqual(clientSent.ToString(), serverReceived.ToString()); }
private void GameServer( out Dictionary <long, StringBuilder> serverSentMessages, out Dictionary <long, StringBuilder> serverReceivedMessages) { object serverConnectionsLock = new object(); Dictionary <long, SocketState> serverSocketStates = new Dictionary <long, SocketState>(); Dictionary <long, StringBuilder> sentMessages = new Dictionary <long, StringBuilder>(); Dictionary <long, StringBuilder> receivedMessages = new Dictionary <long, StringBuilder>(); Random rand = new Random(0); // Local function to serve as a callMe delegate void serverFirstContact(SocketState state) { if (state.ErrorOccured) { return; } // Save the socket state so we can broadcast to all clients // Also save the rest of the per-connection state for validating the test lock (serverConnectionsLock) { // Use one of the stringbuilder lists as a unique socket ID // since they will strictly grow (the SocketState lists will grow and shrink) //state.uid = sentMessages.Count; sentMessages[state.ID] = new StringBuilder(); receivedMessages[state.ID] = new StringBuilder(); serverSocketStates[state.ID] = state; // send the client's ID // important to do this inside the lock so the broadcast loop doesn't // run before sending the client's ID sentMessages[state.ID].Append("" + state.ID + "\n"); Networking.Send(state.TheSocket, "" + state.ID + "\n"); } // Start a receive loop from the client state.OnNetworkAction = removeMessage; Networking.GetData(state); } // Local function to serve as a callMe delegate // Receive loop for the server that just removes and saves the client's messages void removeMessage(SocketState state) { if (state.ErrorOccured) { return; } StringBuilder rcv; lock (serverConnectionsLock) { rcv = receivedMessages[state.ID]; } rcv.Append(state.GetData()); state.RemoveData(0, state.GetData().Length); Networking.GetData(state); } testListener = Networking.StartServer(serverFirstContact, 2112); // Start a stopwatch to simulate a game server's tick-rate System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); watch = new System.Diagnostics.Stopwatch(); watch.Start(); int nextChar = 0; // Run for 150 frames for (int frame = 0; frame < 150; frame++) { // Create several messages ranging in size between 0x - 0.5x the buffer size, StringBuilder messages = new StringBuilder(); for (int i = 0; i < 3; i++) { for (int j = 0; j < rand.Next((int)(SocketState.BufferSize * 0.5)); j++) { messages.Append((char)('a' + (nextChar++ % 26))); } // Newline separator indicates end of object messages.Append("\n"); } lock (serverConnectionsLock) { foreach (StringBuilder sb in sentMessages.Values) { sb.Append(messages); } foreach (SocketState ss in serverSocketStates.Values) { if (ss.TheSocket.Connected) { Networking.Send(ss.TheSocket, messages.ToString()); } } } // Simulate slow-ish server that gives the clients enough time to receive // between frames so that we can assume that everything sent is also received while (watch.ElapsedMilliseconds < 30) { /* just waiting */ } watch.Restart(); } // end frame loop serverSentMessages = sentMessages; serverReceivedMessages = receivedMessages; }
private void GameClients( out Dictionary <long, StringBuilder> clientSentMessages, out Dictionary <long, StringBuilder> clientReceivedMessages, out Dictionary <long, SocketState> clientSockets) { object clientConnectionsLock = new object(); //Dictionary<long, SocketState> clientSocketStates = new Dictionary<long, SocketState>(); Dictionary <long, StringBuilder> sentMessages = new Dictionary <long, StringBuilder>(); Dictionary <long, StringBuilder> receivedMessages = new Dictionary <long, StringBuilder>(); Dictionary <long, SocketState> sockets = new Dictionary <long, SocketState>(); Dictionary <long, Random> randoms = new Dictionary <long, Random>(); Dictionary <long, long> clientIDs = new Dictionary <long, long>(); Random rand = new Random(0); // Local function to serve as a callMe delegate void clientFirstContact(SocketState state) { if (state.ErrorOccured) { return; } // Start a receive loop from the server state.OnNetworkAction = handleMessage; Networking.GetData(state); } // Local function to serve as a callMe delegate // Receive loop for the client that simualtes "processing" a message by // looking for a newline separator void handleMessage(SocketState state) { if (state.ErrorOccured) { return; } lock (clientConnectionsLock) { // If this is the first message, save the per-connection state for validating the test if (!clientIDs.ContainsKey(state.ID)) { // first message contains ID clientIDs[state.ID] = int.Parse(state.GetData().Substring(0, state.GetData().IndexOf("\n") + 1)); sentMessages[clientIDs[state.ID]] = new StringBuilder(); receivedMessages[clientIDs[state.ID]] = new StringBuilder(); sockets[clientIDs[state.ID]] = state; randoms[clientIDs[state.ID]] = new Random((int)clientIDs[state.ID]); } } StringBuilder rcv, sent; Random rnd; lock (clientConnectionsLock) { rcv = receivedMessages[clientIDs[state.ID]]; sent = sentMessages[clientIDs[state.ID]]; rnd = randoms[clientIDs[state.ID]]; } ProcessMessage(state, rcv); // Decide if we will disconnect or not (1% chance) bool disconnect = rnd.Next(100) == 0; // Reply to the server about half of the time if (!disconnect && rnd.Next(2) == 0) { StringBuilder reply = new StringBuilder(); for (int i = 0; i < rand.Next(10); i++) { reply.Append((char)('a' + rand.Next(26))); } reply.Append("\n"); sent.Append(reply); Networking.Send(state.TheSocket, reply.ToString()); } // Continue the receive loop or disconnect if (disconnect) { state.TheSocket.Shutdown(SocketShutdown.Both); } else { Networking.GetData(state); } } // Start a stopwatch to simulate clients connecting and disconnecting over time System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); watch = new System.Diagnostics.Stopwatch(); watch.Start(); // 75 opportunities over time for clients to connect for (int i = 0; i < 75; i++) { // Connect 1 - 3 clients int numClients = 1 + rand.Next(3); for (int j = 0; j < numClients; j++) { Networking.ConnectToServer(clientFirstContact, "localhost", 2112); } while (watch.ElapsedMilliseconds < 30) { /* just waiting */ } watch.Restart(); } clientSentMessages = sentMessages; clientReceivedMessages = receivedMessages; clientSockets = sockets; }
public void TestTwoServers() { SocketState server2 = null; SocketState client2 = null; bool server2Connected = false; bool receive1Called = false; bool receive2Called = false; string client1Message = ""; string client2Message = ""; string server1Message = ""; string server2Message = ""; void Server2OnConnect(SocketState s) { if (s.ErrorOccured) { return; } server2Connected = true; server2 = s; server2.OnNetworkAction = Server2OnReceive; } void Client2OnConnect(SocketState s) { if (s.ErrorOccured) { return; } client2 = s; } void Server1OnReceive(SocketState s) { if (s.ErrorOccured) { return; } receive1Called = true; server1Message = s.GetData(); } void Server2OnReceive(SocketState s) { if (s.ErrorOccured) { return; } receive2Called = true; server2Message = s.GetData(); } void Client1OnReceive(SocketState s) { if (s.ErrorOccured) { return; } receive1Called = true; client1Message = s.GetData(); } void Client2OnReceive(SocketState s) { if (s.ErrorOccured) { return; } receive2Called = true; client2Message = s.GetData(); } // setup first server and client using the normal helper SetupTestConnections(false); testLocalSocketState.OnNetworkAction = Server1OnReceive; // setup second server and client TcpListener listener2 = Networking.StartServer(Server2OnConnect, 2222); Networking.ConnectToServer(Client2OnConnect, "localhost", 2222); // wait for the second pair to connect WaitForOrTimeout(() => server2 != null && client2 != null, timeout); // Receive on server1 Networking.GetData(testLocalSocketState); // Receive on server2 Networking.GetData(server2); // Receive on client1 testRemoteSocketState.OnNetworkAction = Client1OnReceive; Networking.GetData(testRemoteSocketState); // Receive on client2 client2.OnNetworkAction = Client2OnReceive; Networking.GetData(client2); // Send from client1 to server1 Networking.Send(testRemoteSocketState.TheSocket, "a"); // Send from client2 to server2 Networking.Send(client2.TheSocket, "b"); // Send from server1 to client1 Networking.Send(testLocalSocketState.TheSocket, "c"); // Send from server2to client2 Networking.Send(server2.TheSocket, "d"); WaitForOrTimeout(() => server2Connected && receive1Called && receive2Called, timeout); Assert.IsTrue(server2Connected); Assert.IsTrue(receive1Called); Assert.IsTrue(receive2Called); Assert.AreEqual("a", server1Message); Assert.AreEqual("b", server2Message); Assert.AreEqual("c", client1Message); Assert.AreEqual("d", client2Message); }