From 37efd1f95a9ae980bf9dc2124fdab364b12d7293 Mon Sep 17 00:00:00 2001 From: kezhenxu94 Date: Sun, 14 Jul 2019 23:25:41 +0800 Subject: [PATCH] Add e2e cluster tests (#3016) * Add e2e cluster tests --- Jenkinsfile-E2E | 15 +- apm-dist/bin/oapServiceNoInit.sh | 2 +- .../apache/skywalking/e2e/AbstractQuery.java | 14 +- .../skywalking/e2e/SimpleQueryClient.java | 4 + .../skywalking/e2e/metrics/MetricsQuery.java | 19 + .../e2e/service/ServiceMatcher.java | 14 +- .../e2e/service/ServicesMatcher.java | 24 +- .../org/apache/skywalking/e2e/topo/Call.java | 10 + .../skywalking/e2e/topo/CallMatcher.java | 10 + .../org/apache/skywalking/e2e/topo/Node.java | 10 + .../skywalking/e2e/topo/NodeMatcher.java | 10 + .../skywalking/e2e/topo/TopoMatcher.java | 46 ++- .../org/apache/skywalking/e2e/trace/Span.java | 44 +++ .../skywalking/e2e/trace/SpanMatcher.java | 120 ++++++ .../org/apache/skywalking/e2e/trace/Tag.java | 43 +++ .../apache/skywalking/e2e/trace/Trace.java | 6 + .../skywalking/e2e/trace/TraceMatcher.java | 36 ++ .../skywalking/e2e/trace/TracesData.java | 32 +- .../skywalking/e2e/trace/TracesMatcher.java | 29 ++ .../skywalking/e2e/trace/TracesQuery.java | 5 + test/e2e/e2e-cluster/consumer/pom.xml | 56 +++ .../e2e/cluster/Service1Application.java | 32 ++ .../e2e/cluster/TestController.java | 50 +++ .../apache/skywalking/e2e/cluster/User.java | 47 +++ .../src/main/resources/application.yml | 22 ++ test/e2e/e2e-cluster/pom.xml | 38 ++ test/e2e/e2e-cluster/provider/pom.xml | 69 ++++ .../e2e/cluster/Service0Application.java | 34 ++ .../e2e/cluster/TestController.java | 48 +++ .../apache/skywalking/e2e/cluster/User.java | 56 +++ .../skywalking/e2e/cluster/UserRepo.java | 27 ++ .../src/main/resources/application.yml | 35 ++ test/e2e/e2e-cluster/test-runner/pom.xml | 202 ++++++++++ .../test-runner/src/docker/clusterize.awk | 92 +++++ .../src/docker/rc.d/rc0-prepare.sh | 32 ++ .../src/docker/rc.d/rc1-startup.sh | 73 ++++ .../e2e/ClusterVerificationITCase.java | 348 ++++++++++++++++++ ...2e.ClusterVerificationITCase.endpoints.yml | 25 ++ ...2e.ClusterVerificationITCase.instances.yml | 34 ++ ...e2e.ClusterVerificationITCase.services.yml | 28 ++ ...ing.e2e.ClusterVerificationITCase.topo.yml | 39 ++ ...g.e2e.ClusterVerificationITCase.traces.yml | 25 ++ test/e2e/e2e-single-service/pom.xml | 2 +- .../e2e/SampleVerificationITCase.java | 97 +++-- test/e2e/pom.xml | 21 ++ 45 files changed, 1934 insertions(+), 91 deletions(-) create mode 100644 test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/Span.java create mode 100644 test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/SpanMatcher.java create mode 100644 test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/Tag.java create mode 100644 test/e2e/e2e-cluster/consumer/pom.xml create mode 100644 test/e2e/e2e-cluster/consumer/src/main/java/org/apache/skywalking/e2e/cluster/Service1Application.java create mode 100644 test/e2e/e2e-cluster/consumer/src/main/java/org/apache/skywalking/e2e/cluster/TestController.java create mode 100644 test/e2e/e2e-cluster/consumer/src/main/java/org/apache/skywalking/e2e/cluster/User.java create mode 100644 test/e2e/e2e-cluster/consumer/src/main/resources/application.yml create mode 100644 test/e2e/e2e-cluster/pom.xml create mode 100644 test/e2e/e2e-cluster/provider/pom.xml create mode 100644 test/e2e/e2e-cluster/provider/src/main/java/org/apache/skywalking/e2e/cluster/Service0Application.java create mode 100644 test/e2e/e2e-cluster/provider/src/main/java/org/apache/skywalking/e2e/cluster/TestController.java create mode 100644 test/e2e/e2e-cluster/provider/src/main/java/org/apache/skywalking/e2e/cluster/User.java create mode 100644 test/e2e/e2e-cluster/provider/src/main/java/org/apache/skywalking/e2e/cluster/UserRepo.java create mode 100644 test/e2e/e2e-cluster/provider/src/main/resources/application.yml create mode 100644 test/e2e/e2e-cluster/test-runner/pom.xml create mode 100644 test/e2e/e2e-cluster/test-runner/src/docker/clusterize.awk create mode 100755 test/e2e/e2e-cluster/test-runner/src/docker/rc.d/rc0-prepare.sh create mode 100755 test/e2e/e2e-cluster/test-runner/src/docker/rc.d/rc1-startup.sh create mode 100644 test/e2e/e2e-cluster/test-runner/src/test/java/org/apache/skywalking/e2e/ClusterVerificationITCase.java create mode 100644 test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.endpoints.yml create mode 100644 test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.instances.yml create mode 100644 test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.services.yml create mode 100644 test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.topo.yml create mode 100644 test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.traces.yml diff --git a/Jenkinsfile-E2E b/Jenkinsfile-E2E index d43016eed4..2845776afd 100644 --- a/Jenkinsfile-E2E +++ b/Jenkinsfile-E2E @@ -42,8 +42,18 @@ pipeline { } stage('Run End-to-End Tests') { - steps { - sh './mvnw -Dbuild.id=${BUILD_ID} -f test/e2e/pom.xml clean verify' + parallel { + stage('Run Single Node Tests') { + steps { + sh './mvnw -DskipSurefire=false -Dbuild.id=${BUILD_ID} -f test/e2e/pom.xml -pl e2e-single-service -am verify' + } + } + + stage('Run Cluster Tests (ES/ZK)') { + steps { + sh './mvnw -Dbuild.id=${BUILD_ID} -f test/e2e/pom.xml -pl e2e-cluster/test-runner -am verify' + } + } } } } @@ -54,6 +64,7 @@ pipeline { // we need to clean up when there are containers started by the e2e tests sh 'docker ps' sh 'docker ps | grep -e "skywalking-e2e-container-${BUILD_ID}" | awk \'{print $1}\' | xargs --no-run-if-empty docker stop' + sh 'docker ps | grep -e "skywalking-e2e-container-${BUILD_ID}" | awk \'{print $1}\' | xargs --no-run-if-empty docker rm' deleteDir() } } diff --git a/apm-dist/bin/oapServiceNoInit.sh b/apm-dist/bin/oapServiceNoInit.sh index c522e7b72f..5b80f72c3f 100644 --- a/apm-dist/bin/oapServiceNoInit.sh +++ b/apm-dist/bin/oapServiceNoInit.sh @@ -20,7 +20,7 @@ PRG="$0" PRGDIR=`dirname "$PRG"` [ -z "$OAP_HOME" ] && OAP_HOME=`cd "$PRGDIR/.." >/dev/null; pwd` -OAP_LOG_DIR="${OAP_HOME}/logs" +OAP_LOG_DIR=${OAP_LOG_DIR:-"${OAP_HOME}/logs"} JAVA_OPTS=" -Xms256M -Xmx512M" if [ ! -d "${OAP_HOME}/logs" ]; then diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/AbstractQuery.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/AbstractQuery.java index 3bb8e47703..2b38b9e2ea 100644 --- a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/AbstractQuery.java +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/AbstractQuery.java @@ -38,8 +38,8 @@ public abstract class AbstractQuery> { return start; } return "SECOND".equals(step()) - ? LocalDateTime.now(ZoneOffset.UTC).minusMinutes(5).format(TIME_FORMATTER) - : LocalDateTime.now(ZoneOffset.UTC).minusMinutes(5).format(MINUTE_TIME_FORMATTER); + ? LocalDateTime.now(ZoneOffset.UTC).minusMinutes(15).format(TIME_FORMATTER) + : LocalDateTime.now(ZoneOffset.UTC).minusMinutes(15).format(MINUTE_TIME_FORMATTER); } public T start(String start) { @@ -87,4 +87,14 @@ public abstract class AbstractQuery> { this.step = step; return (T) this; } + + public T stepByMinute() { + this.step = "MINUTE"; + return (T) this; + } + + public T stepBySecond() { + this.step = "SECOND"; + return (T) this; + } } diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/SimpleQueryClient.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/SimpleQueryClient.java index 1a12c79acb..1cff8984ec 100644 --- a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/SimpleQueryClient.java +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/SimpleQueryClient.java @@ -57,6 +57,10 @@ public class SimpleQueryClient { private final String endpointUrl; + public SimpleQueryClient(String host, String port) { + this("http://" + host + ":" + port + "/graphql"); + } + public SimpleQueryClient(String endpointUrl) { this.endpointUrl = endpointUrl; } diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/metrics/MetricsQuery.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/metrics/MetricsQuery.java index edcbce1d16..5256c8c5de 100644 --- a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/metrics/MetricsQuery.java +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/metrics/MetricsQuery.java @@ -29,16 +29,35 @@ public class MetricsQuery extends AbstractQuery { public static String SERVICE_P90 = "service_p90"; public static String SERVICE_P75 = "service_p75"; public static String SERVICE_P50 = "service_p50"; + public static String[] ALL_SERVICE_METRICS = { + SERVICE_P99, + SERVICE_P95, + SERVICE_P90, + SERVICE_P75, + SERVICE_P50 + }; public static String ENDPOINT_P99 = "endpoint_p99"; public static String ENDPOINT_P95 = "endpoint_p95"; public static String ENDPOINT_P90 = "endpoint_p90"; public static String ENDPOINT_P75 = "endpoint_p75"; public static String ENDPOINT_P50 = "endpoint_p50"; + public static String[] ALL_ENDPOINT_METRICS = { + ENDPOINT_P99, + ENDPOINT_P95, + ENDPOINT_P90, + ENDPOINT_P75, + ENDPOINT_P50 + }; public static String SERVICE_INSTANCE_RESP_TIME = "service_instance_resp_time"; public static String SERVICE_INSTANCE_CPM = "service_instance_cpm"; public static String SERVICE_INSTANCE_SLA = "service_instance_sla"; + public static String[] ALL_INSTANCE_METRICS = { + SERVICE_INSTANCE_RESP_TIME, + SERVICE_INSTANCE_CPM, + SERVICE_INSTANCE_SLA + }; private String id; private String metricsName; diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/service/ServiceMatcher.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/service/ServiceMatcher.java index 00fcdc65e5..8aec4785a1 100644 --- a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/service/ServiceMatcher.java +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/service/ServiceMatcher.java @@ -44,15 +44,15 @@ public class ServiceMatcher extends AbstractMatcher { } private void verifyKey(Service service) { - final String expected = this.getKey(); + final String expected = getKey(); final String actual = service.getKey(); doVerify(expected, actual); } private void verifyLabel(Service service) { - final String expected = this.getLabel(); - final String actual = String.valueOf(service.getLabel()); + final String expected = getLabel(); + final String actual = service.getLabel(); doVerify(expected, actual); } @@ -72,4 +72,12 @@ public class ServiceMatcher extends AbstractMatcher { public void setLabel(String label) { this.label = label; } + + @Override + public String toString() { + return "ServiceMatcher{" + + "key='" + key + '\'' + + ", label='" + label + '\'' + + '}'; + } } diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/service/ServicesMatcher.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/service/ServicesMatcher.java index 8b33d7f1f2..54dccfee2e 100644 --- a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/service/ServicesMatcher.java +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/service/ServicesMatcher.java @@ -22,6 +22,7 @@ import java.util.LinkedList; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; /** * @author kezhenxu94 @@ -44,10 +45,25 @@ public class ServicesMatcher { public void verify(final List services) { assertThat(services).hasSameSizeAs(this.getServices()); - int size = this.getServices().size(); - - for (int i = 0; i < size; i++) { - this.getServices().get(i).verify(services.get(i)); + for (int i = 0; i < getServices().size(); i++) { + boolean matched = false; + for (Service service : services) { + try { + this.getServices().get(i).verify(service); + matched = true; + } catch (Throwable ignored) { + } + } + if (!matched) { + fail("Expected: %s\nActual: %s", getServices(), services); + } } } + + @Override + public String toString() { + return "ServicesMatcher{" + + "services=" + services + + '}'; + } } diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/Call.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/Call.java index ef39714956..e2104d8a82 100644 --- a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/Call.java +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/Call.java @@ -64,4 +64,14 @@ public class Call { this.target = target; return this; } + + @Override + public String toString() { + return "Call{" + + "id='" + id + '\'' + + ", source='" + source + '\'' + + ", detectPoints=" + detectPoints + + ", target='" + target + '\'' + + '}'; + } } diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/CallMatcher.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/CallMatcher.java index e69b0eb6a2..1b73e90035 100644 --- a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/CallMatcher.java +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/CallMatcher.java @@ -101,4 +101,14 @@ public class CallMatcher extends AbstractMatcher { public void setTarget(String target) { this.target = target; } + + @Override + public String toString() { + return "CallMatcher{" + + "id='" + id + '\'' + + ", source='" + source + '\'' + + ", detectPoints=" + detectPoints + + ", target='" + target + '\'' + + '}'; + } } diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/Node.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/Node.java index bb796afd8f..413894a3df 100644 --- a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/Node.java +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/Node.java @@ -62,4 +62,14 @@ public class Node { isReal = real; return this; } + + @Override + public String toString() { + return "Node{" + + "id='" + id + '\'' + + ", name='" + name + '\'' + + ", type='" + type + '\'' + + ", isReal='" + isReal + '\'' + + '}'; + } } diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/NodeMatcher.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/NodeMatcher.java index b4f264bf3e..89cc07e8e5 100644 --- a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/NodeMatcher.java +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/NodeMatcher.java @@ -93,4 +93,14 @@ public class NodeMatcher extends AbstractMatcher { public void setIsReal(String isReal) { this.isReal = isReal; } + + @Override + public String toString() { + return "NodeMatcher{" + + "id='" + id + '\'' + + ", name='" + name + '\'' + + ", type='" + type + '\'' + + ", isReal='" + isReal + '\'' + + '}'; + } } diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/TopoMatcher.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/TopoMatcher.java index aa64b04c0e..9d7ec35e43 100644 --- a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/TopoMatcher.java +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/topo/TopoMatcher.java @@ -23,7 +23,7 @@ import org.apache.skywalking.e2e.verification.AbstractMatcher; import java.util.List; import java.util.Objects; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; /** * A simple matcher to verify the given {@code Service} is expected @@ -47,22 +47,34 @@ public class TopoMatcher extends AbstractMatcher { } private void verifyNodes(TopoData topoData) { - assertThat(topoData.getNodes()).hasSameSizeAs(getNodes()); - - int size = getNodes().size(); - - for (int i = 0; i < size; i++) { - getNodes().get(i).verify(topoData.getNodes().get(i)); + for (int i = 0; i < getNodes().size(); i++) { + boolean matched = false; + for (int j = 0; j < topoData.getNodes().size(); j++) { + try { + getNodes().get(i).verify(topoData.getNodes().get(j)); + matched = true; + } catch (Throwable ignored) { + } + } + if (!matched) { + fail("Expected: %s\nActual: %s", getNodes(), topoData.getNodes()); + } } } private void verifyCalls(TopoData topoData) { - assertThat(topoData.getCalls()).hasSameSizeAs(getCalls()); - - int size = getCalls().size(); - - for (int i = 0; i < size; i++) { - getCalls().get(i).verify(topoData.getCalls().get(i)); + for (int i = 0; i < getCalls().size(); i++) { + boolean matched = false; + for (int j = 0; j < topoData.getCalls().size(); j++) { + try { + getCalls().get(i).verify(topoData.getCalls().get(j)); + matched = true; + } catch (Throwable ignored) { + } + } + if (!matched) { + fail("Expected: %s\nActual: %s", getCalls(), topoData.getCalls()); + } } } @@ -81,4 +93,12 @@ public class TopoMatcher extends AbstractMatcher { public void setCalls(List calls) { this.calls = calls; } + + @Override + public String toString() { + return "TopoMatcher{" + + "nodes=" + nodes + + ", calls=" + calls + + '}'; + } } diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/Span.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/Span.java new file mode 100644 index 0000000000..98ebe66a8a --- /dev/null +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/Span.java @@ -0,0 +1,44 @@ +/* + * 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.skywalking.e2e.trace; + +import lombok.Data; + +import java.util.List; + +/** + * @author kezhenxu94 + */ +@Data +public class Span { + private String traceId; + private String segmentId; + private int spanId; + private int parentSpanId; + private String serviceCode; + private long startTime; + private long endTime; + private String endpointName; + private String type; + private String peer; + private String component; + private boolean isError; + private String layer; + private List tags; +} diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/SpanMatcher.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/SpanMatcher.java new file mode 100644 index 0000000000..09491f25f7 --- /dev/null +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/SpanMatcher.java @@ -0,0 +1,120 @@ +/* + * 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.skywalking.e2e.trace; + +import com.google.common.base.Strings; +import lombok.Data; +import lombok.ToString; +import org.apache.skywalking.e2e.verification.AbstractMatcher; + +import java.util.List; +import java.util.Objects; + +/** + * @author kezhenxu94 + */ +@Data +@ToString(callSuper = true) +public class SpanMatcher extends AbstractMatcher { + private String traceId; + private String segmentId; + private String spanId; + private String parentSpanId; + private String serviceCode; + private String startTime; + private String endTime; + private String endpointName; + private String type; + private String peer; + private String component; + private String isError; + private String layer; + private List tags; + + @Override + public void verify(final Span span) { + if (Objects.nonNull(traceId)) { + String expected = this.getTraceId(); + String actual = span.getTraceId(); + doVerify(expected, actual); + } + if (Objects.nonNull(segmentId)) { + String expected = this.getSegmentId(); + String actual = span.getSegmentId(); + doVerify(expected, actual); + } + if (Objects.nonNull(spanId)) { + String expected = String.valueOf(this.getSpanId()); + String actual = String.valueOf(span.getSpanId()); + doVerify(expected, actual); + } + if (Objects.nonNull(parentSpanId)) { + String expected = String.valueOf(this.getParentSpanId()); + String actual = String.valueOf(span.getParentSpanId()); + doVerify(expected, actual); + } + if (Objects.nonNull(serviceCode)) { + String expected = this.getServiceCode(); + String actual = span.getServiceCode(); + doVerify(expected, actual); + } + if (Objects.nonNull(startTime)) { + String expected = String.valueOf(this.getStartTime()); + String actual = String.valueOf(span.getStartTime()); + doVerify(expected, actual); + } + if (Objects.nonNull(endTime)) { + String expected = String.valueOf(this.getEndTime()); + String actual = String.valueOf(span.getEndTime()); + doVerify(expected, actual); + } + if (Objects.nonNull(endpointName)) { + String expected = this.getEndpointName(); + String actual = span.getEndpointName(); + doVerify(expected, actual); + } + if (Objects.nonNull(type)) { + String expected = this.getType(); + String actual = span.getType(); + doVerify(expected, actual); + } + if (Objects.nonNull(peer)) { + String expected = this.getPeer(); + String actual = span.getPeer(); + doVerify(expected, actual); + } + if (Objects.nonNull(component)) { + String expected = this.getComponent(); + String actual = span.getComponent(); + doVerify(expected, actual); + } + if (Objects.nonNull(isError)) { + String expected = Strings.nullToEmpty(String.valueOf(this.getIsError())); + String actual = Strings.nullToEmpty(String.valueOf(span.isError())); + doVerify(expected, actual); + } + if (Objects.nonNull(layer)) { + String expected = this.getLayer(); + String actual = span.getLayer(); + doVerify(expected, actual); + } + + } + +} diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/Tag.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/Tag.java new file mode 100644 index 0000000000..a55cdefaa3 --- /dev/null +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/Tag.java @@ -0,0 +1,43 @@ +/* + * 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.skywalking.e2e.trace; + +/** + * @author kezhenxu94 + */ +public class Tag { + private String key; + private String value; + + public String getKey() { + return key; + } + + public void setKey(final String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(final String value) { + this.value = value; + } +} diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/Trace.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/Trace.java index 6296d79633..913e28066b 100644 --- a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/Trace.java +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/Trace.java @@ -31,10 +31,12 @@ public class Trace { private String start; private boolean isError; private final List traceIds; + private final List spans; public Trace() { this.endpointNames = new ArrayList<>(); this.traceIds = new ArrayList<>(); + this.spans = new ArrayList<>(); } public String getKey() { @@ -81,6 +83,10 @@ public class Trace { return traceIds; } + public List getSpans() { + return spans; + } + @Override public String toString() { return "Trace{" + diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/TraceMatcher.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/TraceMatcher.java index 30a537e322..87d7b7698c 100644 --- a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/TraceMatcher.java +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/TraceMatcher.java @@ -39,6 +39,7 @@ public class TraceMatcher extends AbstractMatcher { private String start; private String isError; private List traceIds; + private List spans; @Override public void verify(final Trace trace) { @@ -65,6 +66,10 @@ public class TraceMatcher extends AbstractMatcher { if (Objects.nonNull(getTraceIds())) { verifyTraceIds(trace); } + + if (Objects.nonNull(getSpans())) { + verifySpans(trace); + } } private void verifyKey(Trace trace) { @@ -121,6 +126,16 @@ public class TraceMatcher extends AbstractMatcher { } } + private void verifySpans(Trace trace) { + assertThat(trace.getSpans()).hasSameSizeAs(getSpans()); + + int size = getSpans().size(); + + for (int i = 0; i < size; i++) { + getSpans().get(i).verify(trace.getSpans().get(i)); + } + } + public String getKey() { return key; } @@ -168,4 +183,25 @@ public class TraceMatcher extends AbstractMatcher { public List getTraceIds() { return traceIds != null ? traceIds : new ArrayList<>(); } + + public List getSpans() { + return spans; + } + + public void setSpans(final List spans) { + this.spans = spans; + } + + @Override + public String toString() { + return "TraceMatcher{" + + "key='" + key + '\'' + + ", endpointNames=" + endpointNames + + ", duration='" + duration + '\'' + + ", start='" + start + '\'' + + ", isError='" + isError + '\'' + + ", traceIds=" + traceIds + + ", spans=" + spans + + '}'; + } } diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/TracesData.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/TracesData.java index aa5b49a2f6..2832bd2e9d 100644 --- a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/TracesData.java +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/TracesData.java @@ -24,26 +24,26 @@ import java.util.List; * @author kezhenxu94 */ public class TracesData { - public static class Traces { - private List data; + public static class Traces { + private List data; - public List getData() { - return data; - } + public List getData() { + return data; + } - public Traces setData(List data) { - this.data = data; - return this; + public Traces setData(List data) { + this.data = data; + return this; + } } - } - private Traces traces; + private Traces traces; - public Traces getTraces() { - return traces; - } + public Traces getTraces() { + return traces; + } - public void setTraces(final Traces traces) { - this.traces = traces; - } + public void setTraces(final Traces traces) { + this.traces = traces; + } } diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/TracesMatcher.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/TracesMatcher.java index cade9ccdbe..7d48b5941b 100644 --- a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/TracesMatcher.java +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/TracesMatcher.java @@ -22,6 +22,7 @@ import java.util.LinkedList; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; /** * @author kezhenxu94 @@ -50,4 +51,32 @@ public class TracesMatcher { this.traces.get(i).verify(traces.get(i)); } } + + /** + * Verify the traces in a loose manner + * + * @param traces + */ + public void verifyLoosely(final List traces) { + for (int i = 0; i < getTraces().size(); i++) { + boolean matched = false; + for (int j = 0; j < traces.size(); j++) { + try { + getTraces().get(i).verify(traces.get(j)); + matched = true; + } catch (Throwable ignored) { + } + } + if (!matched) { + fail("Expected: %s\n Actual: %s", getTraces(), traces); + } + } + } + + @Override + public String toString() { + return "TracesMatcher{" + + "traces=" + traces + + '}'; + } } diff --git a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/TracesQuery.java b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/TracesQuery.java index 22b2455d19..410586a5f6 100644 --- a/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/TracesQuery.java +++ b/test/e2e/e2e-base/src/main/java/org/apache/skywalking/e2e/trace/TracesQuery.java @@ -85,6 +85,11 @@ public class TracesQuery extends AbstractQuery { return this; } + public TracesQuery orderByStartTime() { + this.queryOrder = "BY_START_TIME"; + return this; + } + public TracesQuery pageSize(int pageSize) { this.pageSize = String.valueOf(pageSize); return this; diff --git a/test/e2e/e2e-cluster/consumer/pom.xml b/test/e2e/e2e-cluster/consumer/pom.xml new file mode 100644 index 0000000000..efaa53cb22 --- /dev/null +++ b/test/e2e/e2e-cluster/consumer/pom.xml @@ -0,0 +1,56 @@ + + + + + + + e2e-cluster + org.apache.skywalking + 1.0.0 + + 4.0.0 + jar + + consumer + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + true + true + true + + + + + repackage + + + + + + + + diff --git a/test/e2e/e2e-cluster/consumer/src/main/java/org/apache/skywalking/e2e/cluster/Service1Application.java b/test/e2e/e2e-cluster/consumer/src/main/java/org/apache/skywalking/e2e/cluster/Service1Application.java new file mode 100644 index 0000000000..7ba83aac77 --- /dev/null +++ b/test/e2e/e2e-cluster/consumer/src/main/java/org/apache/skywalking/e2e/cluster/Service1Application.java @@ -0,0 +1,32 @@ +/* + * 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.skywalking.e2e.cluster; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author kezhenxu94 + */ +@SpringBootApplication +public class Service1Application { + public static void main(String[] args) { + SpringApplication.run(Service1Application.class, args); + } +} diff --git a/test/e2e/e2e-cluster/consumer/src/main/java/org/apache/skywalking/e2e/cluster/TestController.java b/test/e2e/e2e-cluster/consumer/src/main/java/org/apache/skywalking/e2e/cluster/TestController.java new file mode 100644 index 0000000000..c59f3d315f --- /dev/null +++ b/test/e2e/e2e-cluster/consumer/src/main/java/org/apache/skywalking/e2e/cluster/TestController.java @@ -0,0 +1,50 @@ +/* + * 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.skywalking.e2e.cluster; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +/** + * @author kezhenxu94 + */ +@RestController +@RequestMapping("/e2e") +public class TestController { + private final RestTemplate restTemplate = new RestTemplate(); + + @GetMapping("/health-check") + public String hello() { + return "healthy"; + } + + @PostMapping("/users") + public User createAuthor(@RequestBody final User user) throws InterruptedException { + Thread.sleep(1000L); + final ResponseEntity response = restTemplate.postForEntity( + "http://localhost:9090/e2e/users", user, User.class + ); + return response.getBody(); + } +} diff --git a/test/e2e/e2e-cluster/consumer/src/main/java/org/apache/skywalking/e2e/cluster/User.java b/test/e2e/e2e-cluster/consumer/src/main/java/org/apache/skywalking/e2e/cluster/User.java new file mode 100644 index 0000000000..f62d1e7bcc --- /dev/null +++ b/test/e2e/e2e-cluster/consumer/src/main/java/org/apache/skywalking/e2e/cluster/User.java @@ -0,0 +1,47 @@ +/* + * 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.skywalking.e2e.cluster; + +/** + * @author kezhenxu94 + */ +public class User { + public User() { + } + + private Long id; + + private String name; + + public Long getId() { + return id; + } + + public void setId(final Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } +} diff --git a/test/e2e/e2e-cluster/consumer/src/main/resources/application.yml b/test/e2e/e2e-cluster/consumer/src/main/resources/application.yml new file mode 100644 index 0000000000..757e7cbe00 --- /dev/null +++ b/test/e2e/e2e-cluster/consumer/src/main/resources/application.yml @@ -0,0 +1,22 @@ +# 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. + +server: + port: 9091 + +spring: + main: + banner-mode: 'off' diff --git a/test/e2e/e2e-cluster/pom.xml b/test/e2e/e2e-cluster/pom.xml new file mode 100644 index 0000000000..757863d453 --- /dev/null +++ b/test/e2e/e2e-cluster/pom.xml @@ -0,0 +1,38 @@ + + + + + + apache-skywalking-e2e + org.apache.skywalking + 1.0.0 + + 4.0.0 + + e2e-cluster + pom + + + provider + consumer + test-runner + + diff --git a/test/e2e/e2e-cluster/provider/pom.xml b/test/e2e/e2e-cluster/provider/pom.xml new file mode 100644 index 0000000000..804e24c0b9 --- /dev/null +++ b/test/e2e/e2e-cluster/provider/pom.xml @@ -0,0 +1,69 @@ + + + + + + + e2e-cluster + org.apache.skywalking + 1.0.0 + + 4.0.0 + jar + + provider + + + + org.springframework.boot + spring-boot-starter-data-jpa + ${spring.boot.version} + + + com.h2database + h2 + ${h2.version} + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + true + true + true + + + + + repackage + + + + + + + + diff --git a/test/e2e/e2e-cluster/provider/src/main/java/org/apache/skywalking/e2e/cluster/Service0Application.java b/test/e2e/e2e-cluster/provider/src/main/java/org/apache/skywalking/e2e/cluster/Service0Application.java new file mode 100644 index 0000000000..791eab1a0b --- /dev/null +++ b/test/e2e/e2e-cluster/provider/src/main/java/org/apache/skywalking/e2e/cluster/Service0Application.java @@ -0,0 +1,34 @@ +/* + * 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.skywalking.e2e.cluster; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +/** + * @author kezhenxu94 + */ +@EnableJpaRepositories +@SpringBootApplication +public class Service0Application { + public static void main(String[] args) { + SpringApplication.run(Service0Application.class, args); + } +} diff --git a/test/e2e/e2e-cluster/provider/src/main/java/org/apache/skywalking/e2e/cluster/TestController.java b/test/e2e/e2e-cluster/provider/src/main/java/org/apache/skywalking/e2e/cluster/TestController.java new file mode 100644 index 0000000000..39076484f9 --- /dev/null +++ b/test/e2e/e2e-cluster/provider/src/main/java/org/apache/skywalking/e2e/cluster/TestController.java @@ -0,0 +1,48 @@ +/* + * 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.skywalking.e2e.cluster; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author kezhenxu94 + */ +@RestController +@RequestMapping("/e2e") +public class TestController { + private final UserRepo userRepo; + + public TestController(final UserRepo userRepo) { + this.userRepo = userRepo; + } + + @GetMapping("/health-check") + public String hello() { + return "healthy"; + } + + @PostMapping("/users") + public User createAuthor(@RequestBody final User user) { + return userRepo.save(user); + } +} diff --git a/test/e2e/e2e-cluster/provider/src/main/java/org/apache/skywalking/e2e/cluster/User.java b/test/e2e/e2e-cluster/provider/src/main/java/org/apache/skywalking/e2e/cluster/User.java new file mode 100644 index 0000000000..043127f214 --- /dev/null +++ b/test/e2e/e2e-cluster/provider/src/main/java/org/apache/skywalking/e2e/cluster/User.java @@ -0,0 +1,56 @@ +/* + * 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.skywalking.e2e.cluster; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +/** + * @author kezhenxu94 + */ +@Entity +public class User { + public User() { + } + + @Id + @GeneratedValue + private Long id; + + @Column + private String name; + + public Long getId() { + return id; + } + + public void setId(final Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } +} diff --git a/test/e2e/e2e-cluster/provider/src/main/java/org/apache/skywalking/e2e/cluster/UserRepo.java b/test/e2e/e2e-cluster/provider/src/main/java/org/apache/skywalking/e2e/cluster/UserRepo.java new file mode 100644 index 0000000000..f798f63e07 --- /dev/null +++ b/test/e2e/e2e-cluster/provider/src/main/java/org/apache/skywalking/e2e/cluster/UserRepo.java @@ -0,0 +1,27 @@ +/* + * 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.skywalking.e2e.cluster; + +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * @author kezhenxu94 + */ +public interface UserRepo extends JpaRepository { +} diff --git a/test/e2e/e2e-cluster/provider/src/main/resources/application.yml b/test/e2e/e2e-cluster/provider/src/main/resources/application.yml new file mode 100644 index 0000000000..ef3ed01cd4 --- /dev/null +++ b/test/e2e/e2e-cluster/provider/src/main/resources/application.yml @@ -0,0 +1,35 @@ +# 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. + +server: + port: 9090 + +spring: + main: + banner-mode: 'off' + datasource: + url: jdbc:h2:mem:testdb + driver-class-name: org.h2.Driver + data-username: sa + password: sa + platform: org.hibernate.dialect.H2Dialect + jpa: + generate-ddl: true + hibernate: + ddl-auto: create-drop + properties: + hibernate.format_sql: true + show-sql: true diff --git a/test/e2e/e2e-cluster/test-runner/pom.xml b/test/e2e/e2e-cluster/test-runner/pom.xml new file mode 100644 index 0000000000..c799dc576a --- /dev/null +++ b/test/e2e/e2e-cluster/test-runner/pom.xml @@ -0,0 +1,202 @@ + + + + + + + e2e-cluster + org.apache.skywalking + 1.0.0 + + 4.0.0 + + test-runner + + + + + org.apache.skywalking + e2e-base + ${project.version} + + + + org.apache.skywalking + provider + ${project.version} + + + + org.apache.skywalking + consumer + ${project.version} + + + + + + provider + consumer + 1.1 + + + + + + io.fabric8 + docker-maven-plugin + + %a-%t-%i + Always + + + elastic/elasticsearch:${elasticsearch.version} + skywalking-e2e-container-${build.id}-elasticsearch + + + es.port:9200 + + + + http://localhost:${es.port} + GET + 200 + + + + + single-node + + + + + zookeeper:${zookeeper.image.version} + skywalking-e2e-container-${build.id}-zookeeper + + + zk.port:2181 + + + binding to port + + + + + + skyapm/e2e-container:${e2e.container.version} + skywalking-e2e-container-${build.id} + + + cluster + + skywalking-e2e-container-${build.id}-elasticsearch:9200 + + + skywalking-e2e-container-${build.id}-zookeeper:2181 + + + + ${service0.name}-${project.version}.jar + + + -DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800 + -DSW_AGENT_NAME=${service0.name} + + + --server.port=9090 + + + + ${service1.name}-${project.version}.jar + + + -DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11801 + -DSW_AGENT_NAME=${service1.name} + + + --server.port=9091 + + + + skywalking-e2e-container-${build.id}-elasticsearch + skywalking-e2e-container-${build.id}-zookeeper + + + +webapp.host:webapp.port:8081 + +service.host:service.port:9091 + + + skywalking-e2e-container-${build.id}-elasticsearch + skywalking-e2e-container-${build.id}-zookeeper + + + + + ../../../../dist/apache-skywalking-apm-bin:/sw + + + ../${service0.name}/target/${service0.name}-${project.version}.jar:/home/${service0.name}-${project.version}.jar + + + ../${service1.name}/target/${service1.name}-${project.version}.jar:/home/${service1.name}-${project.version}.jar + + + ${project.basedir}/src/docker/rc.d:/rc.d:ro + + + ${project.basedir}/src/docker/clusterize.awk:/clusterize.awk + + + + + SkyWalking e2e container is ready for tests + + + + + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + ${webapp.host} + ${webapp.port} + ${service.host} + ${service.port} + + + + + + verify + + + + + + + + diff --git a/test/e2e/e2e-cluster/test-runner/src/docker/clusterize.awk b/test/e2e/e2e-cluster/test-runner/src/docker/clusterize.awk new file mode 100644 index 0000000000..870e43bb45 --- /dev/null +++ b/test/e2e/e2e-cluster/test-runner/src/docker/clusterize.awk @@ -0,0 +1,92 @@ +# 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. + +#!/usr/bin/awk -f + +BEGIN { + in_cluster_section=0; + in_cluster_zk_section=0; + + in_storage_section=0; + in_storage_es_section=0; + in_storage_h2_section=0; +} + +{ + if (in_cluster_section == 0) { + in_cluster_section=$0 ~ /^cluster:$/ + } else { + in_cluster_section=$0 ~ /^(#|\s{2})/ + } + if (in_storage_section == 0) { + in_storage_section=$0 ~ /^storage:$/ + } else { + in_storage_section=$0 ~ /^(#|\s{2})/ + } + + if (in_cluster_section == 1) { + # in the cluster: section now + # disable standalone module + if ($0 ~ /^ standalone:$/) { + print "#" $0 + } else { + if (in_cluster_zk_section == 0) { + in_cluster_zk_section=$0 ~ /^#?\s+zookeeper:$/ + } else { + in_cluster_zk_section=$0 ~ /^(#\s{4}|\s{2})/ + } + if (in_cluster_zk_section == 1) { + # in the cluster.zookeeper section now + # uncomment zk config + gsub("^#", "", $0) + print + } else { + print + } + } + } else if (in_storage_section == 1) { + # in the storage: section now + # disable h2 module + if (in_storage_es_section == 0) { + in_storage_es_section=$0 ~ /^#?\s+elasticsearch:$/ + } else { + in_storage_es_section=$0 ~ /^#?\s{4}/ + } + if (in_storage_h2_section == 0) { + in_storage_h2_section=$0 ~ /^#?\s+h2:$/ + } else { + in_storage_h2_section=$0 ~ /^#?\s{4}/ + } + if (in_storage_es_section == 1) { + # in the storage.elasticsearch section now + # uncomment es config + gsub("^#", "", $0) + print + } else if (in_storage_h2_section == 1) { + # comment out h2 config + if ($0 !~ /^#/) { + print "#" $0 + } else { + print + } + } else { + print + } + } else { + print + } +} + diff --git a/test/e2e/e2e-cluster/test-runner/src/docker/rc.d/rc0-prepare.sh b/test/e2e/e2e-cluster/test-runner/src/docker/rc.d/rc0-prepare.sh new file mode 100755 index 0000000000..1723c9b8b2 --- /dev/null +++ b/test/e2e/e2e-cluster/test-runner/src/docker/rc.d/rc0-prepare.sh @@ -0,0 +1,32 @@ +# Licensed to the SkyAPM 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. + +#!/usr/bin/env bash + +if test "${MODE}" = "cluster"; then + original_wd=$(pwd) + + # substitute application.yml to be capable of cluster mode + cd ${SW_HOME}/config \ + && awk -f /clusterize.awk application.yml > clusterized_app.yml \ + && mv clusterized_app.yml application.yml + + cd ${SW_HOME}/webapp \ + && awk '/^\s+listOfServers/ {gsub("127.0.0.1:12800", "127.0.0.1:12800,127.0.0.1:12801", $0)} {print}' webapp.yml > clusterized_webapp.yml \ + && mv clusterized_webapp.yml webapp.yml + + cd ${original_wd} +fi diff --git a/test/e2e/e2e-cluster/test-runner/src/docker/rc.d/rc1-startup.sh b/test/e2e/e2e-cluster/test-runner/src/docker/rc.d/rc1-startup.sh new file mode 100755 index 0000000000..9e95aec8b7 --- /dev/null +++ b/test/e2e/e2e-cluster/test-runner/src/docker/rc.d/rc1-startup.sh @@ -0,0 +1,73 @@ +# Licensed to the SkyAPM 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. + +#!/usr/bin/env bash + +echo 'starting OAP server...' \ + && SW_STORAGE_ES_BULK_ACTIONS=1 \ + && SW_STORAGE_ES_FLUSH_INTERVAL=1 \ + && start_oap 'init' + +echo 'starting Web app...' \ + && start_webapp '0.0.0.0' 8081 + +if test "${MODE}" = "cluster"; then + # start another OAP server in a different port + echo 'starting OAP server...' \ + && SW_CORE_GRPC_PORT=11801 \ + && SW_CORE_REST_PORT=12801 \ + && SW_STORAGE_ES_BULK_ACTIONS=1 \ + && SW_STORAGE_ES_FLUSH_INTERVAL=1 \ + && start_oap 'no-init' + + # start another WebApp server in a different port + echo 'starting Web app...' \ + && start_webapp '0.0.0.0' 8082 +fi + +echo 'starting instrumented services...' && start_instrumented_services + +check_tcp 127.0.0.1 \ + 9090 \ + 60 \ + 10 \ + "waiting for the instrumented service 0 to be ready" + +if [[ $? -ne 0 ]]; then + echo "instrumented service 0 failed to start in 30 * 10 seconds: " + cat ${SERVICE_LOG}/* + exit 1 +fi + +check_tcp 127.0.0.1 \ + 9091 \ + 60 \ + 10 \ + "waiting for the instrumented service 1 to be ready" + +if [[ $? -ne 0 ]]; then + echo "instrumented service 1 failed to start in 24 * 10 seconds: " + cat ${SERVICE_LOG}/* + exit 1 +fi + +echo "SkyWalking e2e container is ready for tests" + +tail -f ${OAP_LOG_DIR}/* \ + ${WEBAPP_LOG_DIR}/* \ + ${SERVICE_LOG}/* \ + ${ES_HOME}/logs/elasticsearch.log \ + ${ES_HOME}/logs/stdout.log diff --git a/test/e2e/e2e-cluster/test-runner/src/test/java/org/apache/skywalking/e2e/ClusterVerificationITCase.java b/test/e2e/e2e-cluster/test-runner/src/test/java/org/apache/skywalking/e2e/ClusterVerificationITCase.java new file mode 100644 index 0000000000..eb45ef023b --- /dev/null +++ b/test/e2e/e2e-cluster/test-runner/src/test/java/org/apache/skywalking/e2e/ClusterVerificationITCase.java @@ -0,0 +1,348 @@ +/* + * 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.skywalking.e2e; + +import org.apache.skywalking.e2e.metrics.AtLeastOneOfMetricsMatcher; +import org.apache.skywalking.e2e.metrics.Metrics; +import org.apache.skywalking.e2e.metrics.MetricsQuery; +import org.apache.skywalking.e2e.metrics.MetricsValueMatcher; +import org.apache.skywalking.e2e.service.Service; +import org.apache.skywalking.e2e.service.ServicesMatcher; +import org.apache.skywalking.e2e.service.ServicesQuery; +import org.apache.skywalking.e2e.service.endpoint.Endpoint; +import org.apache.skywalking.e2e.service.endpoint.EndpointQuery; +import org.apache.skywalking.e2e.service.endpoint.Endpoints; +import org.apache.skywalking.e2e.service.endpoint.EndpointsMatcher; +import org.apache.skywalking.e2e.service.instance.Instance; +import org.apache.skywalking.e2e.service.instance.Instances; +import org.apache.skywalking.e2e.service.instance.InstancesMatcher; +import org.apache.skywalking.e2e.service.instance.InstancesQuery; +import org.apache.skywalking.e2e.topo.TopoData; +import org.apache.skywalking.e2e.topo.TopoMatcher; +import org.apache.skywalking.e2e.topo.TopoQuery; +import org.apache.skywalking.e2e.trace.Trace; +import org.apache.skywalking.e2e.trace.TracesMatcher; +import org.apache.skywalking.e2e.trace.TracesQuery; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.client.RestTemplate; +import org.yaml.snakeyaml.Yaml; + +import java.io.InputStream; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_ENDPOINT_METRICS; +import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_INSTANCE_METRICS; +import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_METRICS; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author kezhenxu94 + */ +@RunWith(SpringJUnit4ClassRunner.class) +public class ClusterVerificationITCase { + private static final Logger LOGGER = LoggerFactory.getLogger(ClusterVerificationITCase.class); + + private final RestTemplate restTemplate = new RestTemplate(); + private final Yaml yaml = new Yaml(); + + private SimpleQueryClient queryClient; + private String instrumentedServiceUrl; + private long retryInterval = TimeUnit.SECONDS.toMillis(30); + + @Before + public void setUp() { + final String swWebappHost = System.getProperty("sw.webapp.host", "127.0.0.1"); + final String swWebappPort = System.getProperty("sw.webapp.port", "32791"); + final String instrumentedServiceHost = System.getProperty("service.host", "127.0.0.1"); + final String instrumentedServicePort = System.getProperty("service.port", "32790"); + queryClient = new SimpleQueryClient(swWebappHost, swWebappPort); + instrumentedServiceUrl = "http://" + instrumentedServiceHost + ":" + instrumentedServicePort; + } + + @Test(timeout = 1200000) + @DirtiesContext + public void verify() throws Exception { + LocalDateTime startTime = LocalDateTime.now(ZoneOffset.UTC); + + final Map user = new HashMap<>(); + user.put("name", "SkyWalking"); + List services = Collections.emptyList(); + while (services.size() < 2) { + try { + restTemplate.postForEntity( + instrumentedServiceUrl + "/e2e/users", + user, + String.class + ); + services = queryClient.services( + new ServicesQuery() + .start(startTime) + .end(LocalDateTime.now(ZoneOffset.UTC).plusMinutes(1)) + ); + } catch (Throwable ignored) { + } + } + + final ResponseEntity responseEntity = restTemplate.postForEntity( + instrumentedServiceUrl + "/e2e/users", + user, + String.class + ); + LOGGER.info("responseEntity: {}, {}", responseEntity.getStatusCode(), responseEntity.getBody()); + assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); + + verifyTraces(startTime); + + verifyServices(startTime); + + verifyTopo(startTime); + } + + private void verifyTopo(LocalDateTime minutesAgo) throws Exception { + final TopoData topoData = queryClient.topo( + new TopoQuery() + .stepByMinute() + .start(minutesAgo) + .end(LocalDateTime.now(ZoneOffset.UTC).plusMinutes(1)) + ); + + InputStream expectedInputStream = + new ClassPathResource("expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.topo.yml").getInputStream(); + + final TopoMatcher topoMatcher = yaml.loadAs(expectedInputStream, TopoMatcher.class); + topoMatcher.verify(topoData); + } + + private void verifyServices(LocalDateTime minutesAgo) throws Exception { + List services = queryClient.services( + new ServicesQuery() + .start(minutesAgo) + .end(LocalDateTime.now(ZoneOffset.UTC).plusMinutes(1)) + ); + while (services.isEmpty()) { + LOGGER.warn("services is null, will retry to query"); + services = queryClient.services( + new ServicesQuery() + .start(minutesAgo) + .end(LocalDateTime.now(ZoneOffset.UTC).plusMinutes(1)) + ); + Thread.sleep(retryInterval); + } + + InputStream expectedInputStream = + new ClassPathResource("expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.services.yml").getInputStream(); + + final ServicesMatcher servicesMatcher = yaml.loadAs(expectedInputStream, ServicesMatcher.class); + servicesMatcher.verify(services); + + for (Service service : services) { + LOGGER.info("verifying service instances: {}", service); + + verifyServiceMetrics(service, minutesAgo); + + Instances instances = verifyServiceInstances(minutesAgo, service); + + verifyInstancesMetrics(instances, minutesAgo); + + Endpoints endpoints = verifyServiceEndpoints(minutesAgo, service); + + verifyEndpointsMetrics(endpoints, minutesAgo); + } + } + + private Instances verifyServiceInstances(LocalDateTime minutesAgo, Service service) throws Exception { + Instances instances = queryClient.instances( + new InstancesQuery() + .serviceId(service.getKey()) + .start(minutesAgo) + .end(LocalDateTime.now(ZoneOffset.UTC).plusMinutes(1)) + ); + while (instances == null) { + LOGGER.warn("instances is null, will retry to query"); + instances = queryClient.instances( + new InstancesQuery() + .serviceId(service.getKey()) + .start(minutesAgo) + .end(LocalDateTime.now(ZoneOffset.UTC).plusMinutes(1)) + ); + Thread.sleep(retryInterval); + } + InputStream expectedInputStream = + new ClassPathResource("expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.instances.yml").getInputStream(); + final InstancesMatcher instancesMatcher = yaml.loadAs(expectedInputStream, InstancesMatcher.class); + instancesMatcher.verify(instances); + return instances; + } + + private Endpoints verifyServiceEndpoints(LocalDateTime minutesAgo, Service service) throws Exception { + Endpoints endpoints = queryClient.endpoints( + new EndpointQuery().serviceId(service.getKey()) + ); + while (endpoints == null) { + LOGGER.warn("endpoints is null, will retry to query"); + endpoints = queryClient.endpoints( + new EndpointQuery().serviceId(service.getKey()) + ); + Thread.sleep(retryInterval); + } + InputStream expectedInputStream = + new ClassPathResource("expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.endpoints.yml").getInputStream(); + final EndpointsMatcher endpointsMatcher = yaml.loadAs(expectedInputStream, EndpointsMatcher.class); + endpointsMatcher.verify(endpoints); + return endpoints; + } + + private void verifyInstancesMetrics(Instances instances, final LocalDateTime minutesAgo) throws Exception { + for (Instance instance : instances.getInstances()) { + for (String metricsName : ALL_INSTANCE_METRICS) { + LOGGER.info("verifying service instance response time: {}", instance); + + boolean matched = false; + while (!matched) { + LOGGER.warn("instanceRespTime is null, will retry to query"); + Metrics instanceRespTime = queryClient.metrics( + new MetricsQuery() + .stepByMinute() + .metricsName(metricsName) + .start(minutesAgo) + .end(LocalDateTime.now(ZoneOffset.UTC).plusMinutes(1)) + .id(instance.getKey()) + ); + AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new AtLeastOneOfMetricsMatcher(); + MetricsValueMatcher greaterThanZero = new MetricsValueMatcher(); + greaterThanZero.setValue("gt 0"); + instanceRespTimeMatcher.setValue(greaterThanZero); + try { + instanceRespTimeMatcher.verify(instanceRespTime); + matched = true; + } catch (Throwable ignored) { + Thread.sleep(retryInterval); + } + LOGGER.info("{}: {}", metricsName, instanceRespTime); + } + } + } + } + + private void verifyEndpointsMetrics(Endpoints endpoints, final LocalDateTime minutesAgo) throws Exception { + for (Endpoint endpoint : endpoints.getEndpoints()) { + if (!endpoint.getLabel().equals("/e2e/users")) { + continue; + } + for (String metricName : ALL_ENDPOINT_METRICS) { + LOGGER.info("verifying endpoint {}, metrics: {}", endpoint, metricName); + + boolean matched = false; + while (!matched) { + LOGGER.warn("serviceMetrics is null, will retry to query"); + Metrics metrics = queryClient.metrics( + new MetricsQuery() + .stepByMinute() + .metricsName(metricName) + .start(minutesAgo) + .end(LocalDateTime.now(ZoneOffset.UTC).plusMinutes(1)) + .id(endpoint.getKey()) + ); + AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new AtLeastOneOfMetricsMatcher(); + MetricsValueMatcher greaterThanZero = new MetricsValueMatcher(); + greaterThanZero.setValue("gt 0"); + instanceRespTimeMatcher.setValue(greaterThanZero); + try { + instanceRespTimeMatcher.verify(metrics); + matched = true; + } catch (Throwable ignored) { + Thread.sleep(retryInterval); + } + LOGGER.info("metrics: {}", metrics); + } + } + } + } + + private void verifyServiceMetrics(Service service, final LocalDateTime minutesAgo) throws Exception { + for (String metricName : ALL_SERVICE_METRICS) { + LOGGER.info("verifying service {}, metrics: {}", service, metricName); + + boolean matched = false; + while (!matched) { + Metrics serviceMetrics = queryClient.metrics( + new MetricsQuery() + .stepByMinute() + .metricsName(metricName) + .start(minutesAgo) + .end(LocalDateTime.now(ZoneOffset.UTC).plusMinutes(1)) + .id(service.getKey()) + ); + AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new AtLeastOneOfMetricsMatcher(); + MetricsValueMatcher greaterThanZero = new MetricsValueMatcher(); + greaterThanZero.setValue("gt 0"); + instanceRespTimeMatcher.setValue(greaterThanZero); + try { + instanceRespTimeMatcher.verify(serviceMetrics); + matched = true; + } catch (Throwable ignored) { + Thread.sleep(retryInterval); + } + LOGGER.info("serviceMetrics: {}", serviceMetrics); + } + } + } + + private void verifyTraces(LocalDateTime minutesAgo) throws Exception { + List traces = queryClient.traces( + new TracesQuery() + .stepBySecond() + .start(minutesAgo) + .end(LocalDateTime.now(ZoneOffset.UTC).plusMinutes(1)) + .orderByStartTime() + ); + while (traces.isEmpty()) { + LOGGER.warn("traces is empty, will retry to query"); + traces = queryClient.traces( + new TracesQuery() + .stepBySecond() + .start(minutesAgo) + .end(LocalDateTime.now(ZoneOffset.UTC).plusMinutes(1)) + .orderByStartTime() + ); + Thread.sleep(retryInterval); + } + + InputStream expectedInputStream = + new ClassPathResource("expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.traces.yml").getInputStream(); + + final TracesMatcher tracesMatcher = yaml.loadAs(expectedInputStream, TracesMatcher.class); + tracesMatcher.verifyLoosely(traces); + } +} diff --git a/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.endpoints.yml b/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.endpoints.yml new file mode 100644 index 0000000000..3ddf42e490 --- /dev/null +++ b/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.endpoints.yml @@ -0,0 +1,25 @@ +# 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. + +# 1 health-check by docker-maven-plugin +# 1 drop table if exists, because we have `ddl-auto: create-drop` +# 1 drop sequence +# 1 create sequence +# 1 create table statement + +endpoints: + - key: not null + label: /e2e/users diff --git a/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.instances.yml b/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.instances.yml new file mode 100644 index 0000000000..1c48fc4ffc --- /dev/null +++ b/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.instances.yml @@ -0,0 +1,34 @@ +# 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. + +# 1 health-check by docker-maven-plugin +# 1 drop table if exists, because we have `ddl-auto: create-drop` +# 1 drop sequence +# 1 create sequence +# 1 create table statement + +instances: + - key: gt 0 + label: not null + attributes: + - name: os_name + value: not null + - name: host_name + value: not null + - name: process_no + value: gt 0 + - name: ipv4s + value: not null diff --git a/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.services.yml b/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.services.yml new file mode 100644 index 0000000000..f0fc184185 --- /dev/null +++ b/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.services.yml @@ -0,0 +1,28 @@ +# 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. + +# 1 health-check by docker-maven-plugin +# 1 drop table if exists, because we have `ddl-auto: create-drop` +# 1 drop sequence +# 1 create sequence +# 1 create table statement + +services: + - key: not null + label: provider + + - key: not null + label: consumer diff --git a/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.topo.yml b/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.topo.yml new file mode 100644 index 0000000000..9f74cfce6a --- /dev/null +++ b/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.topo.yml @@ -0,0 +1,39 @@ +# 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. + +nodes: + - id: not null + name: User + type: USER + - id: not null + name: provider + type: Tomcat + - id: not null + name: consumer + type: Tomcat + - id: not null + name: "localhost:-1" + type: H2 +calls: + - id: not null + source: not null + target: not null + - id: not null + source: not null + target: not null + - id: not null + source: not null + target: not null diff --git a/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.traces.yml b/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.traces.yml new file mode 100644 index 0000000000..4542e5d866 --- /dev/null +++ b/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.traces.yml @@ -0,0 +1,25 @@ +# 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. + +traces: + - key: not null + endpointNames: + - /e2e/users + duration: ge 0 + start: gt 0 + isError: false + traceIds: + - not null diff --git a/test/e2e/e2e-single-service/pom.xml b/test/e2e/e2e-single-service/pom.xml index 866ef62132..32e1d6d4c7 100644 --- a/test/e2e/e2e-single-service/pom.xml +++ b/test/e2e/e2e-single-service/pom.xml @@ -72,7 +72,7 @@ io.fabric8 docker-maven-plugin - %a-%t + %a-%t-%i skyapm/e2e-container:${e2e.container.version} diff --git a/test/e2e/e2e-single-service/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java b/test/e2e/e2e-single-service/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java index cb04459304..883ba14c78 100644 --- a/test/e2e/e2e-single-service/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java +++ b/test/e2e/e2e-single-service/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java @@ -59,19 +59,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import static org.apache.skywalking.e2e.metrics.MetricsQuery.ENDPOINT_P50; -import static org.apache.skywalking.e2e.metrics.MetricsQuery.ENDPOINT_P75; -import static org.apache.skywalking.e2e.metrics.MetricsQuery.ENDPOINT_P90; -import static org.apache.skywalking.e2e.metrics.MetricsQuery.ENDPOINT_P95; -import static org.apache.skywalking.e2e.metrics.MetricsQuery.ENDPOINT_P99; -import static org.apache.skywalking.e2e.metrics.MetricsQuery.SERVICE_INSTANCE_CPM; -import static org.apache.skywalking.e2e.metrics.MetricsQuery.SERVICE_INSTANCE_RESP_TIME; -import static org.apache.skywalking.e2e.metrics.MetricsQuery.SERVICE_INSTANCE_SLA; -import static org.apache.skywalking.e2e.metrics.MetricsQuery.SERVICE_P50; -import static org.apache.skywalking.e2e.metrics.MetricsQuery.SERVICE_P75; -import static org.apache.skywalking.e2e.metrics.MetricsQuery.SERVICE_P90; -import static org.apache.skywalking.e2e.metrics.MetricsQuery.SERVICE_P95; -import static org.apache.skywalking.e2e.metrics.MetricsQuery.SERVICE_P99; +import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_ENDPOINT_METRICS; +import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_INSTANCE_METRICS; +import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_METRICS; import static org.assertj.core.api.Assertions.assertThat; /** @@ -82,6 +72,8 @@ public class SampleVerificationITCase { private static final Logger LOGGER = LoggerFactory.getLogger(SampleVerificationITCase.class); private final RestTemplate restTemplate = new RestTemplate(); + private final int retryTimes = 5; + private final int retryInterval = 30; private SimpleQueryClient queryClient; private String instrumentedServiceUrl; @@ -90,11 +82,10 @@ public class SampleVerificationITCase { public void setUp() { final String swWebappHost = System.getProperty("sw.webapp.host", "127.0.0.1"); final String swWebappPort = System.getProperty("sw.webapp.port", "32783"); - final String instrumentedServiceHost0 = System.getProperty("client.host", "127.0.0.1"); - final String instrumentedServicePort0 = System.getProperty("client.port", "32782"); - final String queryClientUrl = "http://" + swWebappHost + ":" + swWebappPort + "/graphql"; - queryClient = new SimpleQueryClient(queryClientUrl); - instrumentedServiceUrl = "http://" + instrumentedServiceHost0 + ":" + instrumentedServicePort0; + final String instrumentedServiceHost = System.getProperty("client.host", "127.0.0.1"); + final String instrumentedServicePort = System.getProperty("client.port", "32782"); + queryClient = new SimpleQueryClient(swWebappHost, swWebappPort); + instrumentedServiceUrl = "http://" + instrumentedServiceHost + ":" + instrumentedServicePort; } @Test @@ -111,13 +102,29 @@ public class SampleVerificationITCase { ); assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); - Thread.sleep(5000); - - verifyTraces(minutesAgo); + doRetryableVerification(() -> { + try { + verifyTraces(minutesAgo); + } catch (Exception e) { + LOGGER.warn(e.getMessage(), e); + } + }); - verifyServices(minutesAgo); + doRetryableVerification(() -> { + try { + verifyServices(minutesAgo); + } catch (Exception e) { + LOGGER.warn(e.getMessage(), e); + } + }); - verifyTopo(minutesAgo); + doRetryableVerification(() -> { + try { + verifyTopo(minutesAgo); + } catch (Exception e) { + LOGGER.warn(e.getMessage(), e); + } + }); } private void verifyTopo(LocalDateTime minutesAgo) throws Exception { @@ -125,7 +132,7 @@ public class SampleVerificationITCase { final TopoData topoData = queryClient.topo( new TopoQuery() - .step("MINUTE") + .stepByMinute() .start(minutesAgo.minusDays(1)) .end(now) ); @@ -194,17 +201,12 @@ public class SampleVerificationITCase { } private void verifyInstancesMetrics(Instances instances) throws Exception { - final String[] instanceMetricsNames = new String[] { - SERVICE_INSTANCE_RESP_TIME, - SERVICE_INSTANCE_CPM, - SERVICE_INSTANCE_SLA - }; for (Instance instance : instances.getInstances()) { - for (String metricsName : instanceMetricsNames) { + for (String metricsName : ALL_INSTANCE_METRICS) { LOGGER.info("verifying service instance response time: {}", instance); final Metrics instanceRespTime = queryClient.metrics( new MetricsQuery() - .step("MINUTE") + .stepByMinute() .metricsName(metricsName) .id(instance.getKey()) ); @@ -219,22 +221,15 @@ public class SampleVerificationITCase { } private void verifyEndpointsMetrics(Endpoints endpoints) throws Exception { - final String[] endpointMetricsNames = { - ENDPOINT_P99, - ENDPOINT_P95, - ENDPOINT_P90, - ENDPOINT_P75, - ENDPOINT_P50 - }; for (Endpoint endpoint : endpoints.getEndpoints()) { if (!endpoint.getLabel().equals("/e2e/users")) { continue; } - for (String metricName : endpointMetricsNames) { + for (String metricName : ALL_ENDPOINT_METRICS) { LOGGER.info("verifying endpoint {}, metrics: {}", endpoint, metricName); final Metrics metrics = queryClient.metrics( new MetricsQuery() - .step("MINUTE") + .stepByMinute() .metricsName(metricName) .id(endpoint.getKey()) ); @@ -249,18 +244,11 @@ public class SampleVerificationITCase { } private void verifyServiceMetrics(Service service) throws Exception { - final String[] serviceMetrics = { - SERVICE_P99, - SERVICE_P95, - SERVICE_P90, - SERVICE_P75, - SERVICE_P50 - }; - for (String metricName : serviceMetrics) { + for (String metricName : ALL_SERVICE_METRICS) { LOGGER.info("verifying service {}, metrics: {}", service, metricName); final Metrics instanceRespTime = queryClient.metrics( new MetricsQuery() - .step("MINUTE") + .stepByMinute() .metricsName(metricName) .id(service.getKey()) ); @@ -289,4 +277,15 @@ public class SampleVerificationITCase { final TracesMatcher tracesMatcher = new Yaml().loadAs(expectedInputStream, TracesMatcher.class); tracesMatcher.verify(traces); } + + private void doRetryableVerification(Runnable runnable) throws InterruptedException { + for (int i = 0; i < retryTimes; i++) { + try { + runnable.run(); + break; + } catch (Throwable ignored) { + Thread.sleep(retryInterval); + } + } + } } diff --git a/test/e2e/pom.xml b/test/e2e/pom.xml index f914a73616..ae5dcf4bf7 100644 --- a/test/e2e/pom.xml +++ b/test/e2e/pom.xml @@ -34,6 +34,7 @@ e2e-base e2e-single-service + e2e-cluster @@ -51,6 +52,9 @@ 1.23 2.8.5 1.4.199 + 6.3.2 + 3.5 + 1.18.4