This is an automated email from the ASF dual-hosted git repository.

symat pushed a commit to branch branch-3.8
in repository https://gitbox.apache.org/repos/asf/zookeeper.git


The following commit(s) were added to refs/heads/branch-3.8 by this push:
     new c5c46df23 ZOOKEEPER-4308: Fix flaky test EagerACLFilterTest
c5c46df23 is described below

commit c5c46df23877922c05c2e77de730c5bb969faef6
Author: Kezhu Wang <[email protected]>
AuthorDate: Fri Jun 24 15:30:51 2022 +0200

    ZOOKEEPER-4308: Fix flaky test EagerACLFilterTest
    
    There are several problems in this test:
    * It uses `ParameterizedTest` which run tests in single jvm. But
      `ZooKeeperServer.enableEagerACLCheck` is `static` and loaded from env
      variable.
    * It uses `assertNotSame` which assert on object reference equiality.
    * It asserts on `zkLeader.getLastLoggedZxid()` while client connect to
      `connectedServer`. There is no happen-before between
      `zkLeader.getLastLoggedZxid()` and successful response from other
      server. The commit and response are routed to different servers and
      performed asynchronous in each server.
    
    Author: Kezhu Wang <[email protected]>
    
    Reviewers: maoling <[email protected]>, Mate Szalay-Beko 
<[email protected]>
    
    Closes #1851 from kezhuw/ZOOKEEPER-4308-EagerACLFilterTest
    
    (cherry picked from commit 794790c9f6cbacf158493867f3058a6de748b54e)
    Signed-off-by: Mate Szalay-Beko <[email protected]>
---
 .../apache/zookeeper/server/ZooKeeperServer.java   | 13 ++-
 .../server/quorum/EagerACLFilterTest.java          | 98 +++++++++++++++-------
 .../java/org/apache/zookeeper/test/QuorumBase.java |  2 +-
 3 files changed, 82 insertions(+), 31 deletions(-)

diff --git 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperServer.java
 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperServer.java
