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

    assertSame(this.databases[0], balancer.next());
  }
  /**
   * Test method for {@link net.sf.hajdbc.balancer.load.LoadBalancer#add(net.sf.hajdbc.Database)}.
   */
  @Test
  public void add() {
    Balancer<Void, MockDatabase> balancer =
        this.factory.createBalancer(Collections.<MockDatabase>emptySet());

    boolean result = balancer.add(this.databases[1]);
    assertTrue(result);
    assertCollectionEquals(Collections.singleton(this.databases[1]), balancer);

    balancer = this.factory.createBalancer(Collections.singleton(this.databases[0]));

    result = balancer.add(this.databases[1]);
    assertTrue(result);
    assertCollectionEquals(Arrays.asList(this.databases[0], this.databases[1]), balancer);

    balancer =
        this.factory.createBalancer(
            new HashSet<MockDatabase>(Arrays.asList(this.databases[0], this.databases[1])));

    result = balancer.add(this.databases[1]);
    assertFalse(result);
    assertCollectionEquals(Arrays.asList(this.databases[0], this.databases[1]), balancer);

    balancer =
        this.factory.createBalancer(new HashSet<MockDatabase>(Arrays.asList(this.databases)));

    result = balancer.add(this.databases[1]);
    assertFalse(result);
    assertCollectionEquals(Arrays.asList(this.databases), balancer);
  }
  @Test
  public void nextEmptyBalancer() {
    Balancer<Void, MockDatabase> balancer =
        this.factory.createBalancer(Collections.<MockDatabase>emptySet());

    assertNull(balancer.next());
  }
  /** Test method for {@link net.sf.hajdbc.balancer.load.LoadBalancer#clear()}. */
  @Test
  public void clear() {
    Balancer<Void, MockDatabase> balancer =
        this.factory.createBalancer(Collections.<MockDatabase>emptySet());

    balancer.clear();
    assertEquals(Collections.<MockDatabase>emptySet(), balancer);

    balancer = this.factory.createBalancer(Collections.singleton(this.databases[0]));

    balancer.clear();
    assertEquals(Collections.<MockDatabase>emptySet(), balancer);

    balancer =
        this.factory.createBalancer(
            new HashSet<MockDatabase>(Arrays.asList(this.databases[0], this.databases[1])));

    balancer.clear();
    assertEquals(Collections.<MockDatabase>emptySet(), balancer);

    balancer =
        this.factory.createBalancer(new HashSet<MockDatabase>(Arrays.asList(this.databases)));

    balancer.clear();
    assertEquals(Collections.<MockDatabase>emptySet(), balancer);
  }
  /** Test method for {@link net.sf.hajdbc.balancer.AbstractBalancer#contains(java.lang.Object)}. */
  @Test
  public void contains() {
    Balancer<Void, MockDatabase> balancer =
        this.factory.createBalancer(Collections.<MockDatabase>emptySet());

    assertFalse(balancer.contains(this.databases[0]));
    assertFalse(balancer.contains(this.databases[1]));
    assertFalse(balancer.contains(this.databases[2]));

    balancer = this.factory.createBalancer(Collections.singleton(this.databases[0]));

    assertTrue(balancer.contains(this.databases[0]));
    assertFalse(balancer.contains(this.databases[1]));
    assertFalse(balancer.contains(this.databases[2]));

    balancer =
        this.factory.createBalancer(
            new HashSet<MockDatabase>(Arrays.asList(this.databases[0], this.databases[1])));

    assertTrue(balancer.contains(this.databases[0]));
    assertTrue(balancer.contains(this.databases[1]));
    assertFalse(balancer.contains(this.databases[2]));

    balancer =
        this.factory.createBalancer(new HashSet<MockDatabase>(Arrays.asList(this.databases)));

    assertTrue(balancer.contains(this.databases[0]));
    assertTrue(balancer.contains(this.databases[1]));
    assertTrue(balancer.contains(this.databases[2]));
  }
  @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();
    }
  }
  @Test
  public void backups() {
    Balancer<Void, MockDatabase> balancer =
        this.factory.createBalancer(Collections.<MockDatabase>emptySet());

    Iterable<MockDatabase> result = balancer.backups();
    assertNotNull(result);
    Iterator<MockDatabase> backups = result.iterator();
    assertFalse(backups.hasNext());

    balancer = this.factory.createBalancer(Collections.singleton(this.databases[0]));

    result = balancer.backups();
    assertNotNull(result);
    backups = result.iterator();
    assertFalse(backups.hasNext());

    balancer =
        this.factory.createBalancer(
            new HashSet<MockDatabase>(Arrays.asList(this.databases[0], this.databases[1])));

    result = balancer.backups();
    assertNotNull(result);
    backups = result.iterator();
    assertTrue(backups.hasNext());
    assertSame(this.databases[1], backups.next());
    assertFalse(backups.hasNext());

    balancer =
        this.factory.createBalancer(new HashSet<MockDatabase>(Arrays.asList(this.databases)));

    result = balancer.backups();
    assertNotNull(result);
    backups = result.iterator();
    assertTrue(backups.hasNext());
    assertSame(this.databases[1], backups.next());
    assertTrue(backups.hasNext());
    assertSame(this.databases[2], backups.next());
    assertFalse(backups.hasNext());
  }
  /**
   * Test method for {@link
   * net.sf.hajdbc.balancer.load.LoadBalancer#invoke(net.sf.hajdbc.invocation.Invoker,
   * net.sf.hajdbc.Database, java.lang.Object)}.
   */
  @Test
  public void invoke() throws Exception {
    TestInvoker invoker = mock(TestInvoker.class);
    Object object = new Object();
    Object expected = new Object();
    Exception expectedException = new Exception();

    Balancer<Void, MockDatabase> balancer =
        this.factory.createBalancer(new HashSet<MockDatabase>(Arrays.asList(this.databases)));

    when(invoker.invoke(this.databases[0], object)).thenReturn(expected);

    Object result = null;
    Exception exception = null;
    try {
      result = balancer.invoke(invoker, this.databases[0], object);
    } catch (Exception e) {
      exception = e;
    }

    assertSame(expected, result);
    assertNull(exception);

    reset(invoker);

    when(invoker.invoke(this.databases[0], object)).thenThrow(expectedException);

    result = null;
    exception = null;

    try {
      result = balancer.invoke(invoker, this.databases[0], object);
    } catch (Exception e) {
      exception = e;
    }

    assertNull(result);
    assertSame(expectedException, exception);
  }
  @Test
  public void primary() {
    Balancer<Void, MockDatabase> balancer =
        this.factory.createBalancer(Collections.<MockDatabase>emptySet());

    assertNull(balancer.primary());

    balancer = this.factory.createBalancer(Collections.singleton(this.databases[0]));

    assertSame(this.databases[0], balancer.primary());

    balancer =
        this.factory.createBalancer(
            new HashSet<MockDatabase>(Arrays.asList(this.databases[0], this.databases[1])));

    assertSame(this.databases[0], balancer.primary());

    balancer =
        this.factory.createBalancer(new HashSet<MockDatabase>(Arrays.asList(this.databases)));

    assertSame(this.databases[0], balancer.primary());
  }
  /** Test method for {@link net.sf.hajdbc.balancer.AbstractBalancer#iterator()}. */
  @Test
  public void iterator() {
    Balancer<Void, MockDatabase> balancer =
        this.factory.createBalancer(Collections.<MockDatabase>emptySet());

    Iterator<MockDatabase> result = balancer.iterator();
    assertFalse(result.hasNext());

    balancer = this.factory.createBalancer(Collections.singleton(this.databases[0]));

    result = balancer.iterator();
    assertTrue(result.hasNext());
    assertEquals(this.databases[0], result.next());
    assertFalse(result.hasNext());

    balancer =
        this.factory.createBalancer(
            new HashSet<MockDatabase>(Arrays.asList(this.databases[0], this.databases[1])));

    result = balancer.iterator();
    assertTrue(result.hasNext());
    assertEquals(this.databases[0], result.next());
    assertTrue(result.hasNext());
    assertEquals(this.databases[1], result.next());
    assertFalse(result.hasNext());

    balancer =
        this.factory.createBalancer(new HashSet<MockDatabase>(Arrays.asList(this.databases)));

    result = balancer.iterator();
    assertTrue(result.hasNext());
    assertEquals(this.databases[0], result.next());
    assertTrue(result.hasNext());
    assertEquals(this.databases[1], result.next());
    assertTrue(result.hasNext());
    assertEquals(this.databases[2], result.next());
    assertFalse(result.hasNext());
  }
  /** Test method for {@link net.sf.hajdbc.balancer.AbstractBalancer#toArray()}. */
  @Test
  public void toArray() {
    Balancer<Void, MockDatabase> balancer =
        this.factory.createBalancer(Collections.<MockDatabase>emptySet());

    assertTrue(Arrays.equals(new Object[0], balancer.toArray()));

    balancer = this.factory.createBalancer(Collections.singleton(this.databases[0]));

    assertTrue(Arrays.equals(new Object[] {this.databases[0]}, balancer.toArray()));

    balancer =
        this.factory.createBalancer(
            new HashSet<MockDatabase>(Arrays.asList(this.databases[0], this.databases[1])));

    assertTrue(
        Arrays.equals(new Object[] {this.databases[0], this.databases[1]}, balancer.toArray()));

    balancer =
        this.factory.createBalancer(new HashSet<MockDatabase>(Arrays.asList(this.databases)));

    assertTrue(Arrays.equals(this.databases, balancer.toArray()));
  }