@Test
  public void nextZeroWeight() {
    Balancer<Void, MockDatabase> balancer =
        this.factory.createBalancer(Collections.singleton(this.databases[0]));

    assertSame(this.databases[0], balancer.next());
  }
  @Test
  public void nextEmptyBalancer() {
    Balancer<Void, MockDatabase> balancer =
        this.factory.createBalancer(Collections.<MockDatabase>emptySet());

    assertNull(balancer.next());
  }
  @Test
  public void nextSingleWeight() {
    Balancer<Void, MockDatabase> balancer =
        this.factory.createBalancer(
            new HashSet<MockDatabase>(Arrays.asList(this.databases[0], this.databases[1])));

    assertSame(this.databases[1], balancer.next());

    int count = 10;

    CountDownLatch latch = new CountDownLatch(count);
    WaitingInvoker invoker = new WaitingInvoker(latch);

    ExecutorService executor = Executors.newFixedThreadPool(count);
    List<Future<Void>> futures = new ArrayList<Future<Void>>(count);

    for (int i = 0; i < count; ++i) {
      futures.add(executor.submit(new InvocationTask(balancer, invoker, this.databases[1])));
    }

    try {
      // Ensure all invokers are started
      latch.await();

      // Should still use the same database, even under load
      assertSame(this.databases[1], balancer.next());

      // Allow invokers to continue
      synchronized (invoker) {
        invoker.notifyAll();
      }

      this.complete(futures);

      // Should still use the same database, after load
      assertSame(this.databases[1], balancer.next());
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
    } finally {
      executor.shutdownNow();
    }
  }