add unit tests of basic server config
diff --git a/pom.xml b/pom.xml
index 0f066bc..720cf15 100644
--- a/pom.xml
+++ b/pom.xml
@@ -65,6 +65,13 @@
<version>9.4.31.v20200723</version>
</dependency>
+ <!-- Annotation -->
+ <dependency>
+ <groupId>org.checkerframework</groupId>
+ <artifactId>checker-qual</artifactId>
+ <version>3.10.0</version>
+ </dependency>
+
<!--Testing-->
<dependency>
<groupId>org.testng</groupId>
diff --git a/src/main/java/org/apache/datasketches/server/SketchConstants.java b/src/main/java/org/apache/datasketches/server/SketchConstants.java
index 6ef32c8..742dfc9 100644
--- a/src/main/java/org/apache/datasketches/server/SketchConstants.java
+++ b/src/main/java/org/apache/datasketches/server/SketchConstants.java
@@ -76,6 +76,7 @@
public static final String RESPONSE_RESULT_MASS = "mass";
public static final String RESPONSE_QUANTILE_LIST = "estimatedQuantiles";
public static final String RESPONSE_RESULT_QUANTILE = "quantile";
+ public static final String RESPONSE_SKETCH_COUNT_FIELD = "count";
// JSON Config Field Names
public static final String CONFIG_PORT_FIELD = "port";
diff --git a/src/main/java/org/apache/datasketches/server/SketchServer.java b/src/main/java/org/apache/datasketches/server/SketchServer.java
index 4fefb9a..b70dca6 100644
--- a/src/main/java/org/apache/datasketches/server/SketchServer.java
+++ b/src/main/java/org/apache/datasketches/server/SketchServer.java
@@ -21,6 +21,7 @@
import java.io.IOException;
+import org.checkerframework.checker.nullness.qual.NonNull;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ContextHandler;
@@ -43,7 +44,7 @@
* @param configFile Path to a configuration file following the <tt>SketchServerConfig</tt> format
* @throws IOException on parse errors
*/
- public SketchServer(final String configFile) throws IOException {
+ public SketchServer(@NonNull final String configFile) throws IOException {
config = new SketchServerConfig(configFile);
}
diff --git a/src/main/java/org/apache/datasketches/server/SketchServerConfig.java b/src/main/java/org/apache/datasketches/server/SketchServerConfig.java
index 31a2daf..447e36e 100644
--- a/src/main/java/org/apache/datasketches/server/SketchServerConfig.java
+++ b/src/main/java/org/apache/datasketches/server/SketchServerConfig.java
@@ -24,6 +24,7 @@
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
+import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
@@ -36,6 +37,8 @@
import static org.apache.datasketches.server.SketchConstants.*;
+import org.checkerframework.checker.nullness.qual.NonNull;
+
/**
* A class to hold the server configuration, along with a supporting subclass and file-parsing methods.
*
@@ -54,25 +57,16 @@
this.family = family;
this.type = type;
}
-
- SketchInfo(final String name, final int k, final String family) {
- this(name, k, family, null);
- }
-
}
private int port = DEFAULT_PORT;
private ArrayList<SketchInfo> sketchList;
- SketchServerConfig(final String configFile) throws IOException {
+ SketchServerConfig(@NonNull final String configFile) throws IOException {
final JsonElement config = readJsonFromFile(configFile);
parseConfig(config);
}
- SketchServerConfig(final JsonElement config) throws IOException {
- parseConfig(config);
- }
-
int getPort() {
return port;
}
@@ -83,16 +77,10 @@
// output should have a list with full info per sketch, even if input allows a
// more condensed format
- private static JsonElement readJsonFromFile(final String configFile) {
- JsonElement config = null;
-
- try (final Reader reader = Files.newBufferedReader(Paths.get(configFile))) {
- config = JsonParser.parseReader(reader);
- } catch (final IOException e) {
- e.printStackTrace();
- }
-
- return config;
+ private static JsonElement readJsonFromFile(final String configFile) throws IOException {
+ final Path configPath = Paths.get(configFile);
+ final Reader reader = Files.newBufferedReader(configPath);
+ return JsonParser.parseReader(reader);
}
private void parseConfig(final JsonElement config) throws IOException {
diff --git a/src/main/java/org/apache/datasketches/server/SketchStorage.java b/src/main/java/org/apache/datasketches/server/SketchStorage.java
index c6c8c89..b6af0c5 100644
--- a/src/main/java/org/apache/datasketches/server/SketchStorage.java
+++ b/src/main/java/org/apache/datasketches/server/SketchStorage.java
@@ -31,6 +31,8 @@
import org.apache.datasketches.sampling.ReservoirItemsSketch;
import org.apache.datasketches.sampling.VarOptItemsSketch;
import org.apache.datasketches.theta.SetOperationBuilder;
+import org.checkerframework.checker.nullness.qual.NonNull;
+
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
@@ -43,7 +45,8 @@
* order to ensure that data is presented in a consistent way.
*/
public class SketchStorage {
- private static final String SKETCH_COUNT_NAME = "count";
+ // the set of SketchEntries held by this object
+ HashMap<String, SketchEntry> sketchMap;
/**
* Returns true if the sketch family is for distinct counting.
@@ -81,12 +84,8 @@
}
}
- HashMap<String, SketchEntry> sketchMap;
-
- SketchStorage(final List<SketchServerConfig.SketchInfo> sketchList) {
- if (sketchList != null) {
- createSketches(sketchList);
- }
+ SketchStorage(@NonNull final List<SketchServerConfig.SketchInfo> sketchList) {
+ createSketches(sketchList);
}
JsonObject listSketches() {
@@ -125,7 +124,7 @@
sketchList.add(item);
}
- summary.addProperty(SKETCH_COUNT_NAME, sketchMap.size());
+ summary.addProperty(RESPONSE_SKETCH_COUNT_FIELD, sketchMap.size());
summary.add(SketchConstants.CONFIG_SKETCHES_PREFIX, sketchList); // bare prefix, sketches fully qualified
return summary;
diff --git a/src/test/java/org/apache/datasketches/server/SketchServerConfigTest.java b/src/test/java/org/apache/datasketches/server/SketchServerConfigTest.java
new file mode 100644
index 0000000..23dac17
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/server/SketchServerConfigTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.DEFAULT_PORT;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import org.testng.annotations.Test;
+
+public class SketchServerConfigTest {
+
+ @Test
+ public void invalidFile() {
+ try {
+ new SketchServerConfig("fileDoesNotExist");
+ fail();
+ } catch (final IOException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void parseTestConfig() {
+ final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ final SketchServerConfig serverConf =
+ new SketchServerConfig(Objects.requireNonNull(classLoader.getResource("test_config.json")).getFile());
+ assertEquals(serverConf.getSketchList().size(), 15);
+ assertEquals(serverConf.getPort(), 8080);
+ } catch (final IOException e) {
+ fail();
+ }
+ }
+
+ @Test
+ public void parseJsonArrayConfig() {
+ final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ final SketchServerConfig serverConf =
+ new SketchServerConfig(Objects.requireNonNull(classLoader.getResource("array_config.json")).getFile());
+ assertEquals(serverConf.getSketchList().size(), 2);
+ assertEquals(serverConf.getPort(), DEFAULT_PORT);
+ } catch (final IOException e) {
+ fail();
+ }
+ }
+}
diff --git a/src/test/java/org/apache/datasketches/server/SketchServerTest.java b/src/test/java/org/apache/datasketches/server/SketchServerTest.java
new file mode 100644
index 0000000..757c855
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/server/SketchServerTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import org.testng.annotations.Test;
+
+public class SketchServerTest {
+ @Test
+ public void createServer() {
+ final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ SketchServer server = null;
+ try {
+ server = new SketchServer(Objects.requireNonNull(classLoader.getResource("test_config.json")).getFile());
+ } catch (final IOException e) {
+ fail();
+ }
+
+ // check that port and URI are invalid before starting the server
+ assertNotNull(server);
+ assertNull(server.getURI());
+ assertEquals(server.getPort(), -1);
+ try {
+ server.start();
+ } catch (final Exception e) {
+ fail();
+ }
+
+ assertEquals(server.getPort(), 8080);
+ // initial testing suggests it's just using the host's IP address so just checking that the port
+ // is working correctly
+ assertTrue(server.getURI().endsWith(":" + server.getPort() + "/"));
+ }
+}
diff --git a/src/test/java/org/apache/datasketches/server/SketchStorageTest.java b/src/test/java/org/apache/datasketches/server/SketchStorageTest.java
new file mode 100644
index 0000000..39076b2
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/server/SketchStorageTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.RESPONSE_SKETCH_COUNT_FIELD;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import org.apache.datasketches.Family;
+import org.apache.datasketches.cpc.CpcSketch;
+import org.apache.datasketches.hll.HllSketch;
+import org.testng.annotations.Test;
+
+
+import com.google.gson.JsonObject;
+
+public class SketchStorageTest {
+
+ @Test
+ public void invalidSketchEntry() {
+ try {
+ new SketchStorage.SketchEntry(Family.CPC, null, new CpcSketch(12), 12);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ new SketchStorage.SketchEntry(Family.HLL, new HllSketch(10), 10);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void loadSketches() {
+ final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ SketchServerConfig serverConfig = null;
+ try {
+ serverConfig = new SketchServerConfig(Objects.requireNonNull(classLoader.getResource("test_config.json")).getFile());
+ } catch (final IOException e) {
+ fail();
+ }
+ assertNotNull(serverConfig);
+
+ final SketchStorage storage = new SketchStorage(serverConfig.getSketchList());
+ final JsonObject sketches = storage.listSketches();
+ assertTrue(sketches.has(RESPONSE_SKETCH_COUNT_FIELD));
+ assertEquals(sketches.get(RESPONSE_SKETCH_COUNT_FIELD).getAsInt(), 15);
+ assertTrue(storage.contains("cpcOfNumbers"));
+ }
+}
diff --git a/src/test/resources/array_config.json b/src/test/resources/array_config.json
new file mode 100644
index 0000000..7c718ee
--- /dev/null
+++ b/src/test/resources/array_config.json
@@ -0,0 +1,12 @@
+[
+ { "name": "cpcOfNumbers",
+ "k": 12,
+ "type": "long",
+ "family": "cpc"
+ },
+ { "name": "cpcOfStrings",
+ "k": 14,
+ "type": "string",
+ "family": "cpc"
+ }
+]
\ No newline at end of file
diff --git a/src/test/resources/test_config.json b/src/test/resources/test_config.json
new file mode 100644
index 0000000..172086e
--- /dev/null
+++ b/src/test/resources/test_config.json
@@ -0,0 +1,56 @@
+{
+ "port": 8080,
+ "sketches_A": [
+ { "name": "cpcOfNumbers",
+ "k": 12,
+ "type": "long",
+ "family": "cpc"
+ },
+ { "name": "cpcOfStrings",
+ "k": 14,
+ "type": "string",
+ "family": "cpc"
+ }
+ ],
+ "set1": {
+ "family": "hll",
+ "type": "string",
+ "k": 14,
+ "names": [
+ "hll1",
+ "hll2",
+ "hll3",
+ "hll4"
+ ]
+ },
+ "set2": {
+ "k": 12,
+ "family": "theta",
+ "type": "int",
+ "names": [
+ "theta0",
+ "theta1",
+ "theta2",
+ "theta3",
+ "theta4"
+ ]
+ },
+ "sketches_B": [
+ { "name": "duration",
+ "k": "160",
+ "family": "kll"
+ },
+ { "name": "topItems",
+ "k": "128",
+ "family": "frequency"
+ },
+ { "name": "rs",
+ "k": "20",
+ "family": "reservoir"
+ },
+ { "name": "vo",
+ "k": "20",
+ "family": "varopt"
+ }
+ ]
+}