@Test
public void test_watch_on_recoverable_connection() throws InterruptedException {

    String path = "/dubbo/com.alibaba.dubbo.demo.DemoService/connection";
    String child = "/dubbo/com.alibaba.dubbo.demo.DemoService/connection/demoService1";
    final CountDownLatch notNotified = new CountDownLatch(1);
    final CountDownLatch notTwiceNotified = new CountDownLatch(2);
    final Holder notified = new Holder();
    ChildListener childListener = (parent, children) -> {
        notTwiceNotified.countDown();
        switch (notified.increaseAndGet()) {
            case 1: {
                notNotified.countDown();
                Assertions.assertEquals(1, children.size());
                Assertions.assertEquals(child.substring(child.lastIndexOf("/") + 1), children.get(0));
                break;
            }
            case 2: {
                Assertions.assertEquals(0, children.size());
                Assertions.assertEquals(path, parent);
                break;
            }
            default:
                Assertions.fail("two many callback invoked.");
        }
    };
    client.addChildListener(path, childListener);
    client.createEphemeral(child);
    // make sure first time callback successfully
    Assertions.assertTrue(notNotified.await(15, TimeUnit.SECONDS));
    // connection error causes client to release all resources including current watcher
    JEtcdClient.EtcdWatcher watcher = client.getChildListener(path, childListener);
    watcher.onError(Status.UNAVAILABLE.withDescription("temporary connection issue").asRuntimeException());
    // trigger delete after unavailable
    client.delete(child);
    Assertions.assertTrue(notTwiceNotified.await(15, TimeUnit.SECONDS));
    client.removeChildListener(path, childListener);
}