diff options
author | Fiete Ostkamp <Fiete.Ostkamp@telekom.de> | 2024-06-19 13:06:14 +0200 |
---|---|---|
committer | Fiete Ostkamp <Fiete.Ostkamp@telekom.de> | 2024-06-19 14:17:04 +0200 |
commit | c8520cf5ae8d4f9f5df7064c6a6e8f8c85f0cc89 (patch) | |
tree | 9ab205deec11ebccca81991da7bcd7d3accb4877 | |
parent | ce2dccf65d754332d208fad1afc0ce5fcf9d0c78 (diff) |
Add performance test for resources
- add a K6-based performance test
- exact thresholds are not important for now, it's rather meant to
assist development
Issue-ID: AAI-3892
Change-Id: I1387f97acaa593ae8be84a0782f42274b1b100a7
Signed-off-by: Fiete Ostkamp <Fiete.Ostkamp@telekom.de>
-rw-r--r-- | aai-resources/pom.xml | 29 | ||||
-rw-r--r-- | aai-resources/src/main/resources/application.properties | 10 | ||||
-rw-r--r-- | aai-resources/src/test/java/org/onap/aai/it/performance/K6PerformanceTest.java | 139 | ||||
-rw-r--r-- | aai-resources/src/test/resources/k6/test.js | 66 | ||||
-rw-r--r-- | aai-resources/src/test/resources/logback.xml | 5 |
5 files changed, 243 insertions, 6 deletions
diff --git a/aai-resources/pom.xml b/aai-resources/pom.xml index 8ef378c..d50695d 100644 --- a/aai-resources/pom.xml +++ b/aai-resources/pom.xml @@ -571,6 +571,10 @@ <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </exclusion> + <exclusion> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </exclusion> </exclusions> </dependency> <dependency> @@ -661,13 +665,14 @@ <version>${groovy.version}</version> </dependency> <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-test</artifactId> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-test</artifactId> <scope>test</scope> </dependency> + <!-- Only used for the WebTestClient --> <dependency> <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-test</artifactId> + <artifactId>spring-boot-starter-webflux</artifactId> <scope>test</scope> </dependency> <dependency> @@ -710,6 +715,24 @@ <scope>test</scope> </dependency> <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>testcontainers</artifactId> + <version>1.19.8</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>junit-jupiter</artifactId> + <version>1.19.8</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>k6</artifactId> + <version>1.19.8</version> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.30</version> diff --git a/aai-resources/src/main/resources/application.properties b/aai-resources/src/main/resources/application.properties index cc0c46a..960db1b 100644 --- a/aai-resources/src/main/resources/application.properties +++ b/aai-resources/src/main/resources/application.properties @@ -8,7 +8,7 @@ spring.application.name=aai-resources spring.jersey.type=filter spring.main.allow-bean-definition-overriding=true -spring.sleuth.enabled=true +spring.sleuth.enabled=false spring.zipkin.baseUrl=http://jaeger-collector.istio-system:9411 spring.sleuth.messaging.jms.enabled = false spring.sleuth.trace-id128=true @@ -43,6 +43,7 @@ server.certs.location=${server.local.startpath}/etc/auth/ server.keystore.name=aai_keystore server.truststore.name=aai_keystore server.port=8447 +server.ssl.enabled=false server.ssl.enabled-protocols=TLSv1.1,TLSv1.2 server.ssl.key-store=${server.certs.location}${server.keystore.name} server.ssl.key-store-password=password(OBF:1vn21ugu1saj1v9i1v941sar1ugw1vo0) @@ -60,7 +61,7 @@ jms.bind.address=tcp://localhost:61647 # dmaap.ribbon.listOfServers=localhost:3904 spring.kafka.producer.bootstrap-servers=${BOOTSTRAP_SERVERS} spring.kafka.producer.properties.security.protocol=SASL_PLAINTEXT -spring.kafka.producer.properties.sasl.mechanism=SCRAM-SHA-512 +spring.kafka.producer.properties.sasl.mechanism=SCRAM-SHA-512 spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer spring.kafka.producer.properties.sasl.jaas.config = ${JAAS_CONFIG} @@ -148,3 +149,8 @@ validation.service.node-types=generic-vnf,lag-interface,l-interface,logical-link # List of X-FromAppId regexes seperated by comma to ignore the pre validation for # Note: please don't add any client id here as this is only for testing tools such as robot validation.service.exclusion-regexes= + +BOOTSTRAP_SERVERS=localhost:9092 +JAAS_CONFIG="" +BUNDLECONFIG_DIR=src/main/resources/ +AJSC_HOME=./ 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/K6PerformanceTest.java new file mode 100644 index 0000000..8428cb5 --- /dev/null +++ b/aai-resources/src/test/java/org/onap/aai/it/performance/K6PerformanceTest.java @@ -0,0 +1,139 @@ +/** + * ============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.junit.Assert.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.Test; +import org.onap.aai.ResourcesApp; +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.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) +public class K6PerformanceTest { + + private static final Logger logger = LoggerFactory.getLogger(ResourcesApp.class.getName()); + private static final long nPservers = 10; + + @LocalServerPort + private int port; + + + private boolean initialized = false; + + @BeforeEach + public void setup() { + if (!initialized) { + initialized = true; + 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 k6StandardTest() 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 + consumer.waitUntil( + frame -> { + return frame.getUtf8String().contains("iteration_duration"); + }, + testDuration + 30, + 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")); + } + } + + @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/resources/k6/test.js b/aai-resources/src/test/resources/k6/test.js new file mode 100644 index 0000000..8e55214 --- /dev/null +++ b/aai-resources/src/test/resources/k6/test.js @@ -0,0 +1,66 @@ +/** + * ============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"; + +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<1000", + "med<1000", + "min<1000", + ], + }, + insecureSkipTLSVerify: true, +}; + +export default function () { + const encodedCredentials = 'QUFJOkFBSQ=='; + const options = { + headers: { + Accept: "application/json", + Authorization: `Basic ${encodedCredentials}`, + "X-FromAppId": "k6", + "X-TransactionId": "someTransaction", + }, + }; + const pserverCount = parseInt(`${__ENV.N_PSERVERS}`, 10); + const baseUrl = `http://localhost:${__ENV.API_PORT}/aai/${__ENV.API_VERSION}`; + const url = `/cloud-infrastructure/pservers`; + const res = http.get(baseUrl + url, options); + + if (res.status != 200) { + console.error(res); + } + + const parsedResponse = JSON.parse(res.body); + if (parsedResponse.pserver.length != pserverCount) { + console.error(`Expected ${pserverCount} results, got ${parsedResponse.pserver.length}`); + } + check(res, { + "status was 200": (r) => r.status == 200, + "returned correct number of results": () => parsedResponse.pserver.length == pserverCount, + }); +} diff --git a/aai-resources/src/test/resources/logback.xml b/aai-resources/src/test/resources/logback.xml index 7d35439..a550336 100644 --- a/aai-resources/src/test/resources/logback.xml +++ b/aai-resources/src/test/resources/logback.xml @@ -142,7 +142,7 @@ <pattern>${transLogPattern}</pattern> </encoder> </appender> - + <appender name="asynctranslog" class="ch.qos.logback.classic.AsyncAppender"> <queueSize>${queueSize}</queueSize> <includeCallerData>true</includeCallerData> @@ -266,6 +266,9 @@ <appender-ref ref="asyncMETRIC" /> </logger> + <logger name="org.testcontainers" level="INFO"/> + <logger name="com.github.dockerjava.zerodep.shaded.org.apache.hc.client5.http.wire" level="OFF"/> + <root level="DEBUG"> <appender-ref ref="external" /> <appender-ref ref="STDOUT" /> |