summaryrefslogtreecommitdiffstats
path: root/aai-resources
diff options
context:
space:
mode:
authorFiete Ostkamp <Fiete.Ostkamp@telekom.de>2024-10-09 08:24:38 +0200
committerFiete Ostkamp <Fiete.Ostkamp@telekom.de>2024-10-10 08:57:53 +0200
commitc30cae6d1a979e7f6f9cc32b530e14a2aefb9a87 (patch)
treecf0d323e272a5bc114cefe8bc8a09b4b915783e9 /aai-resources
parentfeada673f2e99c3ed5fcdc2a47994e9e4500b2ea (diff)
Add K6 test for writing without relationships
- create test that writes pservers via the LegacyMoxyConsumer (not bulk) Issue-ID: AAI-4013 Change-Id: I0fe4116ebc01ed4f8a5c0807113a08a2424d24ba Signed-off-by: Fiete Ostkamp <Fiete.Ostkamp@telekom.de>
Diffstat (limited to 'aai-resources')
-rw-r--r--aai-resources/src/test/java/org/onap/aai/it/performance/K6ReadTest.java183
-rw-r--r--aai-resources/src/test/java/org/onap/aai/it/performance/K6WriteTest.java (renamed from aai-resources/src/test/java/org/onap/aai/it/performance/K6PerformanceTest.java)58
-rw-r--r--aai-resources/src/test/resources/k6/readWithoutRelations.js (renamed from aai-resources/src/test/resources/k6/test.js)0
-rw-r--r--aai-resources/src/test/resources/k6/writeWithoutRelations.js111
4 files changed, 326 insertions, 26 deletions
diff --git a/aai-resources/src/test/java/org/onap/aai/it/performance/K6ReadTest.java b/aai-resources/src/test/java/org/onap/aai/it/performance/K6ReadTest.java
new file mode 100644
index 0000000..0dee841
--- /dev/null
+++ b/aai-resources/src/test/java/org/onap/aai/it/performance/K6ReadTest.java
@@ -0,0 +1,183 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2024 Deutsche Telekom. All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.aai.it.performance;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.janusgraph.core.JanusGraph;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.dbmap.AAIGraph;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
+import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.testcontainers.containers.output.WaitingConsumer;
+import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.k6.K6Container;
+import org.testcontainers.utility.MountableFile;
+
+import lombok.SneakyThrows;
+
+@Testcontainers
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
+@EnableAutoConfiguration(exclude={CassandraDataAutoConfiguration.class, CassandraAutoConfiguration.class}) // there is no running cassandra instance for the test
+public class K6ReadTest {
+
+ private static final Logger logger = LoggerFactory.getLogger(K6ReadTest.class);
+ private static final long nPservers = 10;
+
+ @LocalServerPort
+ private int port;
+
+ @BeforeEach
+ public void setup() {
+ if (!AAIGraph.isInit()) {
+ AAIGraph.getInstance();
+
+ long startTime = System.currentTimeMillis();
+ logger.info("Creating pserver nodes");
+ loadPerformanceTestData();
+ long endTime = System.currentTimeMillis();
+ logger.info("Created pserver nodes in {} seconds", (endTime - startTime) / 1000);
+ }
+ }
+
+ @AfterAll
+ public static void cleanup() {
+ JanusGraph graph = AAIGraph.getInstance().getGraph();
+ graph.traversal().V().has("aai-node-type", "pserver").drop().iterate();
+ graph.tx().commit();
+ }
+
+ @Test
+ public void readWithoutRelationsTest() throws Exception {
+ int testDuration = 5;
+
+ K6Container container = new K6Container("grafana/k6:0.49.0")
+ .withNetworkMode("host")
+ .withAccessToHost(true)
+ .withTestScript(MountableFile.forClasspathResource("k6/readWithoutRelations.js"))
+ .withScriptVar("API_PORT", String.valueOf(port))
+ .withScriptVar("API_VERSION", "v29")
+ .withScriptVar("DURATION_SECONDS", String.valueOf(testDuration))
+ .withScriptVar("N_PSERVERS", String.valueOf(nPservers))
+ .withCmdOptions("--quiet", "--no-usage-report");
+ container.start();
+
+ WaitingConsumer consumer = new WaitingConsumer();
+ container.followOutput(consumer);
+
+ // Wait for test script results to be collected
+ try {
+ consumer.waitUntil(
+ frame -> {
+ return frame.getUtf8String().contains("iteration_duration");
+ },
+ testDuration + 10,
+ TimeUnit.SECONDS);
+ } catch (Exception e) {
+ logger.error(container.getLogs());
+ }
+
+ logger.debug(container.getLogs());
+ assertThat(container.getLogs(), containsString("✓ status was 200"));
+ assertThat(container.getLogs(), containsString("✓ returned correct number of results"));
+ assertThat(container.getLogs(), containsString("✓ http_req_duration"));
+ assertThat(container.getLogs(), containsString("✓ http_req_failed"));
+ container.stop();
+
+ }
+
+ @Test
+ @Disabled
+ public void writeWithoutRelations() throws Exception {
+ int testDuration = 5;
+
+ K6Container container = new K6Container("grafana/k6:0.49.0")
+ .withNetworkMode("host")
+ .withAccessToHost(true)
+ .withTestScript(MountableFile.forClasspathResource("k6/writeWithoutRelations.js"))
+ .withScriptVar("API_PORT", String.valueOf(port))
+ .withScriptVar("API_VERSION", "v29")
+ .withScriptVar("DURATION_SECONDS", String.valueOf(testDuration))
+ .withScriptVar("N_PSERVERS", String.valueOf(nPservers))
+ .withCmdOptions("--quiet", "--no-usage-report");
+ container.start();
+
+ WaitingConsumer consumer = new WaitingConsumer();
+ container.followOutput(consumer);
+
+ // Wait for test script results to be collected
+ try {
+ consumer.waitUntil(
+ frame -> {
+ return frame.getUtf8String().contains("iteration_duration");
+ },
+ testDuration + 10,
+ TimeUnit.SECONDS);
+ } catch (Exception e) {
+ // log the container stdout in case of failure in the test script
+ logger.error(container.getLogs());
+ }
+
+ String report = container.getLogs().substring(container.getLogs().indexOf("✓ status was 201"));
+ logger.info(report);
+ assertThat(report, containsString("✓ status was 201"));
+ assertThat(report, containsString("✓ http_req_duration"));
+ assertThat(report, containsString("✓ http_req_failed"));
+ container.stop();
+ }
+
+ @SneakyThrows
+ public static void loadPerformanceTestData() {
+ JanusGraph graph = AAIGraph.getInstance().getGraph();
+ GraphTraversalSource g = graph.traversal();
+ long n = nPservers;
+ for (long i = 0; i < n; i++) {
+ createPServer(g, i);
+ }
+ graph.tx().commit();
+ }
+
+ private static void createPServer(GraphTraversalSource g, long i) {
+ String hostname = "hostname" + i;
+ String uri = "/cloud-infrastructure/pservers/pserver/" + hostname;
+ g.addV()
+ .property("aai-node-type", "pserver")
+ .property("hostname", hostname)
+ .property("resource-version", UUID.randomUUID().toString())
+ .property(AAIProperties.AAI_URI, uri)
+ .next();
+ }
+}
diff --git a/aai-resources/src/test/java/org/onap/aai/it/performance/K6PerformanceTest.java b/aai-resources/src/test/java/org/onap/aai/it/performance/K6WriteTest.java
index f7d1cc6..b4a495c 100644
--- a/aai-resources/src/test/java/org/onap/aai/it/performance/K6PerformanceTest.java
+++ b/aai-resources/src/test/java/org/onap/aai/it/performance/K6WriteTest.java
@@ -30,6 +30,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSo
import org.janusgraph.core.JanusGraph;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.onap.aai.ResourcesApp;
import org.onap.aai.db.props.AAIProperties;
@@ -52,9 +53,9 @@ import lombok.SneakyThrows;
@Testcontainers
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@EnableAutoConfiguration(exclude={CassandraDataAutoConfiguration.class, CassandraAutoConfiguration.class}) // there is no running cassandra instance for the test
-public class K6PerformanceTest {
+public class K6WriteTest {
- private static final Logger logger = LoggerFactory.getLogger(ResourcesApp.class.getName());
+ private static final Logger logger = LoggerFactory.getLogger(K6ReadTest.class);
private static final long nPservers = 10;
@LocalServerPort
@@ -81,38 +82,43 @@ public class K6PerformanceTest {
}
@Test
- public void k6StandardTest() throws Exception {
+ @Disabled
+ public void writeWithoutRelations() throws Exception {
int testDuration = 5;
- try (
- K6Container container = new K6Container("grafana/k6:0.49.0")
- .withNetworkMode("host")
- .withAccessToHost(true)
- .withTestScript(MountableFile.forClasspathResource("k6/test.js"))
- .withScriptVar("API_PORT", String.valueOf(port))
- .withScriptVar("API_VERSION", "v29")
- .withScriptVar("DURATION_SECONDS", String.valueOf(testDuration))
- .withScriptVar("N_PSERVERS", String.valueOf(nPservers))
- .withCmdOptions("--quiet", "--no-usage-report");) {
- container.start();
-
- WaitingConsumer consumer = new WaitingConsumer();
- container.followOutput(consumer);
-
- // Wait for test script results to be collected
+ K6Container container = new K6Container("grafana/k6:0.49.0")
+ .withNetworkMode("host")
+ .withAccessToHost(true)
+ .withTestScript(MountableFile.forClasspathResource("k6/writeWithoutRelations.js"))
+ .withScriptVar("API_PORT", String.valueOf(port))
+ .withScriptVar("API_VERSION", "v29")
+ .withScriptVar("DURATION_SECONDS", String.valueOf(testDuration))
+ .withScriptVar("N_PSERVERS", String.valueOf(nPservers))
+ .withCmdOptions("--quiet", "--no-usage-report");
+ container.start();
+
+ WaitingConsumer consumer = new WaitingConsumer();
+ container.followOutput(consumer);
+
+ // Wait for test script results to be collected
+ try {
consumer.waitUntil(
frame -> {
return frame.getUtf8String().contains("iteration_duration");
},
- testDuration + 30,
+ testDuration + 10,
TimeUnit.SECONDS);
-
- logger.debug(container.getLogs());
- assertThat(container.getLogs(), containsString("✓ status was 200"));
- assertThat(container.getLogs(), containsString("✓ returned correct number of results"));
- assertThat(container.getLogs(), containsString("✓ http_req_duration"));
- assertThat(container.getLogs(), containsString("✓ http_req_failed"));
+ } catch (Exception e) {
+ // log the container stdout in case of failure in the test script
+ logger.error(container.getLogs());
}
+
+ String report = container.getLogs().substring(container.getLogs().indexOf("✓ status was 201"));
+ logger.info(report);
+ assertThat(report, containsString("✓ status was 201"));
+ assertThat(report, containsString("✓ http_req_duration"));
+ assertThat(report, containsString("✓ http_req_failed"));
+ container.stop();
}
@SneakyThrows
diff --git a/aai-resources/src/test/resources/k6/test.js b/aai-resources/src/test/resources/k6/readWithoutRelations.js
index 8e55214..8e55214 100644
--- a/aai-resources/src/test/resources/k6/test.js
+++ b/aai-resources/src/test/resources/k6/readWithoutRelations.js
diff --git a/aai-resources/src/test/resources/k6/writeWithoutRelations.js b/aai-resources/src/test/resources/k6/writeWithoutRelations.js
new file mode 100644
index 0000000..bb4b839
--- /dev/null
+++ b/aai-resources/src/test/resources/k6/writeWithoutRelations.js
@@ -0,0 +1,111 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2024 Deutsche Telekom. All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ * ============LICENSE_END=========================================================
+ */
+import http from "k6/http";
+import { check } from "k6";
+import { randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.3.0/index.js';
+
+export const options = {
+ vus: 3,
+ duration: `${__ENV.DURATION_SECONDS}s`,
+ thresholds: {
+ http_req_failed: ["rate<0.01"], // http errors should be less than 1%
+ http_req_duration: [
+ "p(99)<3000",
+ "p(90)<2000",
+ "avg<70",
+ "med<70",
+ "min<1000",
+ ],
+ },
+ insecureSkipTLSVerify: true,
+};
+
+function generatePServer(someInt) {
+ return JSON.stringify({
+ 'hostname': someInt,
+ 'ptnii-equip-name': `example-ptnii-equip-name-val-${someInt}`,
+ 'number-of-cpus': someInt,
+ 'disk-in-gigabytes': someInt,
+ 'ram-in-megabytes': someInt,
+ 'equip-type': `example-equip-type-val-${someInt}`,
+ 'equip-vendor': `example-equip-vendor-val-${someInt}`,
+ 'equip-model': `example-equip-model-val-${someInt}`,
+ 'fqdn': `example-fqdn-val-${someInt}`,
+ 'pserver-selflink': `example-pserver-selflink-val-${someInt}`,
+ 'ipv4-oam-address': `example-ipv4-oam-address-val-${someInt}`,
+ 'serial-number': `example-serial-number-val-${someInt}`,
+ 'ipaddress-v4-loopback-0': `example-ipaddress-v4-loopback0-val-${someInt}`,
+ 'ipaddress-v6-loopback-0': `example-ipaddress-v6-loopback0-val-${someInt}`,
+ 'ipaddress-v4-aim': `example-ipaddress-v4-aim-val-${someInt}`,
+ 'ipaddress-v6-aim': `example-ipaddress-v6-aim-val-${someInt}`,
+ 'ipaddress-v6-oam': `example-ipaddress-v6-oam-val-${someInt}`,
+ 'inv-status': `example-inv-status-val-${someInt}`,
+ 'pserver-id': `example-pserver-id-val-${someInt}`,
+ 'internet-topology': `example-internet-topology-val-${someInt}`,
+ 'in-maint': true,
+ 'pserver-name2': `example-pserver-name2-val-${someInt}`,
+ 'purpose': `example-purpose-val-${someInt}`,
+ 'prov-status': `example-prov-status-val-${someInt}`,
+ 'management-option': `example-management-option-val-${someInt}`,
+ 'host-profile': `example-host-profile-val-${someInt}`
+ });
+}
+
+const baseUrl = `http://localhost:${__ENV.API_PORT}/aai/${__ENV.API_VERSION}`;
+const path = `/cloud-infrastructure/pservers/pserver`;
+const url = baseUrl + path;
+const encodedCredentials = 'QUFJOkFBSQ==';
+const httpOpts = {
+ headers: {
+ Accept: "application/json",
+ Authorization: `Basic ${encodedCredentials}`,
+ "X-FromAppId": "k6",
+ "X-TransactionId": "someTransaction",
+ },
+};
+
+export function setup() {
+ // Perform a warmup with 100 requests
+ for (let i = 0; i < 100; i++) {
+ const someInt = randomIntBetween(10000, 1000000);
+ const payload = generatePServer(someInt);
+ const pserverUrl = url + `/${someInt}`
+ const res = http.put(pserverUrl, payload, httpOpts);
+
+ if (res.status != 201) {
+ console.error(res);
+ }
+ }
+}
+
+export default function () {
+ const someInt = randomIntBetween(10000, 1000000);
+ const pserverUrl = url + `/${someInt}`
+ const payload = generatePServer();
+ const res = http.put(pserverUrl, payload, httpOpts);
+
+ if (res.status != 201) {
+ console.error(res);
+ }
+
+ check(res, {
+ "status was 201": (r) => r.status == 201,
+ });
+}