/**
   * tests that a download from a push location becomes an alternate location.
   *
   * <p>It creates a push uploader from which we must create a PushLoc. After a while, two open
   * uploaders join the swarm -one which is interested in receiving push locs and one which isn't.
   * The interested one should receive the push loc, the other one should not.
   */
  public void testPusherBecomesPushLocAndSentToInterested() throws Exception {
    LOG.info("-Testing push download creating a push location...");
    final int RATE = 200;
    testUploaders[0].setRate(RATE);
    testUploaders[0].setInterestedInFalts(true);
    testUploaders[0].stopAfter(600000);
    testUploaders[1].setRate(RATE);
    testUploaders[1].setInterestedInFalts(false);
    testUploaders[1].stopAfter(300000);

    TestUploader pusher = injector.getInstance(TestUploader.class);
    pusher.start("push uploader");
    pusher.setRate(RATE);
    pusher.stopAfter(200000);

    GUID guid = new GUID();
    AlternateLocation pushLoc =
        alternateLocationFactory.create(
            guid.toHexString() + ";127.0.0.2:" + PPORT_1, TestFile.hash());

    RemoteFileDesc pushRFD = newRFDPush(guid, PPORT_1, 1, 2);

    PushEndpoint pushEndpoint = (PushEndpoint) pushRFD.getAddress();
    assertEquals(0, pushEndpoint.getFWTVersion());

    RemoteFileDesc openRFD1 = newRFDWithURN(PORTS[0], TestFile.hash().toString(), false);
    RemoteFileDesc openRFD2 = newRFDWithURN(PORTS[1], TestFile.hash().toString(), false);

    RemoteFileDesc[] now = {pushRFD};
    HashSet<RemoteFileDesc> later = new HashSet<RemoteFileDesc>();
    later.add(openRFD1);
    later.add(openRFD2);

    testUDPAcceptorFactoryImpl.createTestUDPAcceptor(
        PPORT_1, networkManager.getPort(), savedFile.getName(), pusher, guid, _currentTestName);

    ManagedDownloader download =
        (ManagedDownloader) downloadServices.download(now, RemoteFileDesc.EMPTY_LIST, null, false);
    Thread.sleep(1000);
    download.addDownload(later, false);

    waitForComplete();

    assertGreaterThan("u1 did no work", 100000, testUploaders[0].getAmountUploaded());

    assertGreaterThan("u2 did no work", 100000, testUploaders[1].getAmountUploaded());
    assertLessThan("u2 did too much work", 550 * 1024, testUploaders[1].getAmountUploaded());

    assertGreaterThan("pusher did no work", 100 * 1024, pusher.getAmountUploaded());

    List alc = testUploaders[0].getIncomingGoodAltLocs();
    assertTrue("interested uploader did not get pushloc", alc.contains(pushLoc));

    alc = testUploaders[1].getIncomingGoodAltLocs();
    assertFalse("not interested uploader got pushloc", alc.contains(pushLoc));

    alc = pusher.getIncomingGoodAltLocs();
    assertFalse("not interested uploader got pushloc", alc.contains(pushLoc));
  }
  // problem is:
  // old code ranked as follows: GUID:C72D25808E87DE738FD57BCF51F5FF00, address: 1.1.1.1:6346,
  // proxies:{ /127.0.0.2:10002
  // }]
  //
  // GUID:C72D25808E87DE738FD57BCF51F5FF00, address: 127.0.0.1:7498,
  // proxies:{ /1.2.3.4:5
  // /6.7.8.9:10
  //
  // new code picks:
  // GUID:7ECD430C3F5E93BB76B5CF3706C40700, address: 127.0.0.1:6346,
  // proxies:{ /127.0.0.2:10002
  //
  // GUID:7ECD430C3F5E93BB76B5CF3706C40700, address: 127.0.0.1:7498,
  // proxies:{ /1.2.3.4:5
  //    /6.7.8.9:10
  //
  // GUID:7ECD430C3F5E93BB76B5CF3706C40700, address: 127.0.0.1:7498,
  // proxies:{ /1.2.3.4:5
  //    /6.7.8.9:10
  //    /127.0.0.2:10002
  //    }]
  public void testPushLocUpdatesStatus() throws Exception {
    int successfulPushes =
        ((AtomicInteger) ((Map) statsTracker.inspect()).get("push connect success")).intValue();
    LOG.info("testing that a push loc updates its status");
    final int RATE = 100;
    final int FWTPort = 7498;

    NetworkManagerStub uploaderNetworkManager = new NetworkManagerStub();
    uploaderNetworkManager.setAcceptedIncomingConnection(false);
    uploaderNetworkManager.setCanDoFWT(true);
    udpService.setReceiveSolicited(true);
    testUploaders[0].setRate(RATE);
    testUploaders[0].stopAfter(900000);
    testUploaders[0].setInterestedInFalts(true);

    TestUploader pusher2 = new TestUploader(uploaderNetworkManager);
    pusher2.start("firewalled pusher");
    pusher2.setRate(RATE);
    pusher2.stopAfter(200000);
    pusher2.setFirewalled(true);
    pusher2.setProxiesString("1.2.3.4:5,6.7.8.9:10");
    pusher2.setInterestedInFalts(true);
    pusher2.setFWTPort(FWTPort);

    GUID guid = new GUID();

    // register proxies for GUID, this will add 127.0.0.2:10002 to proxies
    PushEndpoint cachedPE =
        pushEndpointFactory.createPushEndpoint(
            guid.bytes(), new IpPortSet(new IpPortImpl("127.0.0.2", PPORT_2)));
    PushEndpointCache cache = injector.getInstance(PushEndpointCache.class);
    GUID retGuid = cache.updateProxiesFor(guid, cachedPE, true);
    assertSame(retGuid, guid);
    assertEquals(1, cachedPE.getProxies().size());

    RemoteFileDesc openRFD = newRFDWithURN(PORTS[0], false);
    RemoteFileDesc pushRFD2 = newRFDPush(guid, PPORT_2, 1, 2);
    PushEndpoint pushEndpoint = (PushEndpoint) pushRFD2.getAddress();
    assertEquals(0, pushEndpoint.getFWTVersion());

    testUDPAcceptorFactoryImpl.createTestUDPAcceptor(
        PPORT_2, networkManager.getPort(), savedFile.getName(), pusher2, guid, _currentTestName);

    // start download with rfd that needs udp push request
    ManagedDownloader download =
        (ManagedDownloader)
            downloadServices.download(
                new RemoteFileDesc[] {pushRFD2}, RemoteFileDesc.EMPTY_LIST, null, false);
    Thread.sleep(2000);
    LOG.debug("adding regular downloader");
    // also download from uploader1, so it gets the proxy headers from pusher2
    download.addDownload(openRFD, false);
    waitForComplete();

    List<AlternateLocation> alc = testUploaders[0].getIncomingGoodAltLocs();
    assertEquals(1, alc.size());

    PushAltLoc pushLoc = (PushAltLoc) alc.iterator().next();

    assertEquals(RUDPUtils.VERSION, pushLoc.supportsFWTVersion());

    RemoteFileDesc readRFD = pushLoc.createRemoteFileDesc(1, remoteFileDescFactory);
    pushEndpoint = (PushEndpoint) readRFD.getAddress();
    assertTrue(pushEndpoint.getFWTVersion() > 0);
    assertEquals(pushEndpoint.getPort(), FWTPort);

    Set<IpPort> expectedProxies =
        new IpPortSet(new IpPortImpl("1.2.3.4:5"), new IpPortImpl("6.7.8.9:10"));
    assertEquals(
        "expected: " + expectedProxies + ", actual: " + pushEndpoint.getProxies(),
        expectedProxies.size(),
        pushEndpoint.getProxies().size());
    assertTrue(expectedProxies.containsAll(pushEndpoint.getProxies()));

    assertEquals(
        successfulPushes + 1,
        ((AtomicInteger) ((Map) statsTracker.inspect()).get("push connect success")).intValue());
  }