index 86c13aea3..a87acc124 100644
--- 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperServer.java
+++ 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperServer.java
@@ -110,7 +110,7 @@ public class ZooKeeperServer implements SessionExpirer, 
ServerStats.Provider {
 
     // When enabled, will check ACL constraints appertained to the requests 
first,
     // before sending the requests to the quorum.
-    static final boolean enableEagerACLCheck;
+    static boolean enableEagerACLCheck;
 
     static final boolean skipACL;
 
@@ -157,6 +157,17 @@ public class ZooKeeperServer implements SessionExpirer, 
ServerStats.Provider {
         LOG.info("{} = {}", CLOSE_SESSION_TXN_ENABLED, closeSessionTxnEnabled);
     }
 
+    // @VisibleForTesting
+    public static boolean isEnableEagerACLCheck() {
+        return enableEagerACLCheck;
+    }
+
+    // @VisibleForTesting
+    public static void setEnableEagerACLCheck(boolean enabled) {
+        ZooKeeperServer.enableEagerACLCheck = enabled;
+        LOG.info("Update {} to {}", ENABLE_EAGER_ACL_CHECK, enabled);
+    }
+
     public static boolean isCloseSessionTxnEnabled() {
         return closeSessionTxnEnabled;
     }
diff --git 
a/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/EagerACLFilterTest.java
 
b/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/EagerACLFilterTest.java
index a27d5cf9f..4141c586f 100644
--- 
a/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/EagerACLFilterTest.java
+++ 
b/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/EagerACLFilterTest.java
@@ -19,14 +19,16 @@
 package org.apache.zookeeper.server.quorum;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
-import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CompletableFuture;
 import java.util.stream.Stream;
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.TestableZooKeeper;
 import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.ZooKeeper;
 import org.apache.zookeeper.server.ZooKeeperServer;
 import org.apache.zookeeper.server.quorum.QuorumPeer.ServerState;
 import org.apache.zookeeper.test.QuorumBase;
@@ -38,7 +40,6 @@ import org.junit.jupiter.params.provider.MethodSource;
 
 public class EagerACLFilterTest extends QuorumBase {
 
-    protected final CountDownLatch callComplete = new CountDownLatch(1);
     protected boolean complete = false;
     protected static final String PARENT_PATH = "/foo";
     protected static final String CHILD_PATH = "/foo/bar";
@@ -48,7 +49,9 @@ public class EagerACLFilterTest extends QuorumBase {
     protected static final byte[] DATA = "Hint Water".getBytes();
     protected TestableZooKeeper zkClient;
     protected TestableZooKeeper zkClientB;
+    protected TestableZooKeeper zkLeaderClient;
     protected QuorumPeer zkLeader;
+    protected QuorumPeer zkConnected;
     protected ZooKeeperServer connectedServer;
 
     public static Stream<Arguments> data() {
@@ -70,6 +73,7 @@ public class EagerACLFilterTest extends QuorumBase {
 
     public void setUp(ServerState serverState, boolean checkEnabled) throws 
Exception {
         ensureCheck(checkEnabled);
+        CountdownWatcher leaderWatch = new CountdownWatcher();
         CountdownWatcher clientWatch = new CountdownWatcher();
         CountdownWatcher clientWatchB = new CountdownWatcher();
         super.setUp(true, true);
@@ -78,16 +82,31 @@ public class EagerACLFilterTest extends QuorumBase {
         int clientPort = Integer.parseInt(hostPort.split(":")[1]);
 
         zkLeader = getPeerList().get(getLeaderIndex());
-        connectedServer = getPeerByClientPort(clientPort).getActiveServer();
+        zkConnected = getPeerByClientPort(clientPort);
+        connectedServer = zkConnected.getActiveServer();
 
+        zkLeaderClient = createClient(leaderWatch, 
getPeersMatching(ServerState.LEADING));
         zkClient = createClient(clientWatch, hostPort);
         zkClientB = createClient(clientWatchB, hostPort);
         zkClient.addAuthInfo(AUTH_PROVIDER, AUTH);
         zkClientB.addAuthInfo(AUTH_PROVIDER, AUTHB);
+        leaderWatch.waitForConnected(CONNECTION_TIMEOUT);
         clientWatch.waitForConnected(CONNECTION_TIMEOUT);
         clientWatchB.waitForConnected(CONNECTION_TIMEOUT);
     }
 
+    void syncClient(ZooKeeper zk) {
+        CompletableFuture<Void> synced = new CompletableFuture<>();
+        zk.sync("/", (rc, path, ctx) -> {
+            if (rc == 0) {
+                synced.complete(null);
+            } else {
+                
synced.completeExceptionally(KeeperException.create(KeeperException.Code.get(rc)));
+            }
+        }, null);
+        synced.join();
+    }
+
     @AfterEach
     public void tearDown() throws Exception {
         if (zkClient != null) {
@@ -102,19 +121,29 @@ public class EagerACLFilterTest extends QuorumBase {
     }
 
     private void ensureCheck(boolean enabled) {
-        if (enabled) {
-            System.setProperty(ZooKeeperServer.ENABLE_EAGER_ACL_CHECK, "true");
-        } else {
-            System.clearProperty(ZooKeeperServer.ENABLE_EAGER_ACL_CHECK);
-        }
+        ZooKeeperServer.setEnableEagerACLCheck(enabled);
     }
 
-    private void assertTransactionState(String condition, long lastxid, 
ServerState serverState, boolean checkEnabled) {
-        String assertion = String.format("Server State: %s Check Enabled: %s 
%s", serverState, checkEnabled, condition);
-        if (checkEnabled) {
-            assertEquals(lastxid, zkLeader.getLastLoggedZxid(), assertion);
+    private void assertTransactionState(String operation, QuorumPeer peer, 
long lastxid) {
+        if (peer == zkLeader && peer != zkConnected) {
+            // The operation is performed on no leader, but we are asserting 
on leader.
+            // There is no happen-before between 
`zkLeader.getLastLoggedZxid()` and
+            // successful response from other server. The commit and response 
are routed
+            // to different servers and performed asynchronous in each server. 
So we have
+            // to sync leader client to go through commit and response path in 
leader to
+            // build happen-before between `zkLeader.getLastLoggedZxid()` and 
side effect
+            // of previous operation.
+            syncClient(zkLeaderClient);
+        }
+        assertTrue(peer == zkLeader || peer == zkConnected);
+        boolean eagerACL = ZooKeeperServer.isEnableEagerACLCheck();
+        String assertion = String.format(
+                "Connecting: %s Checking: %s EagerACL: %s Operation: %s",
+                zkConnected.getPeerState(), peer.getPeerState(), eagerACL, 
operation);
+        if (eagerACL) {
+            assertEquals(lastxid, peer.getLastLoggedZxid(), assertion);
         } else {
-            assertNotSame(lastxid, zkLeader.getLastLoggedZxid(), assertion);
+            assertNotEquals(lastxid, peer.getLastLoggedZxid(), assertion);
         }
     }
 
@@ -144,15 +173,17 @@ public class EagerACLFilterTest extends QuorumBase {
     public void testCreateFail(ServerState serverState, boolean checkEnabled) 
throws Exception {
         setUp(serverState, checkEnabled);
         zkClient.create(PARENT_PATH, DATA, Ids.CREATOR_ALL_ACL, 
CreateMode.PERSISTENT);
-        long lastxid = zkLeader.getLastLoggedZxid();
+        long lastxid = zkConnected.getLastLoggedZxid();
         try {
             zkClientB.create(CHILD_PATH, DATA, Ids.OPEN_ACL_UNSAFE, 
CreateMode.PERSISTENT);
+            fail("expect no auth");
         } catch (KeeperException.NoAuthException e) {
         }
 
         assertEquals(0, connectedServer.getInProcess(), "OutstandingRequests 
not decremented");
 
-        assertTransactionState("Transaction state on Leader after failed 
create", lastxid, serverState, checkEnabled);
+        assertTransactionState("failed create", zkConnected, lastxid);
+        assertTransactionState("failed create", zkLeader, lastxid);
     }
 
     @ParameterizedTest
@@ -160,15 +191,17 @@ public class EagerACLFilterTest extends QuorumBase {
     public void testCreate2Fail(ServerState serverState, boolean checkEnabled) 
throws Exception {
         setUp(serverState, checkEnabled);
         zkClient.create(PARENT_PATH, DATA, Ids.CREATOR_ALL_ACL, 
CreateMode.PERSISTENT, null);
-        long lastxid = zkLeader.getLastLoggedZxid();
+        long lastxid = zkConnected.getLastLoggedZxid();
         try {
             zkClientB.create(CHILD_PATH, DATA, Ids.OPEN_ACL_UNSAFE, 
CreateMode.PERSISTENT, null);
+            fail("expect no auth");
         } catch (KeeperException.NoAuthException e) {
         }
 
         assertEquals(0, connectedServer.getInProcess(), "OutstandingRequests 
not decremented");
 
-        assertTransactionState("Transaction state on Leader after failed 
create2", lastxid, serverState, checkEnabled);
+        assertTransactionState("failed create2", zkConnected, lastxid);
+        assertTransactionState("failed create2", zkLeader, lastxid);
     }
 
     @ParameterizedTest
@@ -187,15 +220,17 @@ public class EagerACLFilterTest extends QuorumBase {
         setUp(serverState, checkEnabled);
         zkClient.create(PARENT_PATH, DATA, Ids.CREATOR_ALL_ACL, 
CreateMode.PERSISTENT, null);
         zkClient.create(CHILD_PATH, DATA, Ids.CREATOR_ALL_ACL, 
CreateMode.PERSISTENT, null);
-        long lastxid = zkLeader.getLastLoggedZxid();
+        long lastxid = zkConnected.getLastLoggedZxid();
         try {
             zkClientB.delete(CHILD_PATH, -1);
+            fail("expect no auth");
         } catch (KeeperException.NoAuthException e) {
         }
 
         assertEquals(0, connectedServer.getInProcess(), "OutstandingRequests 
not decremented");
 
-        assertTransactionState("Transaction state on Leader after failed 
delete", lastxid, serverState, checkEnabled);
+        assertTransactionState("failed delete", zkConnected, lastxid);
+        assertTransactionState("failed delete", zkLeader, lastxid);
     }
 
     @ParameterizedTest
@@ -211,15 +246,17 @@ public class EagerACLFilterTest extends QuorumBase {
     public void testSetDataFail(ServerState serverState, boolean checkEnabled) 
throws Exception {
         setUp(serverState, checkEnabled);
         zkClient.create(PARENT_PATH, null, Ids.CREATOR_ALL_ACL, 
CreateMode.PERSISTENT, null);
-        long lastxid = zkLeader.getLastLoggedZxid();
+        long lastxid = zkConnected.getLastLoggedZxid();
         try {
             zkClientB.setData(PARENT_PATH, DATA, -1);
+            fail("expect no auth");
         } catch (KeeperException.NoAuthException e) {
         }
 
         assertEquals(0, connectedServer.getInProcess(), "OutstandingRequests 
not decremented");
 
-        assertTransactionState("Transaction state on Leader after failed 
setData", lastxid, serverState, checkEnabled);
+        assertTransactionState("failed setData", zkConnected, lastxid);
+        assertTransactionState("failed setData", zkLeader, lastxid);
     }
 
     @ParameterizedTest
@@ -237,15 +274,17 @@ public class EagerACLFilterTest extends QuorumBase {
     public void testSetACLFail(ServerState serverState, boolean checkEnabled) 
throws Exception {
         setUp(serverState, checkEnabled);
         zkClient.create(PARENT_PATH, null, Ids.CREATOR_ALL_ACL, 
CreateMode.PERSISTENT, null);
-        long lastxid = zkLeader.getLastLoggedZxid();
+        long lastxid = zkConnected.getLastLoggedZxid();
         try {
             zkClientB.setACL(PARENT_PATH, Ids.READ_ACL_UNSAFE, -1);
-        } catch (KeeperException.NoAuthException e) {
+            fail("expect no auth");
+        } catch (KeeperException.NoAuthException ignored) {
         }
 
         assertEquals(0, connectedServer.getInProcess(), "OutstandingRequests 
not decremented");
 
-        assertTransactionState("Transaction state on Leader after failed 
setACL", lastxid, serverState, checkEnabled);
+        assertTransactionState("failed setACL", zkConnected, lastxid);
+        assertTransactionState("failed setACL", zkLeader, lastxid);
     }
 
     @ParameterizedTest
@@ -253,12 +292,12 @@ public class EagerACLFilterTest extends QuorumBase {
     public void testBadACL(ServerState serverState, boolean checkEnabled) 
throws Exception {
         setUp(serverState, checkEnabled);
         CountdownWatcher cw = new CountdownWatcher();
-        TestableZooKeeper zk = createClient(cw, getPeersMatching(serverState));
-        long lastxid;
+        String addr = String.format("%s:%d", LOCALADDR, 
zkConnected.getClientPort());
+        TestableZooKeeper zk = createClient(cw, addr);
 
         cw.waitForConnected(CONNECTION_TIMEOUT);
 
-        lastxid = zkLeader.getLastLoggedZxid();
+        long lastxid = zkConnected.getLastLoggedZxid();
 
         try {
             zk.create("/acltest", new byte[0], Ids.CREATOR_ALL_ACL, 
CreateMode.PERSISTENT);
@@ -268,7 +307,8 @@ public class EagerACLFilterTest extends QuorumBase {
 
         assertEquals(0, connectedServer.getInProcess(), "OutstandingRequests 
not decremented");
 
-        assertTransactionState("zxid after invalid ACL", lastxid, serverState, 
checkEnabled);
+        assertTransactionState("invalid ACL", zkConnected, lastxid);
+        assertTransactionState("invalid ACL", zkLeader, lastxid);
     }
 
 }
diff --git 
a/zookeeper-server/src/test/java/org/apache/zookeeper/test/QuorumBase.java 
b/zookeeper-server/src/test/java/org/apache/zookeeper/test/QuorumBase.java
index 8f5f17db7..4f723f299 100644
--- a/zookeeper-server/src/test/java/org/apache/zookeeper/test/QuorumBase.java
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/QuorumBase.java
@@ -47,7 +47,7 @@ public class QuorumBase extends ClientBase {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(QuorumBase.class);
 
-    private static final String LOCALADDR = "127.0.0.1";
+    protected static final String LOCALADDR = "127.0.0.1";
 
     private File oracleDir;
     private static final String oraclePath_0 = "/oraclePath/0/mastership/";

Reply via email to