1818
1919package org .apache .zookeeper .test ;
2020
21+ import static org .hamcrest .MatcherAssert .assertThat ;
22+ import static org .hamcrest .Matchers .greaterThanOrEqualTo ;
23+ import static org .hamcrest .Matchers .lessThan ;
2124import static org .junit .jupiter .api .Assertions .assertNotNull ;
2225import static org .junit .jupiter .api .Assertions .assertNull ;
2326import static org .junit .jupiter .api .Assertions .assertThrows ;
3134import java .util .concurrent .CompletableFuture ;
3235import java .util .concurrent .CountDownLatch ;
3336import java .util .concurrent .TimeUnit ;
37+ import java .util .concurrent .TimeoutException ;
3438import org .apache .zookeeper .CreateMode ;
3539import org .apache .zookeeper .KeeperException ;
3640import org .apache .zookeeper .TestableZooKeeper ;
3741import org .apache .zookeeper .WatchedEvent ;
3842import org .apache .zookeeper .Watcher ;
3943import org .apache .zookeeper .ZooDefs ;
44+ import org .apache .zookeeper .ZooKeeper ;
45+ import org .apache .zookeeper .common .Time ;
4046import org .junit .jupiter .api .BeforeEach ;
4147import org .junit .jupiter .api .Test ;
4248import org .slf4j .Logger ;
@@ -54,6 +60,21 @@ public void setUp() throws Exception {
5460 zk = createClient ();
5561 }
5662
63+ private static class ExpiredWatcher implements Watcher {
64+ public volatile CompletableFuture <Void > expired = new CompletableFuture <>();
65+
66+ synchronized void reset () {
67+ expired = new CompletableFuture <>();
68+ }
69+
70+ @ Override
71+ public synchronized void process (WatchedEvent event ) {
72+ if (event .getState () == Event .KeeperState .Expired ) {
73+ expired .complete (null );
74+ }
75+ }
76+ }
77+
5778 private static class BusyServer implements AutoCloseable {
5879 private final ServerSocket server ;
5980 private final Socket client ;
@@ -143,17 +164,24 @@ public void testSessionExpirationAfterAllServerDown() throws Exception {
143164 // stop client also to gain less distraction
144165 zk .close ();
145166
146- // small connection timeout to gain quick ci feedback
147- int sessionTimeout = 3000 ;
148- CompletableFuture < Void > expired = new CompletableFuture <> ();
167+ // given: established session
168+ int sessionTimeout = 3000 ; // small connection timeout to gain quick ci feedback
169+ ExpiredWatcher watcher = new ExpiredWatcher ();
149170 zk = createClient (new CountdownWatcher (), hostPort , sessionTimeout );
150- zk .register (event -> {
151- if ( event . getState () == Watcher . Event . KeeperState . Expired ) {
152- expired . complete ( null );
153- }
154- });
171+ zk .register (watcher );
172+
173+ // when: all server down
174+ long start = Time . currentElapsedTime ();
175+ zk . sync ( "/" ); // touch timeout counts
155176 stopServer ();
156- expired .join ();
177+
178+ // then: get Expired after session timeout
179+ watcher .expired .join ();
180+ long elapsed = Time .currentElapsedTime () - start ;
181+ assertThat (elapsed , greaterThanOrEqualTo ((long ) zk .getSessionTimeout ()));
182+ assertThat (elapsed , lessThan (zk .getSessionTimeout () * 10L ));
183+
184+ // then: future request will get SessionExpiredException
157185 assertThrows (KeeperException .SessionExpiredException .class , () -> zk .exists ("/" , null ));
158186 }
159187
@@ -162,18 +190,17 @@ public void testSessionExpirationWhenNoServerUp() throws Exception {
162190 // stop client also to gain less distraction
163191 zk .close ();
164192
193+ // given: unavailable cluster
165194 stopServer ();
166195
167- // small connection timeout to gain quick ci feedback
168- int sessionTimeout = 3000 ;
169- CompletableFuture <Void > expired = new CompletableFuture <>();
170- new TestableZooKeeper (hostPort , sessionTimeout , event -> {
171- if (event .getState () == Watcher .Event .KeeperState .Expired ) {
172- expired .complete (null );
173- }
174- });
175- expired .join ();
176- assertThrows (KeeperException .SessionExpiredException .class , () -> zk .exists ("/" , null ));
196+ // when: try to establish a brand-new session
197+ int sessionTimeout = 300 ; // small connection timeout to gain quick ci feedback
198+ ExpiredWatcher watcher = new ExpiredWatcher ();
199+ try (ZooKeeper zk = new ZooKeeper (hostPort , sessionTimeout , watcher )) {
200+ // then: never Expired
201+ assertThrows (TimeoutException .class , () -> watcher .expired .get (3 * sessionTimeout , TimeUnit .MILLISECONDS ));
202+ assertThrows (KeeperException .ConnectionLossException .class , () -> zk .exists ("/" , null ));
203+ }
177204 }
178205
179206 @ Test
0 commit comments