/// <summary> /// Tests the reliablity components of the underlying protocol. In order to do that, /// we need to simulate sending a number of packets in-order, out of order, in-time /// and out of time (to simulate dropped packets). This is an extremly granular test /// of the packets themselves, a seperate message reliabilty test exists to ensure /// that pipes receive their data and congestion control does its job or resending /// unacked packets. /// /// The concrete congestion tests will set up two controller mocks and pass them into /// this function which will simulate communications between the two points. This function /// assumes that all of the objects have been correctly /// </summary> /// <param name="ep1">Ep1.</param> /// <param name="ep2">Ep2.</param> /// <param name="maxTimeoutPerPacket">A maximum timeout per packet /// before packetloss is deemed a failure</param> internal void TestReliablityAtomic(TunnelCongestionControllerMock ep1, TunnelCongestionControllerMock ep2, Int32 maxTimeOutPerPacket) { Assert.IsNotNull(mPs1, "You must set ep1 to use mPs1 as its packet sender"); Assert.IsNotNull(mPs2, "You must set ep2 to use mPs2 as its packet sender"); GenericPacketMock p1 = new GenericPacketMock(1); GenericPacketMock p2 = new GenericPacketMock(2); GenericPacketMock p3 = new GenericPacketMock(3); GenericPacketMock p4 = new GenericPacketMock(4); Queue <int> expectedAcks = new Queue <int> (); for (int i = 1; i <= 4; i++) { expectedAcks.Enqueue(i); } //the test sends packets from ep1 to ep2 int curCount = 1; mPs1.InterceptOutgoingPacket(p => { //ensure that the acks come in order ep2.HandleIncomingPacket(p); }); mPs2.InterceptOutgoingPacket(p => { ep1.HandleIncomingPacket(p); Assert.IsTrue(expectedAcks.Dequeue() == p.Ack, "Failed at packet seq" + p.Ack); }); ep1.SendPacket(p1); ep1.SendPacket(p2); ep1.SendPacket(p4); ep1.SendPacket(p3); }
/// <summary> /// This test launches multiple tests and sends a series of packets through an object /// that simulates packet loss. The packet loss will medium will randomly simulate /// RTT delays, MTU size differences and just packet loss. /// </summary> internal void TestReliability(TunnelCongestionControllerMock ep1, TunnelSocketSendIntercept sock1, TunnelCongestionControllerMock ep2, TunnelSocketSendIntercept sock2, int lossPercentage, UInt32 dgramSize) { LossyConnection connection = new LossyConnection(lossPercentage); //hook ep1 to ep2 //sending from ep1 to ep2 sock1.SetSendInterceptor(p => { //outgoing packet needs to be bubbled into sock2 connection.SendPacket(p, ep2); }); //ep2 sends an ack to ep1 sock2.SetSendInterceptor(p => { //add test for acks (they should always come in order) connection.SendPacket(p, ep1); }); int curAck = 1; ep1.SetIncomingPacketInterceptor(p => { //should receive Ack's in order Assert.IsTrue(curAck == p.Ack, "Acks should be received in order"); }); StringBuilder buildString = new StringBuilder(); ep2.SetIncomingPacketInterceptor(p => { GenericPacketMock gp = (GenericPacketMock)p; buildString.Append(Encoding.ASCII.GetString(gp.GetPayload())); }); //the test executes on a seperate thread Thread testThread = new Thread(new ThreadStart(() => { byte[] txt = Encoding.ASCII.GetBytes(this.sendText); int size = 576 - 8 - 80; uint seq = 1; ArrayList <GenericPacketMock> packets = new ArrayList <GenericPacketMock>(); int numPackets = txt.Length / size; int overFlow = txt.Length % size; if (overFlow > 0) { numPackets += 1; } for (int i = 0; i < numPackets; i++) { int sizeSubArray = Math.Min(size, txt.Length - (i * size)); byte[] sub = new byte[sizeSubArray]; Array.Copy(txt, i * size, sub, 0, sizeSubArray); GenericPacketMock p = new GenericPacketMock(seq); p.SetPayload(sub); seq++; packets.Add(p); } foreach (GenericPacket p in packets) { ep1.SendPacket(p); } })); testThread.Start(); Thread.Sleep(1000); Assert.IsTrue(this.sendText.Equals(buildString.ToString()), buildString.ToString()); }