From c164b9ca4d0fca9a1d6bf1be2738147fb632a073 Mon Sep 17 00:00:00 2001 From: Ray Tsang Date: Mon, 9 Sep 2019 18:11:47 -0700 Subject: [PATCH] Added integration test for Stackdriver Storage with autoconfiguration (#143) * Added integration test for Stackdriver Storage with autoconfiguration * Fix integration tests to validate results returned from stackdriver * Gate decryption w/ secure env var --- .travis.yml | 5 +- autoconfigure/storage-stackdriver/pom.xml | 44 ++++++ .../ITZipkinStackdriverStorage.java | 139 ++++++++++++++++++ pom.xml | 3 +- sender-stackdriver/pom.xml | 2 +- .../stackdriver/ITStackdriverSender.java | 6 +- 6 files changed, 194 insertions(+), 5 deletions(-) create mode 100644 autoconfigure/storage-stackdriver/src/test/java/zipkin2/storage/stackdriver/ITZipkinStackdriverStorage.java diff --git a/.travis.yml b/.travis.yml index 207ffd00..f144445e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,10 @@ before_install: # Encrypted service account file for integration testing # This file is referenced via GOOGLE_APPLICATION_CREDENTIALS env var # Ex. travis encrypt-file travis/zipkin-gcp-ci-0d7917f58da7.json - - openssl aes-256-cbc -K $encrypted_0d0e64b78c84_key -iv $encrypted_0d0e64b78c84_iv -in travis/zipkin-gcp-ci-0d7917f58da7.json.enc -out travis/zipkin-gcp-ci-0d7917f58da7.json -d + # Only attempt to decrypt secret when it's not a PR and has access to secure env var + - if [ "$TRAVIS_SECURE_ENV_VARS" == "true" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ]; then + openssl aes-256-cbc -K $encrypted_0d0e64b78c84_key -iv $encrypted_0d0e64b78c84_iv -in travis/zipkin-gcp-ci-0d7917f58da7.json.enc -out travis/zipkin-gcp-ci-0d7917f58da7.json -d; + fi; # Override default travis to use the maven wrapper; skip license on travis due to #1512 install: ./mvnw install -DskipTests=true -Dlicense.skip=true -Dmaven.javadoc.skip=true -B -V diff --git a/autoconfigure/storage-stackdriver/pom.xml b/autoconfigure/storage-stackdriver/pom.xml index dd0eee0e..8f844da2 100644 --- a/autoconfigure/storage-stackdriver/pom.xml +++ b/autoconfigure/storage-stackdriver/pom.xml @@ -68,5 +68,49 @@ hamcrest-core test + + + io.zipkin.zipkin2 + zipkin-tests + test + + + + + io.grpc + grpc-core + ${grpc.version} + test + + + io.grpc + grpc-protobuf + ${grpc.version} + test + + + io.grpc + grpc-auth + ${grpc.version} + test + + + io.grpc + grpc-netty-shaded + ${grpc.version} + test + + + com.google.api.grpc + grpc-google-cloud-trace-v1 + ${grpc-google-cloud-trace.version} + test + + + org.awaitility + awaitility + ${awaitility.version} + test + diff --git a/autoconfigure/storage-stackdriver/src/test/java/zipkin2/storage/stackdriver/ITZipkinStackdriverStorage.java b/autoconfigure/storage-stackdriver/src/test/java/zipkin2/storage/stackdriver/ITZipkinStackdriverStorage.java new file mode 100644 index 00000000..72530cda --- /dev/null +++ b/autoconfigure/storage-stackdriver/src/test/java/zipkin2/storage/stackdriver/ITZipkinStackdriverStorage.java @@ -0,0 +1,139 @@ +/* + * Copyright 2016-2019 The OpenZipkin Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package zipkin2.storage.stackdriver; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.devtools.cloudtrace.v1.GetTraceRequest; +import com.google.devtools.cloudtrace.v1.Trace; +import com.google.devtools.cloudtrace.v1.TraceServiceGrpc; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; +import io.grpc.auth.MoreCallCredentials; +import org.awaitility.Duration; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import zipkin.autoconfigure.storage.stackdriver.ZipkinStackdriverStorageAutoConfiguration; +import zipkin.autoconfigure.storage.stackdriver.ZipkinStackdriverStorageProperties; +import zipkin2.Span; + +import java.io.File; +import java.io.IOException; +import java.util.Random; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assumptions.assumeThat; +import static org.assertj.core.api.Assumptions.assumeThatCode; +import static org.awaitility.Awaitility.await; +import static zipkin2.TestObjects.*; +import static zipkin2.TestObjects.TODAY; + +/** Integration test against Stackdriver Trace on a real GCP project */ +public class ITZipkinStackdriverStorage { + final String projectId = "zipkin-gcp-ci"; + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + StackdriverStorage storage; + ZipkinStackdriverStorageProperties storageProperties; + ManagedChannel channel; + TraceServiceGrpc.TraceServiceBlockingStub traceServiceGrpcV1; + + @BeforeEach + public void init() throws IOException { + // Application Default credential is configured using the GOOGLE_APPLICATION_CREDENTIALS env var + // See: https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application + + String credentialsPath = System.getenv("GOOGLE_APPLICATION_CREDENTIALS"); + assumeThat(credentialsPath).isNotBlank(); + assumeThat(new File(credentialsPath)).exists(); + assumeThatCode(GoogleCredentials::getApplicationDefault).doesNotThrowAnyException(); + + TestPropertyValues.of( + "zipkin.storage.type:stackdriver", + "zipkin.storage.stackdriver.project-id:" + projectId).applyTo(context); + context.register( + PropertyPlaceholderAutoConfiguration.class, + ZipkinStackdriverStorageAutoConfiguration.class); + context.refresh(); + storage = context.getBean(StackdriverStorage.class); + storageProperties = context.getBean(ZipkinStackdriverStorageProperties.class); + + GoogleCredentials credentials = GoogleCredentials.getApplicationDefault() + .createScoped("https://www.googleapis.com/auth/cloud-platform"); + + channel = ManagedChannelBuilder.forTarget("cloudtrace.googleapis.com") + .build(); + traceServiceGrpcV1 = TraceServiceGrpc.newBlockingStub(channel) + .withCallCredentials(MoreCallCredentials.from(credentials)); + + } + + @AfterEach + public void close() { + context.close(); + + if (channel != null) { + channel.shutdownNow(); + } + } + + @Test + public void healthCheck() { + assertThat(storage.check().ok()).isTrue(); + } + + @Test + public void spanConsumer() throws IOException { + Random random = new Random(); + Span span = Span.newBuilder() + .traceId(random.nextLong(), random.nextLong()) + .parentId("1") + .id("2") + .name("get") + .kind(Span.Kind.CLIENT) + .localEndpoint(FRONTEND) + .remoteEndpoint(BACKEND) + .timestamp((TODAY + 50L) * 1000L) + .duration(200000L) + .addAnnotation((TODAY + 100L) * 1000L, "foo") + .putTag("http.path", "/api") + .putTag("clnt/finagle.version", "6.45.0") + .build(); + + + storage.spanConsumer().accept(asList(span)).execute(); + + Trace trace = await() + .atLeast(Duration.ONE_SECOND) + .atMost(Duration.TEN_SECONDS) + .pollInterval(Duration.ONE_SECOND) + .ignoreExceptionsMatching(e -> + e instanceof StatusRuntimeException && + ((StatusRuntimeException) e).getStatus().getCode() == Status.Code.NOT_FOUND + ) + .until(() -> traceServiceGrpcV1.getTrace(GetTraceRequest.newBuilder() + .setProjectId(projectId) + .setTraceId(span.traceId()) + .build()), t -> t.getSpansCount() == 1); + + assertThat(trace.getSpans(0).getSpanId()).isEqualTo(2); + assertThat(trace.getSpans(0).getParentSpanId()).isEqualTo(1); + } + +} diff --git a/pom.xml b/pom.xml index 7cd0df4c..37522270 100644 --- a/pom.xml +++ b/pom.xml @@ -49,9 +49,10 @@ 2.16.2 2.10.2 5.6.10 - 1.22.1 + 1.22.2 28.0-jre 3.7.1 + 3.1.6 0.69.0 diff --git a/sender-stackdriver/pom.xml b/sender-stackdriver/pom.xml index b6020a43..b147ccc3 100644 --- a/sender-stackdriver/pom.xml +++ b/sender-stackdriver/pom.xml @@ -98,7 +98,7 @@ org.awaitility awaitility - 3.1.6 + ${awaitility.version} test diff --git a/sender-stackdriver/src/test/java/zipkin2/reporter/stackdriver/ITStackdriverSender.java b/sender-stackdriver/src/test/java/zipkin2/reporter/stackdriver/ITStackdriverSender.java index 6decceed..4a03cda9 100644 --- a/sender-stackdriver/src/test/java/zipkin2/reporter/stackdriver/ITStackdriverSender.java +++ b/sender-stackdriver/src/test/java/zipkin2/reporter/stackdriver/ITStackdriverSender.java @@ -37,6 +37,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assumptions.assumeThat; +import static org.assertj.core.api.Assumptions.assumeThatCode; import static org.awaitility.Awaitility.await; import static zipkin2.TestObjects.FRONTEND; import static zipkin2.TestObjects.BACKEND; @@ -60,6 +61,7 @@ public void setUp() throws IOException { String credentialsPath = System.getenv("GOOGLE_APPLICATION_CREDENTIALS"); assumeThat(credentialsPath).isNotBlank(); assumeThat(new File(credentialsPath)).exists(); + assumeThatCode(GoogleCredentials::getApplicationDefault).doesNotThrowAnyException(); credentials = GoogleCredentials.getApplicationDefault() .createScoped(Collections.singletonList("https://www.googleapis.com/auth/trace.append")); @@ -137,8 +139,8 @@ public void sendSpans() { .setTraceId(span.traceId()) .build()), t -> t.getSpansCount() == 1); - assertThat(span.id()).isEqualTo("0000000000000002"); - assertThat(span.parentId()).isEqualTo("0000000000000001"); + assertThat(trace.getSpans(0).getSpanId()).isEqualTo(2); + assertThat(trace.getSpans(0).getParentSpanId()).isEqualTo(1); } @Test