/// <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());
        }