@Test
  public void testZoneAffinityEnabled() throws Exception {
    ConfigurationManager.getConfigInstance()
        .setProperty(
            "DefaultNIWSServerListFilterTest1.ribbon.DeploymentContextBasedVipAddresses",
            "l10nservicegeneral.cloud.netflix.net:7001");
    ConfigurationManager.getConfigInstance()
        .setProperty(
            "DefaultNIWSServerListFilterTest1.ribbon.NFLoadBalancerClassName",
            DynamicServerListLoadBalancer.class.getName());
    ConfigurationManager.getConfigInstance()
        .setProperty(
            "DefaultNIWSServerListFilterTest1.ribbon.NIWSServerListClassName",
            DiscoveryEnabledNIWSServerList.class.getName());

    ConfigurationManager.getConfigInstance()
        .setProperty("DefaultNIWSServerListFilterTest1.ribbon.EnableZoneAffinity", "true");
    DynamicServerListLoadBalancer lb =
        (DynamicServerListLoadBalancer)
            ClientFactory.getNamedLoadBalancer("DefaultNIWSServerListFilterTest1");
    assertTrue(lb.getRule() instanceof AvailabilityFilteringRule);
    ZoneAffinityServerListFilter filter = (ZoneAffinityServerListFilter) lb.getFilter();
    LoadBalancerStats loadBalancerStats = lb.getLoadBalancerStats();
    List<DiscoveryEnabledServer> servers = new ArrayList<DiscoveryEnabledServer>();
    servers.add(createServer(1, "a"));
    servers.add(createServer(2, "a"));
    servers.add(createServer(3, "a"));
    servers.add(createServer(4, "a"));
    servers.add(createServer(1, "b"));
    servers.add(createServer(2, "b"));
    servers.add(createServer(3, "b"));
    servers.add(createServer(1, "c"));
    servers.add(createServer(2, "c"));
    servers.add(createServer(3, "c"));
    servers.add(createServer(4, "c"));
    servers.add(createServer(5, "c"));
    List<DiscoveryEnabledServer> filtered = filter.getFilteredListOfServers(servers);
    List<DiscoveryEnabledServer> expected = new ArrayList<DiscoveryEnabledServer>();
    expected.add(createServer(1, "c"));
    expected.add(createServer(2, "c"));
    expected.add(createServer(3, "c"));
    expected.add(createServer(4, "c"));
    expected.add(createServer(5, "c"));
    assertEquals(expected, filtered);
    lb.setServersList(filtered);
    for (int i = 1; i <= 4; i++) {
      loadBalancerStats.incrementActiveRequestsCount(createServer(i, "c"));
    }
    filtered = filter.getFilteredListOfServers(servers);
    assertEquals(servers, filtered);
  }
  /**
   * Execute the request on single server after the final URI is calculated. This method takes care
   * of retries and update server stats.
   */
  protected T executeOnSingleServer(S request) throws ClientException {
    boolean done = false;
    int retries = 0;

    boolean retryOkayOnOperation = okToRetryOnAllOperations;
    if (request.isRetriable()) {
      retryOkayOnOperation = true;
    }
    int numRetries = maxAutoRetries;
    URI uri = request.getUri();
    Server server = new Server(uri.getHost(), uri.getPort());
    ServerStats serverStats = null;
    ILoadBalancer lb = this.getLoadBalancer();
    if (lb instanceof AbstractLoadBalancer) {
      LoadBalancerStats lbStats = ((AbstractLoadBalancer) lb).getLoadBalancerStats();
      serverStats = lbStats.getSingleServerStat(server);
    }
    IClientConfig overriddenClientConfig = request.getOverrideConfig();
    if (overriddenClientConfig != null) {
      try {
        numRetries =
            Integer.parseInt(
                ""
                    + overriddenClientConfig.getProperty(
                        CommonClientConfigKey.MaxAutoRetries, maxAutoRetries));
      } catch (Exception e) {
        logger.warn("Invalid maxRetries requested for RestClient:" + this.clientName);
      }
    }

    T response = null;
    Exception lastException = null;
    if (tracer == null) {
      tracer =
          Monitors.newTimer(this.getClass().getName() + "_ExecutionTimer", TimeUnit.MILLISECONDS);
    }
    do {
      noteOpenConnection(serverStats, request);
      Stopwatch w = tracer.start();
      try {
        response = execute(request);
        done = true;
      } catch (Exception e) {
        if (serverStats != null) {
          serverStats.addToFailureCount();
        }
        lastException = e;
        if (isCircuitBreakerException(e) && serverStats != null) {
          serverStats.incrementSuccessiveConnectionFailureCount();
        }
        boolean shouldRetry = retryOkayOnOperation && numRetries >= 0 && isRetriableException(e);
        if (shouldRetry) {
          retries = handleRetry(uri.toString(), retries, numRetries, e);
        } else {
          ClientException niwsClientException = generateNIWSException(uri.toString(), e);
          throw niwsClientException;
        }
      } finally {
        w.stop();
        noteRequestCompletion(
            serverStats, request, response, lastException, w.getDuration(TimeUnit.MILLISECONDS));
      }
    } while (!done);
    return response;
  }
  @Test
  public void testZoneAffinityOverride() throws Exception {
    ConfigurationManager.getConfigInstance()
        .setProperty(
            "DefaultNIWSServerListFilterTest3.ribbon.DeploymentContextBasedVipAddresses",
            "l10nservicegeneral.cloud.netflix.net:7001");
    ConfigurationManager.getConfigInstance()
        .setProperty(
            "DefaultNIWSServerListFilterTest3.ribbon.NFLoadBalancerClassName",
            DynamicServerListLoadBalancer.class.getName());
    ConfigurationManager.getConfigInstance()
        .setProperty("DefaultNIWSServerListFilterTest3.ribbon.EnableZoneAffinity", "true");
    ConfigurationManager.getConfigInstance()
        .setProperty(
            "DefaultNIWSServerListFilterTest3.ribbon.NIWSServerListClassName",
            DiscoveryEnabledNIWSServerList.class.getName());
    ConfigurationManager.getConfigInstance()
        .setProperty(
            "DefaultNIWSServerListFilterTest3.ribbon.zoneAffinity.minAvailableServers", "3");
    DynamicServerListLoadBalancer lb =
        (DynamicServerListLoadBalancer)
            ClientFactory.getNamedLoadBalancer("DefaultNIWSServerListFilterTest3");
    ZoneAffinityServerListFilter filter = (ZoneAffinityServerListFilter) lb.getFilter();
    LoadBalancerStats loadBalancerStats = lb.getLoadBalancerStats();
    List<DiscoveryEnabledServer> servers = new ArrayList<DiscoveryEnabledServer>();
    servers.add(createServer(1, "a"));
    servers.add(createServer(2, "a"));
    servers.add(createServer(3, "a"));
    servers.add(createServer(4, "a"));
    servers.add(createServer(1, "b"));
    servers.add(createServer(2, "b"));
    servers.add(createServer(3, "b"));
    servers.add(createServer(1, "c"));
    servers.add(createServer(2, "c"));
    List<DiscoveryEnabledServer> filtered = filter.getFilteredListOfServers(servers);
    List<DiscoveryEnabledServer> expected = new ArrayList<DiscoveryEnabledServer>();
    /*
    expected.add(createServer(1, "c"));
    expected.add(createServer(2, "c"));
    expected.add(createServer(3, "c"));
    expected.add(createServer(4, "c"));
    expected.add(createServer(5, "c")); */
    // less than 3 servers in zone c, will not honor zone affinity
    assertEquals(servers, filtered);
    lb.setServersList(filtered);
    servers.add(createServer(3, "c"));
    filtered = filter.getFilteredListOfServers(servers);
    expected.add(createServer(1, "c"));
    expected.add(createServer(2, "c"));
    expected.add(createServer(3, "c"));
    filtered = filter.getFilteredListOfServers(servers);
    // now we have enough servers in C
    assertEquals(expected, filtered);

    // make one server black out
    for (int i = 1; i <= 3; i++) {
      loadBalancerStats.incrementSuccessiveConnectionFailureCount(createServer(1, "c"));
    }
    filtered = filter.getFilteredListOfServers(servers);
    assertEquals(servers, filtered);
    // new server added in zone c, zone c should now have enough servers
    servers.add(createServer(4, "c"));
    filtered = filter.getFilteredListOfServers(servers);
    expected.add(createServer(4, "c"));
    assertEquals(expected, filtered);
  }