fix errors in merge (incomplete synchronization, incorrect handling of k in some cases), refactor and use imports to improve code readability a bit, create merge tests
diff --git a/src/main/java/org/apache/datasketches/server/MergeHandler.java b/src/main/java/org/apache/datasketches/server/MergeHandler.java
index d75fad1..116febf 100644
--- a/src/main/java/org/apache/datasketches/server/MergeHandler.java
+++ b/src/main/java/org/apache/datasketches/server/MergeHandler.java
@@ -19,6 +19,13 @@
package org.apache.datasketches.server;
+import static org.apache.datasketches.server.SketchConstants.QUERY_DATA_FIELD;
+import static org.apache.datasketches.server.SketchConstants.QUERY_FAMILY_FIELD;
+import static org.apache.datasketches.server.SketchConstants.QUERY_MERGE_K_FIELD;
+import static org.apache.datasketches.server.SketchConstants.QUERY_MERGE_SRC_FIELD;
+import static org.apache.datasketches.server.SketchConstants.QUERY_MERGE_TGT_FIELD;
+import static org.apache.datasketches.server.SketchConstants.QUERY_SKETCH_FIELD;
+
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashSet;
@@ -83,7 +90,7 @@
// optional targets:
// If no QUERY_MERGE_TGT_FIELD serialize the result, but then need specify QUERY_MERGE_K_FIELD.
// If a valid target is present, any value of QUERY_MERGE_K_FIELD is ignored
- final JsonElement dstElement = query.get(SketchConstants.QUERY_MERGE_TGT_FIELD);
+ final JsonElement dstElement = query.get(QUERY_MERGE_TGT_FIELD);
final String dst = dstElement != null ? dstElement.getAsString() : null;
if (dst != null && !sketches.contains(dst)) {
throw new IllegalArgumentException("Specified target sketch does not exist: " + dst);
@@ -91,15 +98,15 @@
int k = 0;
if (dst == null) {
- final JsonElement kElement = query.get(SketchConstants.QUERY_MERGE_K_FIELD);
- if (kElement == null) {
- throw new IllegalArgumentException("Must specify either \"" + SketchConstants.QUERY_MERGE_TGT_FIELD
- + "\" or \"" + SketchConstants.QUERY_MERGE_K_FIELD + "\". Neither found.");
+ final JsonElement kElement = query.get(QUERY_MERGE_K_FIELD);
+ if (kElement == null || !kElement.isJsonPrimitive() || !kElement.getAsJsonPrimitive().isNumber()) {
+ throw new IllegalArgumentException("Must specify either \"" + QUERY_MERGE_TGT_FIELD
+ + "\" or a numeric value for \"" + QUERY_MERGE_K_FIELD + "\". Neither found.");
}
k = kElement.getAsInt();
}
- final JsonElement srcElement = query.get(SketchConstants.QUERY_MERGE_SRC_FIELD);
+ final JsonElement srcElement = query.get(QUERY_MERGE_SRC_FIELD);
if (srcElement == null || !srcElement.isJsonArray()) {
throw new IllegalArgumentException("Merge source data must be a JSON Array");
}
@@ -110,6 +117,7 @@
if (dst != null) {
se = sketches.getSketch(dst);
dstFamily = se.family_;
+ k = se.configK_;
}
// we'll process (and dedup) any stored sketches before we handle encoded inputs
@@ -130,7 +138,7 @@
// skBytes == null if merging into another sketch; only non-null if returning a serialized image
if (skBytes != null) {
final JsonObject result = new JsonObject();
- result.addProperty(SketchConstants.QUERY_SKETCH_FIELD, Base64.getUrlEncoder().encodeToString(skBytes));
+ result.addProperty(QUERY_SKETCH_FIELD, Base64.getUrlEncoder().encodeToString(skBytes));
return result;
} else {
return null;
@@ -174,14 +182,14 @@
} else { // is JsonObject
// need special handling for theta as we store Unions?
final JsonObject sourceObj = elmt.getAsJsonObject();
- if (!sourceObj.has(SketchConstants.QUERY_FAMILY_FIELD)
- || !sourceObj.has(SketchConstants.QUERY_DATA_FIELD)) {
+ if (!sourceObj.has(QUERY_FAMILY_FIELD)
+ || !sourceObj.has(QUERY_DATA_FIELD)) {
throw new SketchesException("Base64 sketch used as merge input must specify both \""
- + SketchConstants.QUERY_FAMILY_FIELD + "\" and \"" + SketchConstants.QUERY_DATA_FIELD + "\"");
+ + QUERY_FAMILY_FIELD + "\" and \"" + QUERY_DATA_FIELD + "\"");
}
- final Family skFamily = familyFromString(sourceObj.get(SketchConstants.QUERY_FAMILY_FIELD).getAsString());
- final String skString = sourceObj.get(SketchConstants.QUERY_DATA_FIELD).getAsString();
+ final Family skFamily = familyFromString(sourceObj.get(QUERY_FAMILY_FIELD).getAsString());
+ final String skString = sourceObj.get(QUERY_DATA_FIELD).getAsString();
if (skString == null || (family != null
&& ((family != Family.UNION && family != skFamily) || (family == Family.UNION && skFamily != Family.QUICKSELECT)))) {
throw new SketchesException("Input sketches must exist and be of the same family as the target");
@@ -266,8 +274,10 @@
if (dstEntry != null) {
union.update((HllSketch) dstEntry.sketch_);
}
- for (final Object obj : sketchList) {
- union.update((HllSketch) obj);
+ for (final MergeEntry me : sketchList) {
+ synchronized (me.name_.intern()) {
+ union.update((HllSketch) me.sketch_);
+ }
}
if (dstEntry == null) {
@@ -283,8 +293,10 @@
if (dstEntry != null) {
union.update((CpcSketch) dstEntry.sketch_);
}
- for (final Object obj : sketchList) {
- union.update((CpcSketch) obj);
+ for (final MergeEntry me : sketchList) {
+ synchronized (me.name_.intern()) {
+ union.update((CpcSketch) me.sketch_);
+ }
}
if (dstEntry == null) {
@@ -299,8 +311,10 @@
// Only merge(), no separate union. Slightly abusing terminology to call it union
final KllFloatsSketch union = dstEntry == null ? new KllFloatsSketch(k) : (KllFloatsSketch) dstEntry.sketch_;
- for (final Object obj : sketchList) {
- union.merge((KllFloatsSketch) obj);
+ for (final MergeEntry me : sketchList) {
+ synchronized (me.name_.intern()) {
+ union.merge((KllFloatsSketch) me.sketch_);
+ }
}
if (dstEntry == null) {
@@ -315,8 +329,10 @@
// Only merge(), no separate union. Slightly abusing terminology to call it union
final ItemsSketch<String> union = dstEntry == null ? new ItemsSketch<>(k) : (ItemsSketch<String>) dstEntry.sketch_;
- for (final Object obj : sketchList) {
- union.merge((ItemsSketch<String>) obj);
+ for (final MergeEntry me : sketchList) {
+ synchronized (me.name_.intern()) {
+ union.merge((ItemsSketch<String>) me.sketch_);
+ }
}
if (dstEntry == null) {
@@ -333,8 +349,10 @@
union.update((ReservoirItemsSketch<String>) dstEntry.sketch_);
}
- for (final Object obj : sketchList) {
- union.update((ReservoirItemsSketch<String>) obj);
+ for (final MergeEntry me : sketchList) {
+ synchronized (me.name_.intern()) {
+ union.update((ReservoirItemsSketch<String>) me.sketch_);
+ }
}
if (dstEntry == null) {
@@ -351,8 +369,10 @@
union.update((VarOptItemsSketch<String>) dstEntry.sketch_);
}
- for (final Object obj : sketchList) {
- union.update((VarOptItemsSketch<String>) obj);
+ for (final MergeEntry me : sketchList) {
+ synchronized (me.name_.intern()) {
+ union.update((VarOptItemsSketch<String>) me.sketch_);
+ }
}
if (dstEntry == null) {
diff --git a/src/test/java/org/apache/datasketches/server/DataQueryHandlerTest.java b/src/test/java/org/apache/datasketches/server/DataQueryHandlerTest.java
index 43922e5..f38e344 100644
--- a/src/test/java/org/apache/datasketches/server/DataQueryHandlerTest.java
+++ b/src/test/java/org/apache/datasketches/server/DataQueryHandlerTest.java
@@ -28,7 +28,6 @@
import static org.apache.datasketches.server.SketchConstants.QUERY_PATH;
import static org.apache.datasketches.server.SketchConstants.QUERY_PMF_VALUES_FIELD_NAME;
import static org.apache.datasketches.server.SketchConstants.QUERY_SUMMARY_FIELD;
-import static org.apache.datasketches.server.SketchConstants.RESET_PATH;
import static org.apache.datasketches.server.SketchConstants.RESPONSE_CDF_LIST;
import static org.apache.datasketches.server.SketchConstants.RESPONSE_ESTIMATE_FIELD;
import static org.apache.datasketches.server.SketchConstants.RESPONSE_ESTIMATION_MODE_FIELD;
diff --git a/src/test/java/org/apache/datasketches/server/MergeHandlerTest.java b/src/test/java/org/apache/datasketches/server/MergeHandlerTest.java
index 291138e..bb3e83a 100644
--- a/src/test/java/org/apache/datasketches/server/MergeHandlerTest.java
+++ b/src/test/java/org/apache/datasketches/server/MergeHandlerTest.java
@@ -1,2 +1,512 @@
-package org.apache.datasketches.server;public class MergeHandlerTest {
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.server;
+
+import static org.apache.datasketches.server.SketchConstants.MERGE_PATH;
+import static org.apache.datasketches.server.SketchConstants.QUERY_DATA_FIELD;
+import static org.apache.datasketches.server.SketchConstants.QUERY_FAMILY_FIELD;
+import static org.apache.datasketches.server.SketchConstants.QUERY_MERGE_K_FIELD;
+import static org.apache.datasketches.server.SketchConstants.QUERY_MERGE_SRC_FIELD;
+import static org.apache.datasketches.server.SketchConstants.QUERY_MERGE_TGT_FIELD;
+import static org.apache.datasketches.server.SketchConstants.QUERY_SKETCH_FIELD;
+import static org.apache.datasketches.server.SketchConstants.SKETCH_FAMILY_CPC;
+import static org.apache.datasketches.server.SketchConstants.SKETCH_FAMILY_FREQUENCY;
+import static org.apache.datasketches.server.SketchConstants.SKETCH_FAMILY_HLL;
+import static org.apache.datasketches.server.SketchConstants.SKETCH_FAMILY_KLL;
+import static org.apache.datasketches.server.SketchConstants.SKETCH_FAMILY_RESERVOIR;
+import static org.apache.datasketches.server.SketchConstants.SKETCH_FAMILY_THETA;
+import static org.apache.datasketches.server.SketchConstants.SKETCH_FAMILY_VAROPT;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Base64;
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.apache.datasketches.ArrayOfStringsSerDe;
+import org.apache.datasketches.cpc.CpcSketch;
+import org.apache.datasketches.cpc.CpcUnion;
+import org.apache.datasketches.hll.HllSketch;
+import org.apache.datasketches.kll.KllFloatsSketch;
+import org.apache.datasketches.frequencies.ItemsSketch;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.sampling.ReservoirItemsSketch;
+import org.apache.datasketches.sampling.ReservoirItemsUnion;
+import org.apache.datasketches.sampling.VarOptItemsSketch;
+import org.apache.datasketches.sampling.VarOptItemsUnion;
+import org.apache.datasketches.theta.Union;
+import org.eclipse.jetty.http.HttpStatus;
+import org.testng.annotations.Test;
+
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+
+public class MergeHandlerTest extends ServerTestBase {
+ /* Using knowledge of the implementation of merging, much of the merging code is generic
+ * and shared across sketch types. These tests will cover some features only with a single
+ * sketch type (theta) in order to avoid lots of repetitive tests, without sacrificing
+ * functional coverage.
+ */
+
+ @Test
+ public void errorMerges() {
+ final JsonObject response = new JsonObject();
+ JsonObject request = new JsonObject();
+
+ // completely empty request cannot be handled
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.UNPROCESSABLE_ENTITY_422);
+
+ // invalid name field with real sketch name
+ request.addProperty("notAName", "theta0");
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.UNPROCESSABLE_ENTITY_422);
+
+ // valid name, empty value
+ request = new JsonObject();
+ request.add(QUERY_MERGE_TGT_FIELD, new JsonObject());
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.UNPROCESSABLE_ENTITY_422);
+
+ // valid "name" field, invalid sketch name
+ request = new JsonObject();
+ request.addProperty(QUERY_MERGE_TGT_FIELD, "sketchDoesNotExist");
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.UNPROCESSABLE_ENTITY_422);
+
+ // no name, k is not a number
+ request = new JsonObject();
+ request.addProperty(QUERY_MERGE_K_FIELD, "isNotNumber");
+
+ // valid name with real sketch, no source sketches
+ request.addProperty(QUERY_MERGE_TGT_FIELD, "theta2");
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.UNPROCESSABLE_ENTITY_422);
+
+ // valid name with real sketch, source is not JsonArray
+ request.addProperty(QUERY_MERGE_SRC_FIELD, "notAnArray");
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.UNPROCESSABLE_ENTITY_422);
+
+ // serialized input sketch missing family type
+ JsonArray inputSketches = new JsonArray(1);
+ JsonObject sketchInfo = new JsonObject();
+ final CpcSketch cpc = new CpcSketch(10);
+ sketchInfo.addProperty(QUERY_DATA_FIELD, Base64.getUrlEncoder().encodeToString(cpc.toByteArray()));
+ inputSketches.add(sketchInfo);
+ request.add(QUERY_MERGE_SRC_FIELD, inputSketches);
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.UNPROCESSABLE_ENTITY_422);
+
+ // serialized input sketch missing value
+ inputSketches = new JsonArray(1);
+ sketchInfo = new JsonObject();
+ sketchInfo.addProperty(QUERY_FAMILY_FIELD, SKETCH_FAMILY_CPC);
+ inputSketches.add(sketchInfo);
+ request.add(QUERY_MERGE_SRC_FIELD, inputSketches);
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.UNPROCESSABLE_ENTITY_422);
+
+ // serialized input with conflicting sketch types
+ inputSketches = new JsonArray(1);
+ sketchInfo.addProperty(QUERY_DATA_FIELD, Base64.getUrlEncoder().encodeToString(cpc.toByteArray()));
+ inputSketches.add(sketchInfo);
+ request.add(QUERY_MERGE_SRC_FIELD, inputSketches);
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.UNPROCESSABLE_ENTITY_422);
+
+ // input as existing sketch of wrong family
+ inputSketches = new JsonArray(1);
+ inputSketches.add("cpcOfLongs");
+ request.add(QUERY_MERGE_SRC_FIELD, inputSketches);
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.UNPROCESSABLE_ENTITY_422);
+ }
+
+ @Test
+ public void cpcMerge() {
+ final String tgtName = "cpcOfLongs";
+ final JsonObject response = new JsonObject();
+ final JsonObject request = new JsonObject();
+
+ // add data to a couple sketches that we'll pass in via serialization
+ final int n = 5000;
+ final int offset = n / 2;
+ final int k = server_.getSketch(tgtName).configK_;
+ final CpcSketch sk1 = new CpcSketch(k);
+ final CpcSketch sk2 = new CpcSketch(k + 1);
+ for (int i = 0; i < n; ++i) {
+ sk1.update(i);
+ sk2.update(offset + i);
+ }
+ final CpcUnion union = new CpcUnion(k);
+ union.update(sk1);
+ union.update(sk2);
+ final byte[] tgtBytes = union.getResult().toByteArray();
+
+ // add sketches to the request
+ final JsonArray srcSketches = new JsonArray(2);
+
+ final JsonObject serializedSketch1 = new JsonObject();
+ serializedSketch1.addProperty(QUERY_FAMILY_FIELD, SKETCH_FAMILY_CPC);
+ serializedSketch1.addProperty(QUERY_DATA_FIELD, Base64.getUrlEncoder().encodeToString(sk1.toByteArray()));
+ srcSketches.add(serializedSketch1);
+
+ final JsonObject serializedSketch2 = new JsonObject();
+ serializedSketch2.addProperty(QUERY_FAMILY_FIELD, SKETCH_FAMILY_CPC);
+ serializedSketch2.addProperty(QUERY_DATA_FIELD, Base64.getUrlEncoder().encodeToString(sk2.toByteArray()));
+ srcSketches.add(serializedSketch2);
+ request.add(QUERY_MERGE_SRC_FIELD, srcSketches);
+
+ // serialized sketch, so set the k value
+ request.addProperty(QUERY_MERGE_K_FIELD, k);
+
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.OK_200);
+ final JsonObject responseData = response.getAsJsonObject(RESPONSE_FIELD).getAsJsonObject();
+ assertTrue(responseData.has(QUERY_SKETCH_FIELD));
+ assertEquals(Base64.getUrlDecoder().decode(responseData.get(QUERY_SKETCH_FIELD).getAsString()), tgtBytes);
+
+ // save into a target
+ request.addProperty(QUERY_MERGE_TGT_FIELD, tgtName);
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.OK_200);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
+ assertEquals(((CpcSketch) server_.getSketch(tgtName).sketch_).toByteArray(), tgtBytes);
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void fiMerge() {
+ final String tgtName = "topItems";
+ final JsonObject response = new JsonObject();
+ final JsonObject request = new JsonObject();
+
+ // add data to a couple sketches that we'll pass in via serialization
+ final int n = 25;
+ final int offset = 5;
+ final int k = server_.getSketch(tgtName).configK_;
+ final ItemsSketch<String> sk1 = new ItemsSketch<>(k * 2);
+ final ItemsSketch<String> sk2 = new ItemsSketch<>(k);
+ for (int i = 1; i <= n; ++i) {
+ sk1.update(Integer.toString(i), i * i);
+ sk2.update(Integer.toString(offset + i), (n - i) * (n - i));
+ }
+ final ItemsSketch<String> union = new ItemsSketch<>(k);
+ union.merge(sk1);
+ union.merge(sk2);
+ final byte[] tgtBytes = union.toByteArray(new ArrayOfStringsSerDe());
+
+ // add sketches to the request
+ final JsonArray srcSketches = new JsonArray(2);
+
+ final JsonObject serializedSketch1 = new JsonObject();
+ serializedSketch1.addProperty(QUERY_FAMILY_FIELD, SKETCH_FAMILY_FREQUENCY);
+ serializedSketch1.addProperty(QUERY_DATA_FIELD, Base64.getUrlEncoder().encodeToString(sk1.toByteArray(new ArrayOfStringsSerDe())));
+ srcSketches.add(serializedSketch1);
+
+ final JsonObject serializedSketch2 = new JsonObject();
+ serializedSketch2.addProperty(QUERY_FAMILY_FIELD, SKETCH_FAMILY_FREQUENCY);
+ serializedSketch2.addProperty(QUERY_DATA_FIELD, Base64.getUrlEncoder().encodeToString(sk2.toByteArray(new ArrayOfStringsSerDe())));
+ srcSketches.add(serializedSketch2);
+ request.add(QUERY_MERGE_SRC_FIELD, srcSketches);
+
+ // serialized sketch, so set the k value
+ request.addProperty(QUERY_MERGE_K_FIELD, k);
+
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.OK_200);
+ final JsonObject responseData = response.getAsJsonObject(RESPONSE_FIELD).getAsJsonObject();
+ assertTrue(responseData.has(QUERY_SKETCH_FIELD));
+ assertEquals(Base64.getUrlDecoder().decode(responseData.get(QUERY_SKETCH_FIELD).getAsString()), tgtBytes);
+
+ // save into a target
+ request.addProperty(QUERY_MERGE_TGT_FIELD, tgtName);
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.OK_200);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
+ assertEquals(((ItemsSketch<String>) server_.getSketch(tgtName).sketch_).toByteArray(new ArrayOfStringsSerDe()), tgtBytes);
+ }
+
+ @Test
+ public void hllMerge() {
+ final String tgtName = "hll3";
+ final JsonObject response = new JsonObject();
+ final JsonObject request = new JsonObject();
+
+ // add data to a couple sketches that we'll pass in via serialization
+ final int n = 7500;
+ final int offset = n / 3;
+ final int k = server_.getSketch(tgtName).configK_;
+ final HllSketch sk1 = (HllSketch) server_.getSketch("hll1").sketch_;
+ final HllSketch sk2 = (HllSketch) server_.getSketch("hll2").sketch_;
+ for (int i = 0; i < n; ++i) {
+ sk1.update(i);
+ sk2.update(offset + i);
+ }
+ final org.apache.datasketches.hll.Union union = new org.apache.datasketches.hll.Union(k);
+ union.update(sk1);
+ union.update(sk2);
+ final byte[] tgtBytes = union.getResult().toCompactByteArray();
+
+ // add sketches to the request
+ final JsonArray srcSketches = new JsonArray(2);
+ final JsonObject serializedSketch = new JsonObject();
+ serializedSketch.addProperty(QUERY_FAMILY_FIELD, SKETCH_FAMILY_HLL);
+ serializedSketch.addProperty(QUERY_DATA_FIELD, Base64.getUrlEncoder().encodeToString(sk2.toCompactByteArray()));
+ srcSketches.add(serializedSketch);
+ srcSketches.add("hll1");
+ request.add(QUERY_MERGE_SRC_FIELD, srcSketches);
+
+ // serialized sketch, so set the k value
+ request.addProperty(QUERY_MERGE_K_FIELD, k);
+
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.OK_200);
+ final JsonObject responseData = response.getAsJsonObject(RESPONSE_FIELD).getAsJsonObject();
+ assertTrue(responseData.has(QUERY_SKETCH_FIELD));
+ assertEquals(Base64.getUrlDecoder().decode(responseData.get(QUERY_SKETCH_FIELD).getAsString()), tgtBytes);
+
+ // save into a target
+ request.remove(QUERY_MERGE_K_FIELD);
+ request.addProperty(QUERY_MERGE_TGT_FIELD, tgtName);
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.OK_200);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
+ assertEquals(((HllSketch) server_.getSketch(tgtName).sketch_).toCompactByteArray(), tgtBytes);
+
+ }
+
+ @Test
+ public void kllMerge() {
+ final String tgtName = "duration";
+ final JsonObject response = new JsonObject();
+ final JsonObject request = new JsonObject();
+
+ // add data to a couple sketches that we'll pass in via serialization
+ final int n = 6000;
+ final int k = server_.getSketch(tgtName).configK_;
+ final KllFloatsSketch sk1 = new KllFloatsSketch(k + 20);
+ final KllFloatsSketch sk2 = new KllFloatsSketch(k);
+ final ThreadLocalRandom rand = ThreadLocalRandom.current();
+ for (int i = 1; i <= n; ++i) {
+ // unequal number of input points for the sketches
+ sk1.update((float) rand.nextGaussian());
+ sk2.update((float) rand.nextGaussian() + 2);
+ sk2.update((float) rand.nextGaussian() + 3);
+ }
+ final KllFloatsSketch union = new KllFloatsSketch(k);
+ union.merge(sk1);
+ union.merge(sk2);
+
+ // add sketches to the request
+ final JsonArray srcSketches = new JsonArray(2);
+
+ final JsonObject serializedSketch1 = new JsonObject();
+ serializedSketch1.addProperty(QUERY_FAMILY_FIELD, SKETCH_FAMILY_KLL);
+ serializedSketch1.addProperty(QUERY_DATA_FIELD, Base64.getUrlEncoder().encodeToString(sk1.toByteArray()));
+ srcSketches.add(serializedSketch1);
+
+ final JsonObject serializedSketch2 = new JsonObject();
+ serializedSketch2.addProperty(QUERY_FAMILY_FIELD, SKETCH_FAMILY_KLL);
+ serializedSketch2.addProperty(QUERY_DATA_FIELD, Base64.getUrlEncoder().encodeToString(sk2.toByteArray()));
+ srcSketches.add(serializedSketch2);
+ request.add(QUERY_MERGE_SRC_FIELD, srcSketches);
+
+ // serialized sketch, so set the k value
+ request.addProperty(QUERY_MERGE_K_FIELD, k);
+
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.OK_200);
+ final JsonObject responseData = response.getAsJsonObject(RESPONSE_FIELD).getAsJsonObject();
+ assertTrue(responseData.has(QUERY_SKETCH_FIELD));
+ byte[] skBytes = Base64.getUrlDecoder().decode(responseData.get(QUERY_SKETCH_FIELD).getAsString());
+ KllFloatsSketch rebuilt = KllFloatsSketch.heapify(Memory.wrap(skBytes));
+ assertEquals(rebuilt.getMinValue(), union.getMinValue());
+ assertEquals(rebuilt.getMaxValue(), union.getMaxValue());
+ assertEquals(rebuilt.getN(), union.getN());
+
+ // save into a target
+ request.addProperty(QUERY_MERGE_TGT_FIELD, tgtName);
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.OK_200);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
+ skBytes = Base64.getUrlDecoder().decode(responseData.get(QUERY_SKETCH_FIELD).getAsString());
+ rebuilt = KllFloatsSketch.heapify(Memory.wrap(skBytes));
+ assertEquals(rebuilt.getMinValue(), union.getMinValue());
+ assertEquals(rebuilt.getMaxValue(), union.getMaxValue());
+ assertEquals(rebuilt.getN(), union.getN());
+ }
+
+ @Test
+ public void thetaMerge() {
+ final String tgtName = "theta2";
+ final JsonObject response = new JsonObject();
+ final JsonObject request = new JsonObject();
+
+ // add data to multiple sketches, including one passed in serialized
+ final int n = 5;
+ int idx = 0;
+
+ final int k = server_.getSketch("theta0").configK_;
+ Union sk = (Union) server_.getSketch("theta0").sketch_;
+ final Union tgtUnion = Union.builder().setNominalEntries(1 << k).buildUnion();
+ for (int i = 0; i < n; ++i) {
+ sk.update(idx++);
+ }
+ tgtUnion.union(sk.getResult());
+
+ sk = (Union) server_.getSketch("theta1").sketch_;
+ for (int i = 0; i < n; ++i) {
+ sk.update(idx++);
+ }
+ tgtUnion.union(sk.getResult());
+
+ sk = Union.builder().setNominalEntries(1 << k).buildUnion();
+ for (int i = 0; i < n; ++i) {
+ sk.update(idx++);
+ }
+ final String skEncoded = Base64.getUrlEncoder().encodeToString(sk.getResult().toByteArray());
+
+ // we'll compare the result vs a reference serialized sketch
+ tgtUnion.union(sk.getResult());
+ final byte[] tgtBytes = tgtUnion.getResult().toByteArray();
+
+ final JsonArray srcSketches = new JsonArray(3);
+ srcSketches.add("theta0");
+ srcSketches.add("theta1");
+ final JsonObject serializedSketch = new JsonObject();
+ serializedSketch.addProperty(QUERY_FAMILY_FIELD, SKETCH_FAMILY_THETA);
+ serializedSketch.addProperty(QUERY_DATA_FIELD, skEncoded);
+ srcSketches.add(serializedSketch);
+ request.add(QUERY_MERGE_SRC_FIELD, srcSketches);
+
+ // serialized sketch, so set the k value
+ request.addProperty(QUERY_MERGE_K_FIELD, k);
+
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.OK_200);
+ final JsonObject responseData = response.getAsJsonObject(RESPONSE_FIELD).getAsJsonObject();
+ assertTrue(responseData.has(QUERY_SKETCH_FIELD));
+ assertEquals(Base64.getUrlDecoder().decode(responseData.get(QUERY_SKETCH_FIELD).getAsString()), tgtBytes);
+
+ // save into a target
+ request.addProperty(QUERY_MERGE_TGT_FIELD, tgtName);
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.OK_200);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
+ assertEquals(((Union) server_.getSketch(tgtName).sketch_).getResult().toByteArray(), tgtBytes);
+ }
+
+ @Test
+ public void reservoirMerge() {
+ final String tgtName = "rs";
+ final JsonObject response = new JsonObject();
+ final JsonObject request = new JsonObject();
+
+ // add data to a couple sketches that we'll pass in via serialization
+ final int k = server_.getSketch(tgtName).configK_;
+ final int n = (k - 1) / 2;
+ final ReservoirItemsSketch<String> sk1 = ReservoirItemsSketch.newInstance(k);
+ final ReservoirItemsSketch<String> sk2 = ReservoirItemsSketch.newInstance(k);
+ for (int i = 0; i < n; ++i) {
+ sk1.update(Integer.toString(i));
+ sk2.update(Integer.toString(n + i));
+ }
+ final ReservoirItemsUnion<String> union = ReservoirItemsUnion.newInstance(k);
+ union.update(sk1);
+ union.update(sk2);
+ final ReservoirItemsSketch<String> result = union.getResult();
+
+ // add sketches to the request
+ final JsonArray srcSketches = new JsonArray(2);
+
+ final JsonObject serializedSketch1 = new JsonObject();
+ serializedSketch1.addProperty(QUERY_FAMILY_FIELD, SKETCH_FAMILY_RESERVOIR);
+ serializedSketch1.addProperty(QUERY_DATA_FIELD, Base64.getUrlEncoder().encodeToString(sk1.toByteArray(new ArrayOfStringsSerDe())));
+ srcSketches.add(serializedSketch1);
+
+ final JsonObject serializedSketch2 = new JsonObject();
+ serializedSketch2.addProperty(QUERY_FAMILY_FIELD, SKETCH_FAMILY_RESERVOIR);
+ serializedSketch2.addProperty(QUERY_DATA_FIELD, Base64.getUrlEncoder().encodeToString(sk2.toByteArray(new ArrayOfStringsSerDe())));
+ srcSketches.add(serializedSketch2);
+ request.add(QUERY_MERGE_SRC_FIELD, srcSketches);
+
+ // serialized sketch, so set the k value
+ request.addProperty(QUERY_MERGE_K_FIELD, k);
+
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.OK_200);
+ final JsonObject responseData = response.getAsJsonObject(RESPONSE_FIELD).getAsJsonObject();
+ assertTrue(responseData.has(QUERY_SKETCH_FIELD));
+ byte[] skBytes = Base64.getUrlDecoder().decode(responseData.get(QUERY_SKETCH_FIELD).getAsString());
+ ReservoirItemsSketch<String> rebuilt = ReservoirItemsSketch.heapify(Memory.wrap(skBytes), new ArrayOfStringsSerDe());
+ assertEquals(rebuilt.getN(), result.getN());
+ assertEquals(rebuilt.estimateSubsetSum(x -> true).getTotalSketchWeight(),
+ result.estimateSubsetSum(x -> true).getTotalSketchWeight());
+
+ // save into a target
+ request.addProperty(QUERY_MERGE_TGT_FIELD, tgtName);
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.OK_200);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
+ skBytes = Base64.getUrlDecoder().decode(responseData.get(QUERY_SKETCH_FIELD).getAsString());
+ rebuilt = ReservoirItemsSketch.heapify(Memory.wrap(skBytes), new ArrayOfStringsSerDe());
+ assertEquals(rebuilt.getN(), result.getN());
+ assertEquals(rebuilt.estimateSubsetSum(x -> true).getTotalSketchWeight(),
+ result.estimateSubsetSum(x -> true).getTotalSketchWeight());
+ }
+
+ @Test
+ public void varOptMerge() {
+ final String tgtName = "vo";
+ final JsonObject response = new JsonObject();
+ final JsonObject request = new JsonObject();
+
+ // add data to a couple sketches that we'll pass in via serialization
+ final int k = server_.getSketch(tgtName).configK_;
+ final int n = 5 * k;
+ final VarOptItemsSketch<String> sk1 = VarOptItemsSketch.newInstance(k);
+ final VarOptItemsSketch<String> sk2 = VarOptItemsSketch.newInstance(k);
+ final ThreadLocalRandom rand = ThreadLocalRandom.current();
+ for (int i = 0; i < n; ++i) {
+ sk1.update(Integer.toString(i), rand.nextInt(25000));
+ sk2.update(Integer.toString(n + i), rand.nextInt(5000));
+ }
+ final VarOptItemsUnion<String> union = VarOptItemsUnion.newInstance(k);
+ union.update(sk1);
+ union.update(sk2);
+ final VarOptItemsSketch<String> result = union.getResult();
+
+ // add sketches to the request
+ final JsonArray srcSketches = new JsonArray(2);
+
+ final JsonObject serializedSketch1 = new JsonObject();
+ serializedSketch1.addProperty(QUERY_FAMILY_FIELD, SKETCH_FAMILY_VAROPT);
+ serializedSketch1.addProperty(QUERY_DATA_FIELD, Base64.getUrlEncoder().encodeToString(sk1.toByteArray(new ArrayOfStringsSerDe())));
+ srcSketches.add(serializedSketch1);
+
+ final JsonObject serializedSketch2 = new JsonObject();
+ serializedSketch2.addProperty(QUERY_FAMILY_FIELD, SKETCH_FAMILY_VAROPT);
+ serializedSketch2.addProperty(QUERY_DATA_FIELD, Base64.getUrlEncoder().encodeToString(sk2.toByteArray(new ArrayOfStringsSerDe())));
+ srcSketches.add(serializedSketch2);
+ request.add(QUERY_MERGE_SRC_FIELD, srcSketches);
+
+ // serialized sketch, so set the k value
+ request.addProperty(QUERY_MERGE_K_FIELD, k);
+
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.OK_200);
+ final JsonObject responseData = response.getAsJsonObject(RESPONSE_FIELD).getAsJsonObject();
+ assertTrue(responseData.has(QUERY_SKETCH_FIELD));
+ byte[] skBytes = Base64.getUrlDecoder().decode(responseData.get(QUERY_SKETCH_FIELD).getAsString());
+ VarOptItemsSketch<String> rebuilt = VarOptItemsSketch.heapify(Memory.wrap(skBytes), new ArrayOfStringsSerDe());
+ assertEquals(rebuilt.getN(), result.getN());
+ assertEquals(rebuilt.estimateSubsetSum(x -> true).getTotalSketchWeight(),
+ result.estimateSubsetSum(x -> true).getTotalSketchWeight());
+
+ // save into a target
+ request.addProperty(QUERY_MERGE_TGT_FIELD, tgtName);
+ assertEquals(postData(MERGE_PATH, request, response), HttpStatus.OK_200);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
+ skBytes = Base64.getUrlDecoder().decode(responseData.get(QUERY_SKETCH_FIELD).getAsString());
+ rebuilt = VarOptItemsSketch.heapify(Memory.wrap(skBytes), new ArrayOfStringsSerDe());
+ assertEquals(rebuilt.getN(), result.getN());
+ assertEquals(rebuilt.estimateSubsetSum(x -> true).getTotalSketchWeight(),
+ result.estimateSubsetSum(x -> true).getTotalSketchWeight());
+ }
}
diff --git a/src/test/java/org/apache/datasketches/server/ResetHandlerTest.java b/src/test/java/org/apache/datasketches/server/ResetHandlerTest.java
index 0ead4d2..c2dcaff 100644
--- a/src/test/java/org/apache/datasketches/server/ResetHandlerTest.java
+++ b/src/test/java/org/apache/datasketches/server/ResetHandlerTest.java
@@ -75,7 +75,7 @@
// reset, then check sketch is again empty
request.addProperty(QUERY_NAME_FIELD, sketchName);
assertEquals(getData(RESET_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
// get sketch again before testing
sk = (CpcSketch) server_.getSketch(sketchName).sketch_;
@@ -98,7 +98,7 @@
// reset, then check sketch is again empty
request.addProperty(QUERY_NAME_FIELD, sketchName);
assertEquals(getData(RESET_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
// get sketch again before testing
sk = (ItemsSketch<String>) server_.getSketch(sketchName).sketch_;
@@ -120,7 +120,7 @@
// reset, then check sketch is again empty
request.addProperty(QUERY_NAME_FIELD, sketchName);
assertEquals(getData(RESET_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
// get sketch again before testing
sk = (HllSketch) server_.getSketch(sketchName).sketch_;
@@ -141,7 +141,7 @@
// reset, then check sketch is again empty
request.addProperty(QUERY_NAME_FIELD, sketchName);
assertEquals(getData(RESET_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
// get sketch again before testing
sk = (KllFloatsSketch) server_.getSketch(sketchName).sketch_;
@@ -162,7 +162,7 @@
// reset, then check sketch is again empty
request.addProperty(QUERY_NAME_FIELD, sketchName);
assertEquals(getData(RESET_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
// get sketch again before testing
sk = (Union) server_.getSketch(sketchName).sketch_;
@@ -184,7 +184,7 @@
// reset, then check sketch is again empty
request.addProperty(QUERY_NAME_FIELD, sketchName);
assertEquals(getData(RESET_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
// get sketch again before testing
sk = (ReservoirItemsSketch<String>) server_.getSketch(sketchName).sketch_;
@@ -206,7 +206,7 @@
// reset, then check sketch is again empty
request.addProperty(QUERY_NAME_FIELD, sketchName);
assertEquals(getData(RESET_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
// get sketch again before testing
sk = (VarOptItemsSketch<String>) server_.getSketch(sketchName).sketch_;
diff --git a/src/test/java/org/apache/datasketches/server/ServerTestBase.java b/src/test/java/org/apache/datasketches/server/ServerTestBase.java
index e6e41bf..dc27f50 100644
--- a/src/test/java/org/apache/datasketches/server/ServerTestBase.java
+++ b/src/test/java/org/apache/datasketches/server/ServerTestBase.java
@@ -118,17 +118,13 @@
try (final InputStreamReader isr = new InputStreamReader(http.getInputStream())) {
responseData = JsonParser.parseReader(isr);
}
- if (!responseData.isJsonNull()) {
- response.add(RESPONSE_FIELD, responseData);
- }
+ response.add(RESPONSE_FIELD, responseData);
} else if (status == HttpStatus.UNPROCESSABLE_ENTITY_422) {
// read error response and put into a JSON element
try (final InputStreamReader isr = new InputStreamReader(http.getErrorStream())) {
responseData = JsonParser.parseReader(isr);
}
- if (!responseData.isJsonNull()) {
- response.add(ERROR_KEY, responseData);
- }
+ response.add(ERROR_KEY, responseData);
}
} catch (final IOException e) {
fail();
@@ -175,17 +171,13 @@
try (final InputStreamReader isr = new InputStreamReader(http.getInputStream())) {
responseData = JsonParser.parseReader(isr);
}
- if (!responseData.isJsonNull()) {
- response.add(RESPONSE_FIELD, responseData);
- }
+ response.add(RESPONSE_FIELD, responseData);
} else if (status == HttpStatus.UNPROCESSABLE_ENTITY_422) {
// read error response and put into a JSON element
try (final InputStreamReader isr = new InputStreamReader(http.getErrorStream())) {
responseData = JsonParser.parseReader(isr);
}
- if (!responseData.isJsonNull()) {
- response.add(ERROR_KEY, responseData);
- }
+ response.add(ERROR_KEY, responseData);
}
} catch (final IOException e) {
fail();
diff --git a/src/test/java/org/apache/datasketches/server/UpdateHandlerTest.java b/src/test/java/org/apache/datasketches/server/UpdateHandlerTest.java
index 5436bcc..ced786b 100644
--- a/src/test/java/org/apache/datasketches/server/UpdateHandlerTest.java
+++ b/src/test/java/org/apache/datasketches/server/UpdateHandlerTest.java
@@ -74,7 +74,7 @@
data.add(i);
request.add(sketchName, data);
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
request = new JsonObject();
data = new JsonArray();
@@ -82,13 +82,13 @@
data.add(i);
request.add(sketchName, data);
assertEquals(getData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
// single-item update
request = new JsonObject();
request.add(sketchName, new JsonPrimitive(-1));
assertEquals(getData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
final SketchStorage.SketchEntry entry = server_.getSketch(sketchName);
final CpcSketch sk = (CpcSketch) entry.sketch_;
@@ -109,12 +109,12 @@
data.add(i); // not converting to String since should happen upon parsing
request.add(sketchName, data);
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
request = new JsonObject();
request.add(sketchName, new JsonPrimitive(-1));
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
final SketchStorage.SketchEntry entry = server_.getSketch(sketchName);
final CpcSketch sk = (CpcSketch) entry.sketch_;
@@ -136,12 +136,12 @@
data.add(i * 10.0);
request.add(sketchName, data);
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
request = new JsonObject();
request.add(sketchName, new JsonPrimitive(-1));
assertEquals(getData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
final SketchStorage.SketchEntry entry = server_.getSketch(sketchName);
final CpcSketch sk = (CpcSketch) entry.sketch_;
@@ -160,7 +160,7 @@
JsonObject request = new JsonObject();
request.addProperty(sketchName, "item1");
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
// item with weight
request = new JsonObject();
@@ -169,7 +169,7 @@
data.addProperty(QUERY_PAIR_WEIGHT_FIELD, 5);
request.add(sketchName, data);
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
// array of items with and without weights
request = new JsonObject();
@@ -181,7 +181,7 @@
dataArray.add(data);
request.add(sketchName, dataArray);
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
final SketchStorage.SketchEntry entry = server_.getSketch(sketchName);
final org.apache.datasketches.frequencies.ItemsSketch<String> sk = (org.apache.datasketches.frequencies.ItemsSketch<String>) entry.sketch_;
@@ -216,12 +216,12 @@
data.add(i); // not converting to String since should happen upon parsing
request.add(sketchName, data);
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
request = new JsonObject();
request.add(sketchName, new JsonPrimitive(-1));
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
final SketchStorage.SketchEntry entry = server_.getSketch(sketchName);
final HllSketch sk = (HllSketch) entry.sketch_;
@@ -242,7 +242,7 @@
data.add(i);
request.add(sketchName, data);
assertEquals(getData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
request = new JsonObject();
data = new JsonArray();
@@ -250,13 +250,13 @@
data.add(i);
request.add(sketchName, data);
assertEquals(getData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
// single-item update
request = new JsonObject();
request.add(sketchName, new JsonPrimitive(-1));
assertEquals(getData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
final SketchStorage.SketchEntry entry = server_.getSketch(sketchName);
final HllSketch sk = (HllSketch) entry.sketch_;
@@ -277,12 +277,12 @@
data.add(i * 10.0);
request.add(sketchName, data);
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
request = new JsonObject();
request.add(sketchName, new JsonPrimitive(-1));
assertEquals(getData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
final SketchStorage.SketchEntry entry = server_.getSketch(sketchName);
final HllSketch sk = (HllSketch) entry.sketch_;
@@ -306,13 +306,13 @@
data.add(i * 10.0);
request.add(sketchName, data);
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
// single update
request = new JsonObject();
request.add(sketchName, new JsonPrimitive(-1));
assertEquals(getData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
}
final SketchStorage.SketchEntry entry = server_.getSketch(sketchName);
@@ -332,7 +332,7 @@
data.add(i);
request.add(sketchName, data);
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
request = new JsonObject();
data = new JsonArray();
@@ -340,13 +340,13 @@
data.add(i);
request.add(sketchName, data);
assertEquals(getData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
// single-item update
request = new JsonObject();
request.add(sketchName, new JsonPrimitive(-1));
assertEquals(getData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
final SketchStorage.SketchEntry entry = server_.getSketch(sketchName);
final CompactSketch sk = ((Union) entry.sketch_).getResult();
@@ -367,12 +367,12 @@
data.add(i); // not converting to String since should happen upon parsing
request.add(sketchName, data);
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
request = new JsonObject();
request.add(sketchName, new JsonPrimitive(-1));
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
final SketchStorage.SketchEntry entry = server_.getSketch(sketchName);
final CompactSketch sk = ((Union) entry.sketch_).getResult();
@@ -393,12 +393,12 @@
data.add(i * 10.0);
request.add(sketchName, data);
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
request = new JsonObject();
request.add(sketchName, new JsonPrimitive(-1));
assertEquals(getData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
final SketchStorage.SketchEntry entry = server_.getSketch(sketchName);
final CompactSketch sk = ((Union) entry.sketch_).getResult();
@@ -423,13 +423,13 @@
data.add(Integer.toString(i));
request.add(sketchName, data);
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
// single update
request = new JsonObject();
request.add(sketchName, new JsonPrimitive("-1"));
assertEquals(getData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
}
final SketchStorage.SketchEntry entry = server_.getSketch(sketchName);
@@ -447,7 +447,7 @@
JsonObject request = new JsonObject();
request.addProperty(sketchName, "item1");
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
// item with weight
request = new JsonObject();
@@ -456,7 +456,7 @@
data.addProperty(QUERY_PAIR_WEIGHT_FIELD, 5);
request.add(sketchName, data);
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
// array of items with and without weights
request = new JsonObject();
@@ -468,7 +468,7 @@
dataArray.add(data);
request.add(sketchName, dataArray);
assertEquals(postData(UPDATE_PATH, request, response), HttpStatus.OK_200);
- assertEquals(response.size(), 0);
+ assertTrue(response.get(RESPONSE_FIELD).isJsonNull());
final SketchStorage.SketchEntry entry = server_.getSketch(sketchName);
final VarOptItemsSketch<String> sk = (VarOptItemsSketch<String>) entry.sketch_;