diff --git a/agents/drivers/zookeeper/src/main/java/com/dbx/agent/zookeeper/ZooKeeperAgent.java b/agents/drivers/zookeeper/src/main/java/com/dbx/agent/zookeeper/ZooKeeperAgent.java index 72b4329266..5cca0ccbd3 100644 --- a/agents/drivers/zookeeper/src/main/java/com/dbx/agent/zookeeper/ZooKeeperAgent.java +++ b/agents/drivers/zookeeper/src/main/java/com/dbx/agent/zookeeper/ZooKeeperAgent.java @@ -386,6 +386,11 @@ public final class ZooKeeperAgent { private static Map valueObject(byte[] bytes) { Map value = new LinkedHashMap<>(); + // ZooKeeper represents znodes created without a data payload as null. + // Expose them as empty UTF-8 values instead of passing null to decoders. + if (bytes == null) { + bytes = new byte[0]; + } String utf8 = strictUtf8(bytes); if (utf8 != null) { value.put("encoding", "utf8"); diff --git a/agents/drivers/zookeeper/src/test/java/com/dbx/agent/zookeeper/ZooKeeperAgentTest.java b/agents/drivers/zookeeper/src/test/java/com/dbx/agent/zookeeper/ZooKeeperAgentTest.java index c50f3518a7..0f11aa774f 100644 --- a/agents/drivers/zookeeper/src/test/java/com/dbx/agent/zookeeper/ZooKeeperAgentTest.java +++ b/agents/drivers/zookeeper/src/test/java/com/dbx/agent/zookeeper/ZooKeeperAgentTest.java @@ -4,7 +4,12 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.retry.ExponentialBackoffRetry; import org.apache.curator.test.TestingServer; +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.ZooDefs; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -175,6 +180,31 @@ final class ZooKeeperAgentTest { } } + @Test + void kvGetReadsZnodeCreatedWithoutDataAsEmptyUtf8() throws Exception { + try (TestingServer server = new TestingServer(); + CuratorFramework curator = CuratorFrameworkFactory.newClient( + server.getConnectString(), + new ExponentialBackoffRetry(100, 3) + )) { + curator.start(); + curator.getZookeeperClient().getZooKeeper().create( + "/empty", + null, + ZooDefs.Ids.OPEN_ACL_UNSAFE, + CreateMode.PERSISTENT + ); + connect(server); + + JsonObject get = result(request(3, "kv_get", "{\"key\":\"/empty\"}")); + + Assertions.assertTrue(get.get("found").getAsBoolean()); + Assertions.assertEquals("utf8", get.getAsJsonObject("value").get("encoding").getAsString()); + Assertions.assertEquals("", get.getAsJsonObject("value").get("data").getAsString()); + Assertions.assertEquals(0, get.getAsJsonObject("metadata").get("valueSize").getAsInt()); + } + } + @Test void kvPutUpdatesExistingZnode() throws Exception { try (TestingServer server = new TestingServer()) {