Esempio n. 1
0
  @Test
  @Parameters
  @SuppressWarnings("unchecked")
  public final void testDelayed(
      int minDelay,
      int maxDelay,
      float lossChance,
      float dupChance,
      int executeInterval,
      long executeTime,
      boolean retransmit)
      throws InterruptedException {

    /*
     * Record phase
     */
    final UnreliableQueue<Packet<Long>> aToB =
        new UnreliableQueue<Packet<Long>>(
            queueListenerAtoB, minDelay, maxDelay, lossChance, dupChance);
    final UnreliableQueue<Packet<Long>> bToA =
        new UnreliableQueue<Packet<Long>>(
            queueListenerBtoA, minDelay, maxDelay, lossChance, dupChance);

    ProtocolListener<Long> listenerA =
        DEBUG
            ? new DebugProtocolListener<Long>(protocolListenerA, Logger.getConsoleLogger("A"))
            : protocolListenerA;
    final TestHost<Long> hostA =
        new TestHost<Long>(
            hostListenerA,
            new LongDataGenerator(),
            bToA,
            aToB,
            new ProtocolConfig<Long>(listenerA),
            DEBUG ? "A" : null);
    final List<Long> sentA = new ArrayList<Long>();
    final List<Long> lostSentA = new ArrayList<Long>();
    final List<Long> dupedSentA = new ArrayList<Long>();
    final List<Long> receivedA = new ArrayList<Long>();
    final List<Long> ackedA = new ArrayList<Long>();
    final List<Long> notAckedA = new ArrayList<Long>();
    final List<Long> orderedA = new ArrayList<Long>();
    final List<Long> unorderedA = new ArrayList<Long>();
    final List<Long> retransmitsA = new ArrayList<Long>();

    ProtocolListener<Long> listenerB =
        DEBUG
            ? new DebugProtocolListener<Long>(protocolListenerB, Logger.getConsoleLogger("B"))
            : protocolListenerB;
    final TestHost<Long> hostB =
        new TestHost<Long>(
            hostListenerB,
            new LongDataGenerator(),
            aToB,
            bToA,
            new ProtocolConfig<Long>(listenerB),
            DEBUG ? "B" : null);
    final List<Long> sentB = new ArrayList<Long>();
    final List<Long> lostSentB = new ArrayList<Long>();
    final List<Long> dupedSentB = new ArrayList<Long>();
    final List<Long> receivedB = new ArrayList<Long>();
    final List<Long> ackedB = new ArrayList<Long>();
    final List<Long> notAckedB = new ArrayList<Long>();
    final List<Long> orderedB = new ArrayList<Long>();
    final List<Long> unorderedB = new ArrayList<Long>();
    final List<Long> retransmitsB = new ArrayList<Long>();

    new NonStrictExpectations() {
      {
        hostListenerA.notifyReceived(withCapture(receivedA));
        hostListenerA.notifySent(withCapture(sentA));
        hostListenerA.notifyRetransmitted(withCapture(retransmitsA));

        protocolListenerA.handleAckedData(anyShort, withCapture(ackedA));
        protocolListenerA.handleUnackedData(anyShort, withCapture(notAckedA));
        protocolListenerA.handleOrderedData(anyShort, withCapture(orderedA));
        protocolListenerA.handleUnorderedData(anyShort, withCapture(unorderedA));
      }
    };

    new NonStrictExpectations() {
      {
        hostListenerB.notifyReceived(withCapture(receivedB));
        hostListenerB.notifySent(withCapture(sentB));
        hostListenerB.notifyRetransmitted(withCapture(retransmitsB));

        protocolListenerB.handleAckedData(anyShort, withCapture(ackedB));
        protocolListenerB.handleUnackedData(anyShort, withCapture(notAckedB));
        protocolListenerB.handleOrderedData(anyShort, withCapture(orderedB));
        protocolListenerB.handleUnorderedData(anyShort, withCapture(unorderedB));
      }
    };

    new NonStrictExpectations() {
      {
        queueListenerAtoB.notifyDuplicate((Packet<Long>) any);
        result =
            new Delegate<Packet<Long>>() {
              @SuppressWarnings("unused")
              void delegate(Packet<Long> dup) {
                for (Metadata<Long> metadata : dup.getMetadatas()) {
                  dupedSentA.add(metadata.getData());
                  if (DEBUG) System.out.println("[A-dupedSent]: " + metadata.getData());
                }
              }
            };
        queueListenerAtoB.notifyLoss((Packet<Long>) any);
        result =
            new Delegate<Packet<Long>>() {
              @SuppressWarnings("unused")
              void delegate(Packet<Long> loss) {
                for (Metadata<Long> metadata : loss.getMetadatas()) {
                  lostSentA.add(metadata.getData());
                  if (DEBUG) System.out.println("[A-lostSent]: " + metadata.getData());
                }
              }
            };

        queueListenerBtoA.notifyDuplicate((Packet<Long>) any);
        result =
            new Delegate<Packet<Long>>() {
              @SuppressWarnings("unused")
              void delegate(Packet<Long> dup) {
                for (Metadata<Long> metadata : dup.getMetadatas()) {
                  dupedSentB.add(metadata.getData());
                  if (DEBUG) System.out.println("[B-dupedSent]: " + metadata.getData());
                }
              }
            };
        queueListenerBtoA.notifyLoss((Packet<Long>) any);
        result =
            new Delegate<Packet<Long>>() {
              @SuppressWarnings("unused")
              void delegate(Packet<Long> loss) {
                for (Metadata<Long> metadata : loss.getMetadatas()) {
                  lostSentB.add(metadata.getData());
                  if (DEBUG) System.out.println("[B-lostSent]: " + metadata.getData());
                }
              }
            };
      }
    };

    /*
     * Replay phase
     */

    // play it for a longer interval
    executor.scheduleAtFixedRate(hostA, 0, executeInterval, TimeUnit.MILLISECONDS);
    executor.scheduleAtFixedRate(
        hostB, executeInterval / 2, executeInterval, TimeUnit.MILLISECONDS);
    executor.schedule(
        new Runnable() {
          @Override
          public void run() {
            // enable reliable queue mode for final messages
            aToB.setDupChance(0f);
            aToB.setLossChance(0f);
            aToB.setMinDelay(0L);
            aToB.setMaxDelay(0L);
            bToA.setDupChance(0f);
            bToA.setLossChance(0f);
            bToA.setMinDelay(0L);
            bToA.setMaxDelay(0L);
          }
        },
        executeTime - executeTime / 10,
        TimeUnit.SECONDS);
    executor.awaitTermination(executeTime, TimeUnit.SECONDS);
    executor.shutdown();
    executor.awaitTermination(executeInterval * 2 + maxDelay * 2, TimeUnit.MILLISECONDS);

    // let pending messages finish
    Thread.sleep(maxDelay * 2);
    hostA.receive();
    hostB.receive();
    hostA.send();
    hostB.send();
    Thread.sleep(maxDelay * 2); // wait for queue to make all elements available
    hostA.receive();
    hostB.receive();

    System.out.println();

    /*
     * Verify phase
     */

    for (Long item : notAckedA)
      assertTrue("notAcked data should not have been acked", !ackedA.contains(item));
    for (Long item : notAckedB)
      assertTrue("notAcked data should not have been acked", !ackedB.contains(item));

    for (Long item : retransmitsA)
      assertTrue("retransmitted data should have been sent from sender", sentA.contains(item));
    for (Long item : retransmitsB)
      assertTrue("retransmitted data should have been sent from sender", sentB.contains(item));
    for (Long item : lostSentA)
      assertTrue("over medium lost data should have been sent from sender", sentA.contains(item));
    for (Long item : lostSentB)
      assertTrue("over medium lost data should have been sent from sender", sentB.contains(item));
    for (Long item : dupedSentA)
      assertTrue(
          "over medium duplicated data should have been sent from sender", sentA.contains(item));
    for (Long item : dupedSentB)
      assertTrue(
          "over medium duplicated data should have been sent from sender", sentB.contains(item));

    Long lastItem = null;
    for (Long item : orderedA) {
      assertTrue("orderly received data should have been sent from sender", sentB.contains(item));

      if (lastItem != null) {
        assertTrue("ordered data should be ordered", item > lastItem);
      }
      lastItem = item;
    }
    lastItem = null;
    for (Long item : orderedB) {
      assertTrue("orderly received data should have been sent from sender", sentA.contains(item));

      if (lastItem != null) {
        assertTrue("ordered data should be ordered", item > lastItem);
      }
      lastItem = item;
    }

    lastItem = null;
    for (Long item : unorderedA) {
      assertTrue("unorderly received data should have been sent from sender", sentB.contains(item));

      if (lastItem != null) {
        assertTrue("unordered data should be ordered", item > lastItem);
      }
      lastItem = item;

      assertTrue("unordered data should not have been orderly received", !orderedA.contains(item));

      // The following assertions can not be guaranteed, since there may be multiple unordered
      // events and multiple holes until an ordered event occurs
      //			Long pred = item;
      //			do {
      //				pred--;
      //			} while(unorderedA.contains(pred));
      //			Long succ = item;
      //			do {
      //				succ++;
      //			} while(unorderedA.contains(succ));
      //			assertTrue("ordered data contains predecessor of unorderedData",
      // orderedA.contains(pred));
      //			assertTrue("ordered data contains successor of unorderedData", orderedA.contains(succ));
    }

    lastItem = null;
    for (Long item : unorderedB) {
      assertTrue("orderly received data should have been sent from sender", sentA.contains(item));

      if (lastItem != null) {
        assertTrue("unordered data should be ordered", item > lastItem);
      }
      lastItem = item;

      assertTrue("unordered data should not have been orderly received", !orderedB.contains(item));

      // The following assertions can not be guaranteed, since there may be multiple unordered
      // events and multiple holes until an ordered event occurs
      //			Long pred = item;
      //			do {
      //				pred--;
      //			} while(unorderedB.contains(pred));
      //			Long succ = item;
      //			do {
      //				succ++;
      //			} while(unorderedB.contains(succ));
      //			assertTrue("ordered data contains predecessor of unorderedData",
      // orderedB.contains(pred));
      //			assertTrue("ordered data contains successor of unorderedData", orderedB.contains(succ));
    }

    // the following addition of "magic constants" is due to the scheduling procedure of the very
    // last messages
    assertEquals(
        "all messages from A must be received at B",
        receivedB.size(),
        sentA.size() - lostSentA.size() + dupedSentA.size());
    assertEquals(
        "all messages from A must be acked",
        ackedA.size(),
        sentA.size() - retransmitsA.size() - notAckedA.size() - 1);
    assertEquals(
        "all messages from A must be ordered at B",
        orderedB.size(),
        sentA.size() - retransmitsA.size() - unorderedB.size());

    // the following addition of "magic constants" is due to the scheduling procedure of the very
    // last messages
    assertEquals(
        "all messages from B must be received at A",
        receivedA.size(),
        sentB.size() - lostSentB.size() + dupedSentB.size());
    assertEquals(
        "all messages from B must be acked",
        ackedB.size(),
        sentB.size() - retransmitsB.size() - notAckedB.size() - 1);
    assertEquals(
        "all messages from B must be ordered at A",
        orderedA.size(),
        sentB.size() - retransmitsB.size() - unorderedA.size());

    if (lossChance == 0f) {
      assertEquals("no lost packets", 0, lostSentB.size());
      assertEquals("no lost packets", 0, lostSentA.size());
    }

    if (dupChance == 0f) {
      assertEquals("no duped packets", 0, dupedSentB.size());
      assertEquals("no duped packets", 0, dupedSentA.size());
    }

    if (retransmit || lossChance == 0f) {
      new Verifications() {
        {
          protocolListenerA.handleUnackedData(anyShort, anyLong);
          times = 0;
          protocolListenerA.handleUnorderedData(anyShort, anyLong);
          times = 0;
        }
      };
      new Verifications() {
        {
          protocolListenerB.handleUnackedData(anyShort, anyLong);
          times = 0;
          protocolListenerB.handleUnorderedData(anyShort, anyLong);
          times = 0;
        }
      };

      assertEquals("all packets acked", 0, notAckedA.size());
      assertEquals("all packets ordered", 0, unorderedA.size());
      assertEquals("all packets acked", 0, notAckedB.size());
      assertEquals("all packets ordered", 0, unorderedB.size());
    }
  }