You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2020/04/15 02:01:21 UTC

[skywalking] branch master updated: Add `java` -> `go2sky` -> `java` e2e test case, and adapt v3 protocol (#4647)

This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new ccb65ff  Add `java` -> `go2sky` -> `java` e2e test case, and adapt v3 protocol (#4647)
ccb65ff is described below

commit ccb65ff27fb062fa36ba75afca85c8b5cfbbcb5a
Author: zhang-wei <pk...@outlook.com>
AuthorDate: Wed Apr 15 10:01:11 2020 +0800

    Add `java` -> `go2sky` -> `java` e2e test case, and adapt v3 protocol (#4647)
    
    * go2sky e2e
    
    Co-authored-by: kezhenxu94 <ke...@apache.org>
---
 .github/workflows/e2e.go.yaml                      |  53 ++++
 .../skywalking/e2e/controller/UserController.java  |  22 +-
 test/e2e/e2e-test/docker/go/Dockerfile.go          |  37 +++
 test/e2e/e2e-test/docker/go/docker-compose.yml     | 109 ++++++++
 .../test/java/org/apache/skywalking/e2e/GOE2E.java | 292 +++++++++++++++++++++
 .../resources/expected/go/endpoints-consumer.yml   |  18 ++
 .../resources/expected/go/endpoints-go2sky.yml     |  18 ++
 .../resources/expected/go/endpoints-provider.yml   |  18 ++
 .../test/resources/expected/go/instances-go.yml    |  27 ++
 .../test/resources/expected/go/instances-java.yml  |  27 ++
 .../resources/expected/go/serviceInstanceTopo.yml  |  35 +++
 .../src/test/resources/expected/go/services.yml    |  22 ++
 .../src/test/resources/expected/go/topo.yml        |  59 +++++
 .../src/test/resources/expected/go/traces.yml      |  24 ++
 14 files changed, 758 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/e2e.go.yaml b/.github/workflows/e2e.go.yaml
new file mode 100644
index 0000000..ac461fc
--- /dev/null
+++ b/.github/workflows/e2e.go.yaml
@@ -0,0 +1,53 @@
+# 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.
+
+name: E2E
+
+on:
+  pull_request:
+  push:
+    branches:
+      - master
+    tags:
+      - 'v*'
+
+env:
+  SKIP_TEST: true
+  SW_AGENT_JDK_VERSION: 8
+
+jobs:
+  GOAgent:
+    name: GO2SKY
+    runs-on: ubuntu-latest
+    timeout-minutes: 90
+    steps:
+      - uses: actions/checkout@v2
+      - name: checkout submodules
+        shell: bash
+        run: |
+          git submodule sync --recursive
+          git -c protocol.version=2 submodule update --init --force --recursive --depth=1
+      - name: Compile and Build
+        run: make docker
+      - name: Copy dist package
+        run: cp -R dist test/e2e/
+      - name: GO2SKY
+        run: ./mvnw --batch-mode -f test/e2e/pom.xml -am -DfailIfNoTests=false verify -Dit.test=org.apache.skywalking.e2e.GOE2E
+      - uses: actions/upload-artifact@v1
+        if: failure()
+        with:
+          name: logs
+          path: logs
diff --git a/test/e2e/e2e-service-consumer/src/main/java/org/apache/skywalking/e2e/controller/UserController.java b/test/e2e/e2e-service-consumer/src/main/java/org/apache/skywalking/e2e/controller/UserController.java
index 392ddf7..21379de 100644
--- a/test/e2e/e2e-service-consumer/src/main/java/org/apache/skywalking/e2e/controller/UserController.java
+++ b/test/e2e/e2e-service-consumer/src/main/java/org/apache/skywalking/e2e/controller/UserController.java
@@ -19,17 +19,18 @@
 package org.apache.skywalking.e2e.controller;
 
 import com.google.common.base.Strings;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import lombok.RequiredArgsConstructor;
 import org.apache.skywalking.e2e.E2EConfiguration;
 import org.apache.skywalking.e2e.User;
+import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.client.RestTemplate;
 
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
 @RestController
 @RequiredArgsConstructor
 public class UserController {
@@ -37,6 +38,21 @@ public class UserController {
 
     private final E2EConfiguration configuration;
 
+    @PostMapping("/info")
+    public String info() throws InterruptedException {
+        Thread.sleep(1000L);
+
+        Optional<ResponseEntity<String>> optionalResponseEntity = Stream.of(
+            Strings.nullToEmpty(configuration.getProviderBaseUrl()).split(","))
+                                                                        .map(baseUrl -> restTemplate.postForEntity(
+                                                                            baseUrl + "/info", null, String.class))
+                                                                        .findFirst();
+        if (optionalResponseEntity.isPresent() && optionalResponseEntity.get().getStatusCodeValue() == 200) {
+            return optionalResponseEntity.get().getBody();
+        }
+        throw new RuntimeException();
+    }
+
     @PostMapping("/users")
     public Object createAuthor(@RequestBody final User user) throws InterruptedException {
         Thread.sleep(1000L);
diff --git a/test/e2e/e2e-test/docker/go/Dockerfile.go b/test/e2e/e2e-test/docker/go/Dockerfile.go
new file mode 100644
index 0000000..bcbd02b
--- /dev/null
+++ b/test/e2e/e2e-test/docker/go/Dockerfile.go
@@ -0,0 +1,37 @@
+# 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.
+
+FROM golang:1.12 AS builder
+
+ARG COMMIT_HASH=fdb185d66faddad1651c18150d63bae32610f3ac
+ARG GO2SKY_CODE=${COMMIT_HASH}.tar.gz
+ARG GO2SKY_CODE_URL=https://github.com/SkyAPM/go2sky/archive/${GO2SKY_CODE}
+
+ENV CGO_ENABLED=0
+ENV GO111MODULE=on
+
+WORKDIR /go2sky
+
+ADD ${GO2SKY_CODE_URL} .
+RUN tar -xf ${GO2SKY_CODE} --strip 1
+RUN rm ${GO2SKY_CODE}
+
+WORKDIR /go2sky/test/e2e/example-server
+RUN go build -o main
+
+FROM alpine:3.10
+
+COPY --from=builder /go2sky/test/e2e/example-server/main .
+ENTRYPOINT ["/main"]
\ No newline at end of file
diff --git a/test/e2e/e2e-test/docker/go/docker-compose.yml b/test/e2e/e2e-test/docker/go/docker-compose.yml
new file mode 100644
index 0000000..c1cfbc7
--- /dev/null
+++ b/test/e2e/e2e-test/docker/go/docker-compose.yml
@@ -0,0 +1,109 @@
+# 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.
+
+version: '2.1'
+
+services:
+  oap:
+    image: skywalking/oap:latest
+    expose:
+      - 11800
+      - 12800
+    networks:
+      - e2e
+    restart: on-failure
+    healthcheck:
+      test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/11800"]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+
+  ui:
+    image: skywalking/ui:latest
+    expose:
+      - 8080
+    networks:
+      - e2e
+    environment:
+      - SW_OAP_ADDRESS=oap:12800
+    depends_on:
+      oap:
+        condition: service_healthy
+
+  java-provider:
+    build:
+      context: ../../../
+      dockerfile: e2e-test/docker/Dockerfile.provider
+    networks:
+      - e2e
+    expose:
+      - 9090
+    environment:
+      - SW_AGENT_COLLECTOR_BACKEND_SERVICES=oap:11800
+      - SW_AGENT_NAME=e2e-service-java-provider
+    depends_on:
+      oap:
+        condition: service_healthy
+    healthcheck:
+      test: ["CMD", "sh", "-c", "nc -z 127.0.0.1 9090"]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+
+  go2sky:
+    build:
+      context: .
+      dockerfile: Dockerfile.go
+    networks:
+      - e2e
+    expose:
+      - 8080
+    depends_on:
+      oap:
+        condition: service_healthy
+      java-provider:
+        condition: service_healthy
+    command: ['--grpc', '--oap-server', 'oap:11800', '--upstream-url', 'http://java-provider:9090/info']
+    healthcheck:
+      test: ["CMD", "sh", "-c", "nc -z 127.0.0.1 8080"]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+
+  java-consumer:
+    build:
+      context: ../../../
+      dockerfile: e2e-test/docker/Dockerfile.consumer
+    networks:
+      - e2e
+    expose:
+      - 9092
+    environment:
+      - SW_AGENT_COLLECTOR_BACKEND_SERVICES=oap:11800
+      - SW_AGENT_NAME=e2e-service-java-consumer
+      - PROVIDER_URL=http://go2sky:8080
+    depends_on:
+      oap:
+        condition: service_healthy
+      go2sky:
+        condition: service_healthy
+    healthcheck:
+      test: ["CMD", "sh", "-c", "nc -z 127.0.0.1 9092"]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+
+networks:
+  e2e:
\ No newline at end of file
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/GOE2E.java b/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/GOE2E.java
new file mode 100644
index 0000000..504bf90
--- /dev/null
+++ b/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/GOE2E.java
@@ -0,0 +1,292 @@
+/*
+ * 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 java.util.List;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.e2e.annotation.ContainerHostAndPort;
+import org.apache.skywalking.e2e.annotation.DockerCompose;
+import org.apache.skywalking.e2e.base.SkyWalkingE2E;
+import org.apache.skywalking.e2e.base.SkyWalkingTestAdapter;
+import org.apache.skywalking.e2e.common.HostAndPort;
+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.retryable.RetryableTest;
+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.Call;
+import org.apache.skywalking.e2e.topo.ServiceInstanceTopology;
+import org.apache.skywalking.e2e.topo.ServiceInstanceTopologyMatcher;
+import org.apache.skywalking.e2e.topo.ServiceInstanceTopologyQuery;
+import org.apache.skywalking.e2e.topo.TopoMatcher;
+import org.apache.skywalking.e2e.topo.TopoQuery;
+import org.apache.skywalking.e2e.topo.Topology;
+import org.apache.skywalking.e2e.trace.Trace;
+import org.apache.skywalking.e2e.trace.TracesMatcher;
+import org.apache.skywalking.e2e.trace.TracesQuery;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.testcontainers.containers.DockerComposeContainer;
+
+import static org.apache.skywalking.e2e.metrics.MetricsMatcher.verifyMetrics;
+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_INSTANCE_RELATION_CLIENT_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_INSTANCE_RELATION_SERVER_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_RELATION_CLIENT_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_RELATION_SERVER_METRICS;
+import static org.apache.skywalking.e2e.utils.Times.now;
+import static org.apache.skywalking.e2e.utils.Yamls.load;
+
+@Slf4j
+@SkyWalkingE2E
+public class GOE2E extends SkyWalkingTestAdapter {
+
+    @SuppressWarnings("unused")
+    @DockerCompose("docker/go/docker-compose.yml")
+    private DockerComposeContainer<?> justForSideEffects;
+
+    @SuppressWarnings("unused")
+    @ContainerHostAndPort(name = "ui", port = 8080)
+    private HostAndPort swWebappHostPort;
+
+    @SuppressWarnings("unused")
+    @ContainerHostAndPort(name = "java-consumer", port = 9092)
+    private HostAndPort javaConsumerHostPort;
+
+    private final String go2skyServiceName = "go2sky";
+
+    private final String javaProviderServiceName = "e2e-service-java-provider";
+
+    private final String javaConsumerServiceName = "e2e-service-java-consumer";
+
+    @BeforeAll
+    public void setUp() throws Exception {
+        queryClient(swWebappHostPort);
+        trafficController(javaConsumerHostPort, "/info");
+    }
+
+    @AfterAll
+    public void tearDown() {
+        trafficController.stop();
+    }
+
+    @RetryableTest
+    void services() throws Exception {
+        final List<Service> services = graphql.services(new ServicesQuery().start(startTime).end(now()));
+
+        LOGGER.info("services: {}", services);
+
+        load("expected/go/services.yml").as(ServicesMatcher.class).verify(services);
+
+        for (Service service : services) {
+            LOGGER.info("verifying service instances: {}", service);
+
+            verifyServiceMetrics(service);
+
+            final Instances instances = verifyServiceInstances(service);
+
+            verifyInstancesMetrics(instances);
+
+            final Endpoints endpoints = verifyServiceEndpoints(service);
+            verifyEndpointsMetrics(endpoints);
+        }
+    }
+
+    @RetryableTest
+    void traces() throws Exception {
+        final List<Trace> traces = graphql.traces(new TracesQuery().start(startTime).end(now()).orderByDuration());
+
+        LOGGER.info("traces: {}", traces);
+
+        load("expected/go/traces.yml").as(TracesMatcher.class).verifyLoosely(traces);
+    }
+
+    @RetryableTest
+    void topology() throws Exception {
+        final Topology topology = graphql.topo(new TopoQuery().stepByMinute().start(startTime.minusDays(1)).end(now()));
+
+        LOGGER.info("topology: {}", topology);
+
+        load("expected/go/topo.yml").as(TopoMatcher.class).verify(topology);
+
+        verifyServiceRelationMetrics(topology.getCalls());
+    }
+
+    @RetryableTest
+    void serviceInstanceTopology() throws Exception {
+        final ServiceInstanceTopology topology = graphql.serviceInstanceTopo(
+            new ServiceInstanceTopologyQuery().stepByMinute()
+                                              .start(startTime.minusDays(1))
+                                              .end(now())
+                                              .clientServiceId("ZTJlLXNlcnZpY2UtamF2YS1jb25zdW1lcg==.1")
+                                              .serverServiceId("Z28yc2t5.1"));
+
+        LOGGER.info("instance topology: {}", topology);
+
+        load("expected/go/serviceInstanceTopo.yml").as(ServiceInstanceTopologyMatcher.class).verify(topology);
+
+        verifyServiceInstanceRelationMetrics(topology.getCalls());
+    }
+
+    private Instances verifyServiceInstances(final Service service) throws Exception {
+        final Instances instances = graphql.instances(
+            new InstancesQuery().serviceId(service.getKey()).start(startTime).end(now())
+        );
+
+        LOGGER.info("instances: {}", instances);
+        if (service.getLabel().equals(go2skyServiceName)) {
+            load("expected/go/instances-go.yml").as(InstancesMatcher.class).verify(instances);
+        } else {
+            load("expected/go/instances-java.yml").as(InstancesMatcher.class).verify(instances);
+        }
+
+        return instances;
+    }
+
+    private Endpoints verifyServiceEndpoints(final Service service) throws Exception {
+        final Endpoints endpoints = graphql.endpoints(new EndpointQuery().serviceId(service.getKey()));
+
+        LOGGER.info("endpoints: {}", endpoints);
+
+        switch (service.getLabel()) {
+            case go2skyServiceName: {
+                load("expected/go/endpoints-go2sky.yml").as(EndpointsMatcher.class).verify(endpoints);
+                break;
+            }
+            case javaProviderServiceName: {
+                load("expected/go/endpoints-provider.yml").as(EndpointsMatcher.class).verify(endpoints);
+                break;
+            }
+            case javaConsumerServiceName: {
+                load("expected/go/endpoints-consumer.yml").as(EndpointsMatcher.class).verify(endpoints);
+                break;
+            }
+            default:
+                throw new RuntimeException("unknown service: " + service.getLabel());
+        }
+        return endpoints;
+    }
+
+    private void verifyServiceMetrics(final Service service) throws Exception {
+        for (String metricName : ALL_SERVICE_METRICS) {
+            LOGGER.info("verifying service {}, metrics: {}", service, metricName);
+            final Metrics serviceMetrics = graphql.metrics(
+                new MetricsQuery().stepByMinute().metricsName(metricName).id(service.getKey())
+            );
+            LOGGER.info("serviceMetrics: {}", serviceMetrics);
+            final AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new AtLeastOneOfMetricsMatcher();
+            final MetricsValueMatcher greaterThanZero = new MetricsValueMatcher();
+            greaterThanZero.setValue("gt 0");
+            instanceRespTimeMatcher.setValue(greaterThanZero);
+            instanceRespTimeMatcher.verify(serviceMetrics);
+            LOGGER.info("{}: {}", metricName, serviceMetrics);
+        }
+    }
+
+    private void verifyInstancesMetrics(Instances instances) throws Exception {
+        for (Instance instance : instances.getInstances()) {
+            for (String metricsName : ALL_INSTANCE_METRICS) {
+                LOGGER.info("verifying service instance response time: {}", instance);
+                final Metrics instanceMetrics = graphql.metrics(
+                    new MetricsQuery().stepByMinute().metricsName(metricsName).id(instance.getKey())
+                );
+
+                LOGGER.info("instance metrics: {}", instanceMetrics);
+
+                final AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new AtLeastOneOfMetricsMatcher();
+                final MetricsValueMatcher greaterThanZero = new MetricsValueMatcher();
+                greaterThanZero.setValue("gt 0");
+                instanceRespTimeMatcher.setValue(greaterThanZero);
+                instanceRespTimeMatcher.verify(instanceMetrics);
+                LOGGER.info("{}: {}", metricsName, instanceMetrics);
+            }
+        }
+    }
+
+    private void verifyEndpointsMetrics(Endpoints endpoints) throws Exception {
+        for (Endpoint endpoint : endpoints.getEndpoints()) {
+            if (!endpoint.getLabel().equals("/info") && !endpoint.getLabel().equals("/nginx/info")) {
+                continue;
+            }
+            for (final String metricName : ALL_ENDPOINT_METRICS) {
+                LOGGER.info("verifying endpoint {}: {}", endpoint, metricName);
+
+                final Metrics metrics = graphql.metrics(
+                    new MetricsQuery().stepByMinute().metricsName(metricName).id(endpoint.getKey())
+                );
+
+                LOGGER.info("metrics: {}", metrics);
+
+                final AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new AtLeastOneOfMetricsMatcher();
+                final MetricsValueMatcher greaterThanZero = new MetricsValueMatcher();
+                greaterThanZero.setValue("gt 0");
+                instanceRespTimeMatcher.setValue(greaterThanZero);
+                instanceRespTimeMatcher.verify(metrics);
+
+                LOGGER.info("{}: {}", metricName, metrics);
+            }
+        }
+    }
+
+    private void verifyServiceInstanceRelationMetrics(final List<Call> calls) throws Exception {
+        verifyRelationMetrics(
+            calls, ALL_SERVICE_INSTANCE_RELATION_CLIENT_METRICS,
+            ALL_SERVICE_INSTANCE_RELATION_SERVER_METRICS
+        );
+    }
+
+    private void verifyServiceRelationMetrics(final List<Call> calls) throws Exception {
+        verifyRelationMetrics(calls, ALL_SERVICE_RELATION_CLIENT_METRICS, ALL_SERVICE_RELATION_SERVER_METRICS);
+    }
+
+    private void verifyRelationMetrics(final List<Call> calls,
+                                       final String[] relationClientMetrics,
+                                       final String[] relationServerMetrics) throws Exception {
+        for (Call call : calls) {
+            for (String detectPoint : call.getDetectPoints()) {
+                switch (detectPoint) {
+                    case "CLIENT": {
+                        for (String metricName : relationClientMetrics) {
+                            verifyMetrics(graphql, metricName, call.getId(), startTime);
+                        }
+                        break;
+                    }
+                    case "SERVER": {
+                        for (String metricName : relationServerMetrics) {
+                            verifyMetrics(graphql, metricName, call.getId(), startTime);
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/test/e2e/e2e-test/src/test/resources/expected/go/endpoints-consumer.yml b/test/e2e/e2e-test/src/test/resources/expected/go/endpoints-consumer.yml
new file mode 100644
index 0000000..650f2dc
--- /dev/null
+++ b/test/e2e/e2e-test/src/test/resources/expected/go/endpoints-consumer.yml
@@ -0,0 +1,18 @@
+# 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.
+
+endpoints:
+  - key: ZTJlLXNlcnZpY2UtamF2YS1jb25zdW1lcg==.1_L2luZm8=
+    label: /info
\ No newline at end of file
diff --git a/test/e2e/e2e-test/src/test/resources/expected/go/endpoints-go2sky.yml b/test/e2e/e2e-test/src/test/resources/expected/go/endpoints-go2sky.yml
new file mode 100644
index 0000000..038fa5d
--- /dev/null
+++ b/test/e2e/e2e-test/src/test/resources/expected/go/endpoints-go2sky.yml
@@ -0,0 +1,18 @@
+# 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.
+
+endpoints:
+  - key: Z28yc2t5.1_L1BPU1QvaW5mbw==
+    label: /POST/info
\ No newline at end of file
diff --git a/test/e2e/e2e-test/src/test/resources/expected/go/endpoints-provider.yml b/test/e2e/e2e-test/src/test/resources/expected/go/endpoints-provider.yml
new file mode 100644
index 0000000..0562bd2
--- /dev/null
+++ b/test/e2e/e2e-test/src/test/resources/expected/go/endpoints-provider.yml
@@ -0,0 +1,18 @@
+# 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.
+
+endpoints:
+  - key: ZTJlLXNlcnZpY2UtamF2YS1wcm92aWRlcg==.1_L2luZm8=
+    label: /info
\ No newline at end of file
diff --git a/test/e2e/e2e-test/src/test/resources/expected/go/instances-go.yml b/test/e2e/e2e-test/src/test/resources/expected/go/instances-go.yml
new file mode 100644
index 0000000..2f36f23
--- /dev/null
+++ b/test/e2e/e2e-test/src/test/resources/expected/go/instances-go.yml
@@ -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.
+
+instances:
+  - key: not null
+    label: not null
+    attributes:
+      - name: Process No.
+        value: gt 0
+      - name: hostname
+        value: not null
+      - name: OS Name
+        value: not null
+      - name: ipv4s
+        value: not null
\ No newline at end of file
diff --git a/test/e2e/e2e-test/src/test/resources/expected/go/instances-java.yml b/test/e2e/e2e-test/src/test/resources/expected/go/instances-java.yml
new file mode 100644
index 0000000..066bac6
--- /dev/null
+++ b/test/e2e/e2e-test/src/test/resources/expected/go/instances-java.yml
@@ -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.
+
+instances:
+  - key: not null
+    label: not null
+    attributes:
+      - name: OS Name
+        value: not null
+      - name: hostname
+        value: not null
+      - name: Process No.
+        value: gt 0
+      - name: ipv4s
+        value: not null
\ No newline at end of file
diff --git a/test/e2e/e2e-test/src/test/resources/expected/go/serviceInstanceTopo.yml b/test/e2e/e2e-test/src/test/resources/expected/go/serviceInstanceTopo.yml
new file mode 100644
index 0000000..cc66a86
--- /dev/null
+++ b/test/e2e/e2e-test/src/test/resources/expected/go/serviceInstanceTopo.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.
+
+nodes:
+  - id: not null
+    name: not null
+    type: ""
+    serviceId: ZTJlLXNlcnZpY2UtamF2YS1jb25zdW1lcg==.1
+    serviceName: e2e-service-java-consumer
+    isReal: true
+  - id: not null
+    name: not null
+    serviceId: Z28yc2t5.1
+    serviceName: go2sky
+    type: not null
+    isReal: true
+calls:
+  - id: not null
+    source: not null
+    detectPoints:
+      - CLIENT
+      - SERVER
+    target: not null
\ No newline at end of file
diff --git a/test/e2e/e2e-test/src/test/resources/expected/go/services.yml b/test/e2e/e2e-test/src/test/resources/expected/go/services.yml
new file mode 100644
index 0000000..b7fa809
--- /dev/null
+++ b/test/e2e/e2e-test/src/test/resources/expected/go/services.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.
+
+services:
+  - key: ZTJlLXNlcnZpY2UtamF2YS1wcm92aWRlcg==.1
+    label: "e2e-service-java-provider"
+  - key: Z28yc2t5.1
+    label: "go2sky"
+  - key: ZTJlLXNlcnZpY2UtamF2YS1jb25zdW1lcg==.1
+    label: "e2e-service-java-consumer"
diff --git a/test/e2e/e2e-test/src/test/resources/expected/go/topo.yml b/test/e2e/e2e-test/src/test/resources/expected/go/topo.yml
new file mode 100644
index 0000000..ab3a5e4
--- /dev/null
+++ b/test/e2e/e2e-test/src/test/resources/expected/go/topo.yml
@@ -0,0 +1,59 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+nodes:
+  - id: VXNlcg==.0
+    name: User
+    type: USER
+    isReal: false
+  - id: ZTJlLXNlcnZpY2UtamF2YS1jb25zdW1lcg==.1
+    name: e2e-service-java-consumer
+    type: Tomcat
+    isReal: true
+  - id: Z28yc2t5.1
+    name: go2sky
+    type: http
+    isReal: true
+  - id: ZTJlLXNlcnZpY2UtamF2YS1wcm92aWRlcg==.1
+    name: e2e-service-java-provider
+    type: Tomcat
+    isReal: true
+  - id: bG9jYWxob3N0Oi0x.0
+    name: localhost:-1
+    type: H2
+    isReal: false
+calls:
+  - id: VXNlcg==.0-ZTJlLXNlcnZpY2UtamF2YS1jb25zdW1lcg==.1
+    source: VXNlcg==.0
+    detectPoints:
+      - SERVER
+    target: ZTJlLXNlcnZpY2UtamF2YS1jb25zdW1lcg==.1
+  - id: ZTJlLXNlcnZpY2UtamF2YS1jb25zdW1lcg==.1-Z28yc2t5.1
+    source: ZTJlLXNlcnZpY2UtamF2YS1jb25zdW1lcg==.1
+    detectPoints:
+      - CLIENT
+      - SERVER
+    target: Z28yc2t5.1
+  - id: Z28yc2t5.1-ZTJlLXNlcnZpY2UtamF2YS1wcm92aWRlcg==.1
+    source: Z28yc2t5.1
+    detectPoints:
+      - CLIENT
+      - SERVER
+    target: ZTJlLXNlcnZpY2UtamF2YS1wcm92aWRlcg==.1
+  - id: ZTJlLXNlcnZpY2UtamF2YS1wcm92aWRlcg==.1-bG9jYWxob3N0Oi0x.0
+    source: ZTJlLXNlcnZpY2UtamF2YS1wcm92aWRlcg==.1
+    detectPoints:
+      - CLIENT
+    target: bG9jYWxob3N0Oi0x.0
\ No newline at end of file
diff --git a/test/e2e/e2e-test/src/test/resources/expected/go/traces.yml b/test/e2e/e2e-test/src/test/resources/expected/go/traces.yml
new file mode 100644
index 0000000..9cab9bf
--- /dev/null
+++ b/test/e2e/e2e-test/src/test/resources/expected/go/traces.yml
@@ -0,0 +1,24 @@
+# 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:
+      - /info
+    duration: ge 0
+    start: gt 0
+    isError: false
+    traceIds:
+      - not null
\ No newline at end of file