From 1d62be917cc5cba768d369defda95dbf47ea7700 Mon Sep 17 00:00:00 2001 From: samarth-gupta-traceable Date: Wed, 17 Feb 2021 15:51:40 +0530 Subject: [PATCH 01/11] Replicate smoke test from OTEL instrumentation --- build.gradle.kts | 1 + gradle/dependencies.gradle | 97 ++++++ gradle/java.gradle | 228 +++++++++++++ smoke-tests/build.gradle.kts | 12 +- .../agent/smoketest/AppServerTest.groovy | 322 ++++++++++++++++++ .../agent/smoketest/GrpcSmokeTest.groovy | 44 +++ .../smoketest/JaegerExporterSmokeTest.groovy | 51 +++ .../agent/smoketest/JettySmokeTest.groovy | 31 ++ .../LibertyServletOnlySmokeTest.groovy | 17 + .../agent/smoketest/LibertySmokeTest.groovy | 40 +++ .../agent/smoketest/PlaySmokeTest.groovy | 40 +++ .../agent/smoketest/PropagationTest.groovy | 121 +++++++ .../agent/smoketest/SmokeTest.groovy | 252 ++++++++++++++ .../agent/smoketest/TomcatSmokeTest.groovy | 28 ++ .../agent/smoketest/TomeeSmokeTest.groovy | 36 ++ .../agent/smoketest/TraceInspector.java | 105 ++++++ .../agent/smoketest/WildflySmokeTest.groovy | 52 +++ .../hypertrace/agent/smoketest/AppServer.java | 34 ++ .../agent/smoketest/AppServerTestRunner.java | 70 ++++ .../agent/smoketest/AppServers.java | 30 ++ .../src/test/resources/liberty-servlet.xml | 12 + smoke-tests/src/test/resources/otel.yaml | 34 ++ testing-common/build.gradle.kts | 1 + .../hypertrace/agent/testing/OkHttpUtils.java | 67 ++++ 24 files changed, 1724 insertions(+), 1 deletion(-) create mode 100644 gradle/dependencies.gradle create mode 100644 gradle/java.gradle create mode 100644 smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/AppServerTest.groovy create mode 100644 smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/GrpcSmokeTest.groovy create mode 100644 smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/JaegerExporterSmokeTest.groovy create mode 100644 smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/JettySmokeTest.groovy create mode 100644 smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/LibertyServletOnlySmokeTest.groovy create mode 100644 smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/LibertySmokeTest.groovy create mode 100644 smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/PlaySmokeTest.groovy create mode 100644 smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/PropagationTest.groovy create mode 100644 smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/SmokeTest.groovy create mode 100644 smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/TomcatSmokeTest.groovy create mode 100644 smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/TomeeSmokeTest.groovy create mode 100644 smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/TraceInspector.java create mode 100644 smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/WildflySmokeTest.groovy create mode 100644 smoke-tests/src/test/java/org/hypertrace/agent/smoketest/AppServer.java create mode 100644 smoke-tests/src/test/java/org/hypertrace/agent/smoketest/AppServerTestRunner.java create mode 100644 smoke-tests/src/test/java/org/hypertrace/agent/smoketest/AppServers.java create mode 100644 smoke-tests/src/test/resources/liberty-servlet.xml create mode 100644 smoke-tests/src/test/resources/otel.yaml create mode 100644 testing-common/src/main/java/org/hypertrace/agent/testing/OkHttpUtils.java diff --git a/build.gradle.kts b/build.gradle.kts index ca63a9633..fbd8ee939 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,6 +3,7 @@ plugins { id("com.diffplug.spotless") version "5.2.0" apply false id("org.hypertrace.publish-plugin") version "0.3.3" apply false id("org.hypertrace.ci-utils-plugin") version "0.1.4" + id("org.gradle.test-retry") version "1.2.0" apply false } allprojects { diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle new file mode 100644 index 000000000..03d1a649f --- /dev/null +++ b/gradle/dependencies.gradle @@ -0,0 +1,97 @@ +def groovyVer = "2.5.11" +def spockGroovyVer = groovyVer.replaceAll(/\.\d+$/, '') + +// this is only needed for the working against unreleased otel-java snapshots +configurations.all { + resolutionStrategy.cacheChangingModulesFor 12, 'hours' +} + +ext { + versions = [ + opentelemetry : '0.15.0', + opentelemetryAlpha: "0.15.0-alpha", + + slf4j : "1.7.30", + guava : "30.1-jre", + + spock : "1.3-groovy-$spockGroovyVer", + groovy : groovyVer, + logback : "1.2.3", + bytebuddy : "1.10.18", // Also explicitly specified in buildSrc + scala : "2.11.12", // Last version to support Java 7 (2.12+ require Java 8+) + kotlin : "1.4.0", + coroutines : "1.3.0", + springboot : "2.3.1.RELEASE", + // TODO(anuraaga): Switch off of milestones, this version fixes compatibility with Spock Unroll + junit5 : "5.7.0-M1", + checkerFramework : "3.6.1", + errorprone : "2.4.0", + nullaway : "0.8.0", + autoValue : "1.7.4", + systemLambda : "1.1.0", + prometheus : "0.9.0" + ] + + deps = [ + // OpenTelemetry + opentelemetryApi : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-api', version: versions.opentelemetry), + opentelemetryApiMetrics : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-api-metrics', version: versions.opentelemetryAlpha), + opentelemetryExtAnnotations : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-annotations', version: versions.opentelemetry), + opentelemetryContext : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-context', version: versions.opentelemetry), + opentelemetryKotlin : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-kotlin', version: versions.opentelemetry), + opentelemetryLogging : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-logging', version: versions.opentelemetry), + opentelemetryTraceProps : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-trace-propagators', version: versions.opentelemetry), + opentelemetrySdk : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk', version: versions.opentelemetry), + opentelemetrySdkAutoconfigure: dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-extension-autoconfigure', version: versions.opentelemetryAlpha), + opentelemetrySdkMetrics : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-metrics', version: versions.opentelemetryAlpha), + opentelemetryJaeger : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-jaeger', version: versions.opentelemetry), + opentelemetryOtlp : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-otlp', version: versions.opentelemetry), + opentelemetryOtlpMetrics : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-otlp-metrics', version: versions.opentelemetryAlpha), + opentelemetryZipkin : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-zipkin', version: versions.opentelemetry), + opentelemetryPrometheus : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-prometheus', version: versions.opentelemetryAlpha), + opentelemetryLogging : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-logging', version: versions.opentelemetry), + opentelemetryProto : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-proto', version: versions.opentelemetry), + opentelemetryResources : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-extension-resources', version: versions.opentelemetry), + opentelemetrySdkTesting : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-testing', version: versions.opentelemetry), + opentelemetrySemConv : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-semconv', version: versions.opentelemetryAlpha), + + // General + slf4j : "org.slf4j:slf4j-api:${versions.slf4j}", + guava : "com.google.guava:guava:$versions.guava", + bytebuddy : dependencies.create(group: 'net.bytebuddy', name: 'byte-buddy', version: "${versions.bytebuddy}"), + bytebuddyagent : dependencies.create(group: 'net.bytebuddy', name: 'byte-buddy-agent', version: "${versions.bytebuddy}"), + autoservice : [ + dependencies.create(group: 'com.google.auto.service', name: 'auto-service', version: '1.0-rc7'), + dependencies.create(group: 'com.google.auto', name: 'auto-common', version: '0.8'), + ], + autoValueAnnotations : "com.google.auto.value:auto-value-annotations:${versions.autoValue}", + // annotation processor + autoValue : "com.google.auto.value:auto-value:${versions.autoValue}", + prometheus : [ + dependencies.create(group: 'io.prometheus', name: 'simpleclient', version: "${versions.prometheus}"), + dependencies.create(group: 'io.prometheus', name: 'simpleclient_httpserver', version: "${versions.prometheus}"), + ], + + // Testing + + spock : [ + dependencies.create("org.spockframework:spock-core:${versions.spock}", { + exclude group: 'org.codehaus.groovy', module: 'groovy-all' + }), + // Used by Spock for mocking: + dependencies.create(group: 'org.objenesis', name: 'objenesis', version: '3.1') + ], + groovy : "org.codehaus.groovy:groovy-all:${versions.groovy}", + systemLambda : "com.github.stefanbirkner:system-lambda:${versions.systemLambda}", + testcontainers : "org.testcontainers:testcontainers:1.15.0-rc2", + testLogging : [ + dependencies.create(group: 'ch.qos.logback', name: 'logback-classic', version: versions.logback), + dependencies.create(group: 'org.slf4j', name: 'log4j-over-slf4j', version: versions.slf4j), + dependencies.create(group: 'org.slf4j', name: 'jcl-over-slf4j', version: versions.slf4j), + dependencies.create(group: 'org.slf4j', name: 'jul-to-slf4j', version: versions.slf4j), + ], + scala : dependencies.create(group: 'org.scala-lang', name: 'scala-library', version: "${versions.scala}"), + kotlin : dependencies.create(group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: "${versions.kotlin}"), + coroutines : dependencies.create(group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: "${versions.coroutines}"), + ] +} diff --git a/gradle/java.gradle b/gradle/java.gradle new file mode 100644 index 000000000..f39339635 --- /dev/null +++ b/gradle/java.gradle @@ -0,0 +1,228 @@ +import java.time.Duration + +apply plugin: 'java-library' +apply plugin: 'groovy' +apply plugin: 'org.gradle.test-retry' + +apply from: "$rootDir/gradle/dependencies.gradle" + +// Version to use to compile code and run tests. +def DEFAULT_JAVA_VERSION = 11 + + +/*java { + sourceCompatibility = JavaVersion.toVersion(project.ext.release) + targetCompatibility = JavaVersion.toVersion(project.ext.release) + + toolchain { + languageVersion = JavaLanguageVersion.of(Math.max(project.ext.release.majorVersion.toInteger(), DEFAULT_JAVA_VERSION)) + } + + // See https://docs.gradle.org/current/userguide/upgrading_version_5.html, Automatic target JVM version + disableAutoTargetJvm() + withJavadocJar() + withSourcesJar() +}*/ + +/*tasks.withType(JavaCompile) { + options.release = project.ext.release.majorVersion.toInteger() +} +tasks.withType(GroovyCompile) { + options.release = project.ext.release.majorVersion.toInteger() +} +tasks.withType(ScalaCompile) { + options.release = project.ext.release.majorVersion.toInteger() +}*/ + +/*apply plugin: "eclipse" +eclipse { + classpath { + downloadSources = true + downloadJavadoc = true + } +} +if (configurations.find { it.name == 'jmh' }) { + eclipse.classpath.plusConfigurations += [configurations.jmh] +}*/ + +jar { + /* + Make Jar build fail on duplicate files + + By default Gradle Jar task can put multiple files with the same name + into a Jar. This may lead to confusion. For example if auto-service + annotation processing creates files with same name in `scala` and + `java` directory this would result in Jar having two files with the + same name in it. Which in turn would result in only one of those + files being actually considered when that Jar is used leading to very + confusing failures. + + Instead we should 'fail early' and avoid building such Jars. + */ + duplicatesStrategy = 'fail' +} + +repositories { + mavenLocal() + mavenCentral() + jcenter() + maven { + url "https://repo.typesafe.com/typesafe/releases" + } + // this is only needed for the working against unreleased otel-java snapshots + maven { + url "https://oss.jfrog.org/artifactory/oss-snapshot-local" + content { + includeGroup "io.opentelemetry" + } + } +} + +dependencies { + compileOnly group: 'org.checkerframework', name: 'checker-qual', version: versions.checkerFramework + + testImplementation enforcedPlatform(group: 'org.junit', name: 'junit-bom', version: versions.junit5) + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api' + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-params' + testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine' + testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine' + + testImplementation deps.spock + testImplementation deps.groovy + testImplementation deps.testLogging + testImplementation group: 'info.solidsoft.spock', name: 'spock-global-unroll', version: '0.5.1' + testImplementation group: 'com.github.stefanbirkner', name: 'system-rules', version: '1.19.0' +} + +jar { + manifest { + attributes( + "Implementation-Title": project.name, + "Implementation-Version": project.version, + "Implementation-Vendor": "Hypertace", + "Implementation-URL": "https://github.com/hypertrace/hypertrace", + ) + } +} + +normalization { + runtimeClasspath { + metaInf { + ignoreAttribute("Implementation-Version") + } + } +} + +javadoc { + options.addStringOption('Xdoclint:none', '-quiet') + + doFirst { + if (project.ext.has("apiLinks")) { + options.links(*project.apiLinks) + } + } + source = sourceSets.main.allJava + classpath = configurations.compileClasspath + + options { + encoding = "utf-8" + docEncoding = "utf-8" + charSet = "utf-8" + + setMemberLevel JavadocMemberLevel.PUBLIC + setAuthor true + + links "https://docs.oracle.com/javase/8/docs/api/" + source = 8 + } +} + +project.afterEvaluate { + if (project.plugins.hasPlugin('org.unbroken-dome.test-sets') && configurations.hasProperty("latestDepTestRuntime")) { + tasks.withType(Test).configureEach { + doFirst { + def testArtifacts = configurations.testRuntimeClasspath.resolvedConfiguration.resolvedArtifacts + def latestTestArtifacts = configurations.latestDepTestRuntimeClasspath.resolvedConfiguration.resolvedArtifacts + assert testArtifacts != latestTestArtifacts: "latestDepTest dependencies are identical to test" + } + } + } +} + +def isJavaVersionAllowed(JavaVersion version) { + if (project.hasProperty('minJavaVersionForTests') && project.getProperty('minJavaVersionForTests').compareTo(version) > 0) { + return false + } + if (project.hasProperty('maxJavaVersionForTests') && project.getProperty('maxJavaVersionForTests').compareTo(version) < 0) { + return false + } + return true +} + +def testJavaVersion = rootProject.findProperty('testJavaVersion') +if (testJavaVersion != null) { + def requestedJavaVersion = JavaVersion.toVersion(testJavaVersion) + tasks.withType(Test).all { + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(requestedJavaVersion.majorVersion) + } + enabled = isJavaVersionAllowed(requestedJavaVersion) + } +} else { + // We default to testing with Java 11 for most tests, but some tests don't support it, where we change + // the default test task's version so commands like `./gradlew check` can test all projects regardless + // of Java version. + if (!isJavaVersionAllowed(JavaVersion.toVersion(DEFAULT_JAVA_VERSION))) { + tasks.withType(Test) { + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(project.getProperty('maxJavaVersionForTests').majorVersion) + } + } + } +} + +tasks.withType(Test).configureEach { + useJUnitPlatform() + + // All tests must complete within 15 minutes. + // This value is quite big because with lower values (3 mins) we were experiencing large number of false positives + timeout = Duration.ofMinutes(60) + + retry { + // You can see tests that were retried by this mechanism in the collected test reports and build scans. + maxRetries = System.getenv("CI") != null ? 5 : 0 + } + + reports { + junitXml.outputPerTestCase = true + } + + testLogging { + exceptionFormat = 'full' + } +} + +tasks.withType(AbstractArchiveTask) { + preserveFileTimestamps = false + reproducibleFileOrder = true +} + +plugins.withId('net.ltgt.errorprone') { + dependencies { + annotationProcessor group: "com.uber.nullaway", name: "nullaway", version: versions.nullaway + errorprone group: "com.google.errorprone", name: "error_prone_core", version: versions.errorprone + } + + tasks.withType(JavaCompile) { + if (!name.toLowerCase().contains("test")) { + options.errorprone { + error("NullAway") + + // Doesn't work well with Java 8 + disable("FutureReturnValueIgnored") + + option("NullAway:AnnotatedPackages", "io.opentelemetry,com.linecorp.armeria,com.google.common") + } + } + } +} diff --git a/smoke-tests/build.gradle.kts b/smoke-tests/build.gradle.kts index 94b3d2bfa..5fc395699 100644 --- a/smoke-tests/build.gradle.kts +++ b/smoke-tests/build.gradle.kts @@ -1,10 +1,16 @@ plugins { + groovy `java-library` } +apply { + from("$rootDir/gradle/java.gradle") +} + val versions: Map by extra dependencies{ + testImplementation(project(":testing-common")) testImplementation(project(":javaagent-core")) testImplementation("org.testcontainers:testcontainers:1.15.0") testImplementation("com.squareup.okhttp3:okhttp:4.9.0") @@ -12,6 +18,10 @@ dependencies{ testImplementation("io.opentelemetry:opentelemetry-proto:${versions["opentelemetry"]}") testImplementation("io.opentelemetry:opentelemetry-sdk:${versions["opentelemetry"]}") testImplementation("com.google.protobuf:protobuf-java-util:3.13.0") + testImplementation("org.spockframework:spock-core:1.3-groovy-2.5") + testImplementation("info.solidsoft.spock:spock-global-unroll:0.5.1") + testImplementation("com.fasterxml.jackson.core:jackson-databind:2.11.2") + testImplementation("org.codehaus.groovy:groovy-all:2.5.11") } tasks.test { @@ -26,4 +36,4 @@ tasks.test { doFirst { jvmArgs("-Dsmoketest.javaagent.path=${shadowTask.archiveFile.get()}") } -} +} \ No newline at end of file diff --git a/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/AppServerTest.groovy b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/AppServerTest.groovy new file mode 100644 index 000000000..a7929d209 --- /dev/null +++ b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/AppServerTest.groovy @@ -0,0 +1,322 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hypertrace.agent.smoketest + +import static org.junit.Assume.assumeTrue + +import io.opentelemetry.proto.trace.v1.Span +import java.util.jar.Attributes +import java.util.jar.JarFile +import okhttp3.Request +import org.junit.runner.RunWith +import spock.lang.Shared +import spock.lang.Unroll + +@RunWith(AppServerTestRunner) +abstract class AppServerTest extends SmokeTest { + @Shared + String jdk + @Shared + String serverVersion + + def setupSpec() { + def appServer = AppServerTestRunner.currentAppServer(this.getClass()) + serverVersion = appServer.version() + jdk = appServer.jdk() + startTarget(jdk, serverVersion) + } + + def cleanupSpec() { + stopTarget() + } + + boolean testSmoke() { + true + } + + boolean testAsyncSmoke() { + true + } + + boolean testException() { + true + } + + boolean testRequestWebInfWebXml() { + true + } + + //TODO add assert that server spans were created by servers, not by servlets + @Unroll + def "#appServer smoke test on JDK #jdk"(String appServer, String jdk) { + assumeTrue(testSmoke()) + + String url = "http://localhost:${target.getMappedPort(8080)}/app/greeting" + def request = new Request.Builder().url(url).get().build() + //def currentAgentVersion = new JarFile(agentPath).getManifest().getMainAttributes().get(Attributes.Name + //.IMPLEMENTATION_VERSION) + + when: + def response = CLIENT.newCall(request).execute() + TraceInspector traces = new TraceInspector(waitForTraces()) + Set traceIds = traces.traceIds + String responseBody = response.body().string() + + println traces.getSpanStream().forEach({ span -> "************** " + span.toString() + " *******************************" }); + + then: "There is one trace" + traceIds.size() == 1 + + and: "trace id is present in the HTTP headers as reported by the called endpoint" + responseBody.contains(traceIds.find()) + + and: "Server spans in the distributed trace" + traces.countSpansByKind(Span.SpanKind.SPAN_KIND_SERVER) == 2 + + and: "Expected span names" + traces.countSpansByName(getSpanName('/app/greeting')) == 1 + traces.countSpansByName(getSpanName('/app/headers')) == 1 + + and: "The span for the initial web request" + traces.countFilteredAttributes("http.url", url) == 1 + + and: "Client and server spans for the remote call" + traces.countFilteredAttributes("http.url", "http://localhost:8080/app/headers") == 2 + + cleanup: + response?.close() + + where: + [appServer, jdk] << getTestParams() + } + + @Unroll + def "#appServer test static file found on JDK #jdk"(String appServer, String jdk) { + String url = "http://localhost:${target.getMappedPort(8080)}/app/hello.txt" + def request = new Request.Builder().url(url).get().build() + //def currentAgentVersion = new JarFile(agentPath).getManifest().getMainAttributes().get(Attributes.Name + //.IMPLEMENTATION_VERSION) + + when: + def response = CLIENT.newCall(request).execute() + TraceInspector traces = new TraceInspector(waitForTraces()) + Set traceIds = traces.traceIds + String responseBody = response.body().string() + + then: "There is one trace" + traceIds.size() == 1 + + and: "Response contains Hello" + responseBody.contains("Hello") + + and: "There is one server span" + traces.countSpansByKind(Span.SpanKind.SPAN_KIND_SERVER) == 1 + + and: "Expected span names" + traces.countSpansByName(getSpanName('/app/hello.txt')) == 1 + + and: "The span for the initial web request" + traces.countFilteredAttributes("http.url", url) == 1 + + cleanup: + response?.close() + + where: + [appServer, jdk] << getTestParams() + } + + @Unroll + def "#appServer test static file not found on JDK #jdk"(String appServer, String jdk) { + String url = "http://localhost:${target.getMappedPort(8080)}/app/file-that-does-not-exist" + def request = new Request.Builder().url(url).get().build() + //def currentAgentVersion = new JarFile(agentPath).getManifest().getMainAttributes().get(Attributes.Name + //.IMPLEMENTATION_VERSION) + + when: + def response = CLIENT.newCall(request).execute() + TraceInspector traces = new TraceInspector(waitForTraces()) + Set traceIds = traces.traceIds + + then: "There is one trace" + traceIds.size() == 1 + + and: "Response code is 404" + response.code() == 404 + + and: "There is one server span" + traces.countSpansByKind(Span.SpanKind.SPAN_KIND_SERVER) == 1 + + and: "Expected span names" + traces.countSpansByName(getSpanName('/app/file-that-does-not-exist')) == 1 + + and: "The span for the initial web request" + traces.countFilteredAttributes("http.url", url) == 1 + + cleanup: + response?.close() + + where: + [appServer, jdk] << getTestParams() + } + + @Unroll + def "#appServer test request for WEB-INF/web.xml on JDK #jdk"(String appServer, String jdk) { + assumeTrue(testRequestWebInfWebXml()) + + String url = "http://localhost:${target.getMappedPort(8080)}/app/WEB-INF/web.xml" + def request = new Request.Builder().url(url).get().build() + //def currentAgentVersion = new JarFile(agentPath).getManifest().getMainAttributes().get(Attributes.Name + //.IMPLEMENTATION_VERSION) + + when: + def response = CLIENT.newCall(request).execute() + TraceInspector traces = new TraceInspector(waitForTraces()) + Set traceIds = traces.traceIds + + then: "There is one trace" + traceIds.size() == 1 + + and: "Response code is 404" + response.code() == 404 + + and: "There is one server span" + traces.countSpansByKind(Span.SpanKind.SPAN_KIND_SERVER) == 1 + + and: "Expected span names" + traces.countSpansByName(getSpanName('/app/WEB-INF/web.xml')) == 1 + + and: "The span for the initial web request" + traces.countFilteredAttributes("http.url", url) == 1 + + cleanup: + response?.close() + + where: + [appServer, jdk] << getTestParams() + } + + @Unroll + def "#appServer test request with error JDK #jdk"(String appServer, String jdk) { + assumeTrue(testException()) + + String url = "http://localhost:${target.getMappedPort(8080)}/app/exception" + def request = new Request.Builder().url(url).get().build() + //def currentAgentVersion = new JarFile(agentPath).getManifest().getMainAttributes().get(Attributes.Name + //.IMPLEMENTATION_VERSION) + + when: + def response = CLIENT.newCall(request).execute() + TraceInspector traces = new TraceInspector(waitForTraces()) + Set traceIds = traces.traceIds + + then: "There is one trace" + traceIds.size() == 1 + + and: "Response code is 500" + response.code() == 500 + + and: "There is one server span" + traces.countSpansByKind(Span.SpanKind.SPAN_KIND_SERVER) == 1 + + and: "Expected span names" + traces.countSpansByName(getSpanName('/app/exception')) == 1 + + and: "There is one exception" + traces.countFilteredEventAttributes('exception.message', 'This is expected') == 1 + + and: "The span for the initial web request" + traces.countFilteredAttributes("http.url", url) == 1 + + cleanup: + response?.close() + + where: + [appServer, jdk] << getTestParams() + } + + @Unroll + def "#appServer test request outside deployed application JDK #jdk"(String appServer, String jdk) { + String url = "http://localhost:${target.getMappedPort(8080)}/this-is-definitely-not-there-but-there-should-be-a-trace-nevertheless" + def request = new Request.Builder().url(url).get().build() + //def currentAgentVersion = new JarFile(agentPath).getManifest().getMainAttributes().get(Attributes.Name + //.IMPLEMENTATION_VERSION) + + when: + def response = CLIENT.newCall(request).execute() + TraceInspector traces = new TraceInspector(waitForTraces()) + Set traceIds = traces.traceIds + + then: "There is one trace" + traceIds.size() == 1 + + and: "Response code is 404" + response.code() == 404 + + and: "There is one server span" + traces.countSpansByKind(Span.SpanKind.SPAN_KIND_SERVER) == 1 + + and: "Expected span names" + traces.countSpansByName(getSpanName('/this-is-definitely-not-there-but-there-should-be-a-trace-nevertheless')) == 1 + + and: "The span for the initial web request" + traces.countFilteredAttributes("http.url", url) == 1 + + cleanup: + response?.close() + + where: + [appServer, jdk] << getTestParams() + } + + @Unroll + def "#appServer async smoke test on JDK #jdk"(String appServer, String jdk) { + assumeTrue(testAsyncSmoke()) + + String url = "http://localhost:${target.getMappedPort(8080)}/app/asyncgreeting" + def request = new Request.Builder().url(url).get().build() + //def currentAgentVersion = new JarFile(agentPath).getManifest().getMainAttributes().get(Attributes.Name + //.IMPLEMENTATION_VERSION) + + when: + def response = CLIENT.newCall(request).execute() + TraceInspector traces = new TraceInspector(waitForTraces()) + Set traceIds = traces.traceIds + String responseBody = response.body().string() + + then: "There is one trace" + traceIds.size() == 1 + + and: "trace id is present in the HTTP headers as reported by the called endpoint" + responseBody.contains(traceIds.find()) + + and: "Server spans in the distributed trace" + traces.countSpansByKind(Span.SpanKind.SPAN_KIND_SERVER) == 2 + + and: "Expected span names" + traces.countSpansByName(getSpanName('/app/asyncgreeting')) == 1 + traces.countSpansByName(getSpanName('/app/headers')) == 1 + + and: "The span for the initial web request" + traces.countFilteredAttributes("http.url", url) == 1 + + and: "Client and server spans for the remote call" + traces.countFilteredAttributes("http.url", "http://localhost:8080/app/headers") == 2 + + cleanup: + response?.close() + + where: + [appServer, jdk] << getTestParams() + } + + protected abstract String getSpanName(String path); + + protected List> getTestParams() { + return [ + [serverVersion, jdk] + ] + } +} \ No newline at end of file diff --git a/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/GrpcSmokeTest.groovy b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/GrpcSmokeTest.groovy new file mode 100644 index 000000000..afe0dee9d --- /dev/null +++ b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/GrpcSmokeTest.groovy @@ -0,0 +1,44 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hypertrace.agent.smoketest + +import io.grpc.ManagedChannelBuilder +import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest +import io.opentelemetry.proto.collector.trace.v1.TraceServiceGrpc +import spock.lang.Unroll + +class GrpcSmokeTest extends SmokeTest { + + protected String getTargetImage(String jdk, String serverVersion) { + "ghcr.io/open-telemetry/java-test-containers:smoke-grpc-jdk$jdk-20210129.520311770" + } + + @Unroll + def "grpc smoke test on JDK #jdk"(int jdk) { + setup: + startTarget(jdk) + + def channel = ManagedChannelBuilder.forAddress("localhost", target.getMappedPort(8080)) + .usePlaintext() + .build() + def stub = TraceServiceGrpc.newBlockingStub(channel) + + when: + stub.export(ExportTraceServiceRequest.getDefaultInstance()) + Collection traces = waitForTraces() + + then: + countSpansByName(traces, 'opentelemetry.proto.collector.trace.v1.TraceService/Export') == 1 + countSpansByName(traces, 'TestService.withSpan') == 1 + + cleanup: + stopTarget() + channel.shutdown() + + where: + jdk << [8, 11, 15] + } +} diff --git a/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/JaegerExporterSmokeTest.groovy b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/JaegerExporterSmokeTest.groovy new file mode 100644 index 000000000..4a2946acc --- /dev/null +++ b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/JaegerExporterSmokeTest.groovy @@ -0,0 +1,51 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hypertrace.agent.smoketest + +import static java.util.stream.Collectors.toSet + +import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest +import java.util.jar.Attributes +import java.util.jar.JarFile +import okhttp3.Request + +class JaegerExporterSmokeTest extends SmokeTest { + + protected String getTargetImage(String jdk, String serverVersion) { + "ghcr.io/open-telemetry/java-test-containers:smoke-springboot-jdk$jdk-20210129.520311771" + } + + @Override + protected Map getExtraEnv() { + return [ + "OTEL_TRACES_EXPORTER" : "jaeger", + "OTEL_EXPORTER_JAEGER_ENDPOINT" : "collector:14250" + ] + } + + def "spring boot smoke test with jaeger grpc"() { + setup: + startTarget(11) + + String url = "http://localhost:${target.getMappedPort(8080)}/greeting" + def request = new Request.Builder().url(url).get().build() + + when: + def response = CLIENT.newCall(request).execute() + Collection traces = waitForTraces() + + then: + response.body().string() == "Hi!" + countSpansByName(traces, '/greeting') == 1 + countSpansByName(traces, 'WebController.greeting') == 1 + countSpansByName(traces, 'WebController.withSpan') == 1 + + cleanup: + stopTarget() + + } + +} diff --git a/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/JettySmokeTest.groovy b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/JettySmokeTest.groovy new file mode 100644 index 000000000..e2ea5062c --- /dev/null +++ b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/JettySmokeTest.groovy @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hypertrace.agent.smoketest + +@AppServer(version = "9.4.35", jdk = "8") +@AppServer(version = "9.4.35", jdk = "11") +@AppServer(version = "10.0.0", jdk = "11") +@AppServer(version = "10.0.0", jdk = "15") +class JettySmokeTest extends AppServerTest { + + protected String getTargetImage(String jdk, String serverVersion) { + "ghcr.io/open-telemetry/java-test-containers:jetty-${serverVersion}-jdk$jdk-20201215.422527843" + } + + def getJettySpanName() { + return serverVersion.startsWith("10.") ? "HandlerList.handle" : "HandlerCollection.handle" + } + + @Override + protected String getSpanName(String path) { + switch (path) { + case "/app/WEB-INF/web.xml": + case "/this-is-definitely-not-there-but-there-should-be-a-trace-nevertheless": + return getJettySpanName() + } + return path + } +} diff --git a/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/LibertyServletOnlySmokeTest.groovy b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/LibertyServletOnlySmokeTest.groovy new file mode 100644 index 000000000..e2d69bbca --- /dev/null +++ b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/LibertyServletOnlySmokeTest.groovy @@ -0,0 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hypertrace.agent.smoketest + +import org.testcontainers.containers.BindMode +import org.testcontainers.containers.GenericContainer + +@AppServer(version = "20.0.0.12", jdk = "8") +class LibertyServletOnlySmokeTest extends LibertySmokeTest { + + protected void customizeContainer(GenericContainer container) { + container.withClasspathResourceMapping("liberty-servlet.xml", "/config/server.xml", BindMode.READ_ONLY) + } +} diff --git a/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/LibertySmokeTest.groovy b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/LibertySmokeTest.groovy new file mode 100644 index 000000000..2fe241bf0 --- /dev/null +++ b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/LibertySmokeTest.groovy @@ -0,0 +1,40 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hypertrace.agent.smoketest + +import java.time.Duration +import org.testcontainers.containers.wait.strategy.Wait +import org.testcontainers.containers.wait.strategy.WaitStrategy + +@AppServer(version = "20.0.0.12", jdk = "8") +@AppServer(version = "20.0.0.12", jdk = "11") +@AppServer(version = "20.0.0.12", jdk = "8-jdk-openj9") +@AppServer(version = "20.0.0.12", jdk = "11-jdk-openj9") +class LibertySmokeTest extends AppServerTest { + + protected String getTargetImage(String jdk, String serverVersion) { + "ghcr.io/open-telemetry/java-test-containers:liberty-${serverVersion}-jdk$jdk-20201215.422527843" + } + + @Override + protected WaitStrategy getWaitStrategy() { + return Wait + .forLogMessage(".*server is ready to run a smarter planet.*", 1) + .withStartupTimeout(Duration.ofMinutes(3)) + } + + @Override + protected String getSpanName(String path) { + switch (path) { + case "/app/greeting": + case "/app/headers": + case "/app/exception": + case "/app/asyncgreeting": + return path + } + return 'HTTP GET' + } +} diff --git a/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/PlaySmokeTest.groovy b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/PlaySmokeTest.groovy new file mode 100644 index 000000000..2c9d66920 --- /dev/null +++ b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/PlaySmokeTest.groovy @@ -0,0 +1,40 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hypertrace.agent.smoketest + +import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest +import okhttp3.Request + +class PlaySmokeTest extends SmokeTest { + + protected String getTargetImage(String jdk, String serverVersion) { + "ghcr.io/open-telemetry/java-test-containers:smoke-play-jdk$jdk-20201128.1734635" + } + + def "play smoke test on JDK #jdk"(int jdk) { + setup: + startTarget(jdk) + String url = "http://localhost:${target.getMappedPort(8080)}/welcome?id=1" + def request = new Request.Builder().url(url).get().build() + + when: + def response = CLIENT.newCall(request).execute() + Collection traces = waitForTraces() + + then: + response.body().string() == "Welcome 1." + //Both play and akka-http support produce spans with the same name. + //One internal, one SERVER + countSpansByName(traces, '/welcome') == 2 + + cleanup: + stopTarget() + + where: + jdk << [8, 11, 15] + } + +} diff --git a/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/PropagationTest.groovy b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/PropagationTest.groovy new file mode 100644 index 000000000..fc2af7e1b --- /dev/null +++ b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/PropagationTest.groovy @@ -0,0 +1,121 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hypertrace.agent.smoketest + +import static java.util.stream.Collectors.toSet + +import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest +import okhttp3.Request + +abstract class PropagationTest extends SmokeTest { + + @Override + protected String getTargetImage(String jdk, String serverVersion) { + "ghcr.io/open-telemetry/java-test-containers:smoke-springboot-jdk$jdk-20210129.520311771" + } + + def "Should propagate test"() { + setup: + startTarget(11) + String url = "http://localhost:${target.getMappedPort(8080)}/front" + def request = new Request.Builder().url(url).get().build() + + when: + def response = CLIENT.newCall(request).execute() + Collection traces = waitForTraces() + def traceIds = getSpanStream(traces) + .map({ bytesToHex(it.getTraceId().toByteArray()) }) + .collect(toSet()) + + then: + traceIds.size() == 1 + + def traceId = traceIds.first() + + response.body().string() == "${traceId};${traceId}" + + cleanup: + stopTarget() + + } + +} + +class DefaultPropagationTest extends PropagationTest { +} + +class W3CPropagationTest extends PropagationTest { + @Override + protected Map getExtraEnv() { + return ["otel.propagators": "tracecontext"] + } +} + +class B3PropagationTest extends PropagationTest { + @Override + protected Map getExtraEnv() { + return ["otel.propagators": "b3"] + } +} + +class B3MultiPropagationTest extends PropagationTest { + @Override + protected Map getExtraEnv() { + return ["otel.propagators": "b3multi"] + } +} + +class JaegerPropagationTest extends PropagationTest { + @Override + protected Map getExtraEnv() { + return ["otel.propagators": "jaeger"] + } +} + +class OtTracerPropagationTest extends SmokeTest { + @Override + protected String getTargetImage(String jdk, String serverVersion) { + "ghcr.io/open-telemetry/java-test-containers:smoke-springboot-jdk$jdk-20210129.520311771" + } + + // OtTracer only propagates lower half of trace ID so we have to mangle the trace IDs similar to + // the Lightstep backend. + def "Should propagate test"() { + setup: + startTarget(11) + String url = "http://localhost:${target.getMappedPort(8080)}/front" + def request = new Request.Builder().url(url).get().build() + + when: + def response = CLIENT.newCall(request).execute() + Collection traces = waitForTraces() + def traceIds = getSpanStream(traces) + .map({ bytesToHex(it.getTraceId().toByteArray()).substring(16) }) + .collect(toSet()) + + then: + traceIds.size() == 1 + + def traceId = traceIds.first() + + response.body().string().matches(/[0-9a-f]{16}${traceId};[0]{16}${traceId}/) + + cleanup: + stopTarget() + } + + @Override + protected Map getExtraEnv() { + return ["otel.propagators": "ottracer"] + } +} + +class XRayPropagationTest extends PropagationTest { + @Override + protected Map getExtraEnv() { + return ["otel.propagators": "xray"] + } +} diff --git a/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/SmokeTest.groovy b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/SmokeTest.groovy new file mode 100644 index 000000000..ca02908d6 --- /dev/null +++ b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/SmokeTest.groovy @@ -0,0 +1,252 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hypertrace.agent.smoketest + +import org.hypertrace.agent.testing.OkHttpUtils + +import static java.util.stream.Collectors.toSet + +import com.fasterxml.jackson.databind.ObjectMapper +import com.google.protobuf.util.JsonFormat +import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest +import io.opentelemetry.proto.common.v1.AnyValue +import io.opentelemetry.proto.trace.v1.Span +import java.util.concurrent.TimeUnit +import java.util.regex.Pattern +import java.util.stream.Stream +import okhttp3.OkHttpClient +import okhttp3.Request +import org.slf4j.LoggerFactory +import org.testcontainers.containers.GenericContainer +import org.testcontainers.containers.Network +import org.testcontainers.containers.output.Slf4jLogConsumer +import org.testcontainers.containers.output.ToStringConsumer +import org.testcontainers.containers.wait.strategy.Wait +import org.testcontainers.containers.wait.strategy.WaitStrategy +import org.testcontainers.images.PullPolicy +import org.testcontainers.utility.MountableFile +import spock.lang.Shared +import spock.lang.Specification + +abstract class SmokeTest extends Specification { + private static final Pattern TRACE_ID_PATTERN = Pattern.compile(".*traceId=(?[a-zA-Z0-9]+).*") + + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() + + protected static final OkHttpClient CLIENT = OkHttpUtils.client() + + @Shared + private Network network = Network.newNetwork() + @Shared + protected String agentPath = System.getProperty("smoketest.javaagent.path") + + @Shared + protected GenericContainer target + + protected abstract String getTargetImage(String jdk, String serverVersion) + + /** + * Subclasses can override this method to customise target application's environment + */ + protected Map getExtraEnv() { + return Collections.emptyMap() + } + + /** + * Subclasses can override this method to customise target application's environment + */ + protected void customizeContainer(GenericContainer container) { + } + + @Shared + private GenericContainer backend + + @Shared + private GenericContainer collector + + def setupSpec() { + backend = new GenericContainer<>("ghcr.io/open-telemetry/java-test-containers:smoke-fake-backend-20201128.1734635") + .withExposedPorts(8080) + .waitingFor(Wait.forHttp("/health").forPort(8080)) + .withNetwork(network) + .withNetworkAliases("backend") + .withImagePullPolicy(PullPolicy.alwaysPull()) + .withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger("smoke.tests.backend"))) + backend.start() + + collector = new GenericContainer<>("otel/opentelemetry-collector-dev:latest") + .dependsOn(backend) + .withNetwork(network) + .withNetworkAliases("collector") + .withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger("smoke.tests.collector"))) + .withImagePullPolicy(PullPolicy.alwaysPull()) + .withCopyFileToContainer(MountableFile.forClasspathResource("/otel.yaml"), "/etc/otel.yaml") + .withCommand("--config /etc/otel.yaml") + collector.start() + } + + def startTarget(int jdk, String serverVersion = null) { + startTarget(String.valueOf(jdk), serverVersion) + } + + def startTarget(String jdk, String serverVersion = null) { + def output = new ToStringConsumer() + target = new GenericContainer<>(getTargetImage(jdk, serverVersion)) + .withExposedPorts(8080) + .withNetwork(network) + .withLogConsumer(output) + .withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger("smoke.tests.target"))) + //.withCopyFileToContainer(MountableFile.forHostPath("/Users/samarth/Downloads/hypertrace-agent-all.jar"""), +//"""/opentelemetry-javaagent-all.jar") + .withCopyFileToContainer(MountableFile.forHostPath(agentPath), "/hypertrace-agent-all.jar") + .withEnv("JAVA_TOOL_OPTIONS", "-javaagent:/hypertrace-agent-all.jar -Dorg.hypertrace.agent.slf4j.simpleLogger.log.muzzleMatcher=true") + .withEnv("OTEL_BSP_MAX_EXPORT_BATCH_SIZE", "1") + .withEnv("OTEL_BSP_SCHEDULE_DELAY_MILLIS", "10") + .withEnv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://collector:55680") + .withEnv("HT_SERVICE_NAME", "CIService") + .withEnv("HT_REPORTING_ENDPOINT", "http://collector:9411/api/v2/spans") + .withEnv("OTEL_TRACE_EXPORTER", "otlp") + .withImagePullPolicy(PullPolicy.alwaysPull()) + .withEnv(extraEnv) + customizeContainer(target) + + WaitStrategy waitStrategy = getWaitStrategy() + if (waitStrategy != null) { + target = target.waitingFor(waitStrategy) + } + + target.start() + output + } + + protected WaitStrategy getWaitStrategy() { + return null + } + + def cleanup() { + CLIENT.newCall(new Request.Builder() + .url("http://localhost:${backend.getMappedPort(8080)}/clear-requests") + .build()) + .execute() + .close() + } + + def stopTarget() { + target.stop() + } + + def cleanupSpec() { + backend.stop() + collector.stop() + network.close() + } + + protected static Stream findResourceAttribute(Collection traces, + String attributeKey) { + return traces.stream() + .flatMap { it.getResourceSpansList().stream() } + .flatMap { it.getResource().getAttributesList().stream() } + .filter { it.key == attributeKey } + .map { it.value } + } + + protected static int countSpansByName(Collection traces, String spanName) { + return getSpanStream(traces).filter { it.name == spanName }.count() + } + + protected static Stream getSpanStream(Collection traces) { + return traces.stream() + .flatMap { it.getResourceSpansList().stream() } + .flatMap { it.getInstrumentationLibrarySpansList().stream() } + .flatMap { it.getSpansList().stream() } + } + + protected Collection waitForTraces() { + def content = waitForContent() + + return OBJECT_MAPPER.readTree(content).collect { + def builder = ExportTraceServiceRequest.newBuilder() + // TODO(anuraaga): Register parser into object mapper to avoid de -> re -> deserialize. + JsonFormat.parser().merge(OBJECT_MAPPER.writeValueAsString(it), builder) + return builder.build() + } + } + + private String waitForContent() { + long previousSize = 0 + long deadline = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(30) + String content = "[]" + while (System.currentTimeMillis() < deadline) { + def body = content = CLIENT.newCall(new Request.Builder() + .url("http://localhost:${backend.getMappedPort(8080)}/get-requests") + .build()) + .execute() + .body() + try { + content = body.string() + } finally { + body.close() + } + if (content.length() > 2 && content.length() == previousSize) { + break + } + previousSize = content.length() + println "Curent content size $previousSize" + TimeUnit.MILLISECONDS.sleep(500) + } + + return content + } + + protected static Set getLoggedTraceIds(ToStringConsumer output) { + output.toUtf8String().lines() + .flatMap(SmokeTest.&findTraceId) + .collect(toSet()) + } + + private static Stream findTraceId(String log) { + def m = TRACE_ID_PATTERN.matcher(log) + m.matches() ? Stream.of(m.group("traceId")) : Stream.empty() as Stream + } + + protected static boolean isVersionLogged(ToStringConsumer output, String version) { + output.toUtf8String().lines() + .filter({ it.contains("opentelemetry-javaagent - version: " + version) }) + .findFirst() + .isPresent() + } + + // TODO(anuraaga): Delete after https://github.com/open-telemetry/opentelemetry-java/pull/2750 + static String bytesToHex(byte[] bytes) { + char[] dest = new char[bytes.length * 2] + bytesToBase16(bytes, dest) + return new String(dest) + } + + private static void bytesToBase16(byte[] bytes, char[] dest) { + for (int i = 0; i < bytes.length; i++) { + byteToBase16(bytes[i], dest, i * 2) + } + } + + private static void byteToBase16(byte value, char[] dest, int destOffset) { + int b = value & 0xFF + dest[destOffset] = ENCODING[b] + dest[destOffset + 1] = ENCODING[b | 0x100] + } + + private static final String ALPHABET = "0123456789abcdef" + private static final char[] ENCODING = buildEncodingArray() + + private static char[] buildEncodingArray() { + char[] encoding = new char[512] + for (int i = 0; i < 256; ++i) { + encoding[i] = ALPHABET.charAt(i >>> 4) + encoding[i | 0x100] = ALPHABET.charAt(i & 0xF) + } + return encoding + } +} diff --git a/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/TomcatSmokeTest.groovy b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/TomcatSmokeTest.groovy new file mode 100644 index 000000000..fa310b586 --- /dev/null +++ b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/TomcatSmokeTest.groovy @@ -0,0 +1,28 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hypertrace.agent.smoketest + +@AppServer(version = "7.0.107", jdk = "8") +@AppServer(version = "8.5.60", jdk = "8") +@AppServer(version = "8.5.60", jdk = "11") +@AppServer(version = "9.0.40", jdk = "8") +@AppServer(version = "9.0.40", jdk = "11") +class TomcatSmokeTest extends AppServerTest { + + protected String getTargetImage(String jdk, String serverVersion) { + "ghcr.io/open-telemetry/java-test-containers:tomcat-${serverVersion}-jdk$jdk-20201215.422527843" + } + + @Override + protected String getSpanName(String path) { + switch (path) { + case "/app/WEB-INF/web.xml": + case "/this-is-definitely-not-there-but-there-should-be-a-trace-nevertheless": + return "CoyoteAdapter.service" + } + return path + } +} diff --git a/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/TomeeSmokeTest.groovy b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/TomeeSmokeTest.groovy new file mode 100644 index 000000000..ce5719a27 --- /dev/null +++ b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/TomeeSmokeTest.groovy @@ -0,0 +1,36 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hypertrace.agent.smoketest + +import java.time.Duration +import org.testcontainers.containers.wait.strategy.Wait +import org.testcontainers.containers.wait.strategy.WaitStrategy + +@AppServer(version = "7.0.0", jdk = "8") +@AppServer(version = "8.0.6", jdk = "8") +@AppServer(version = "8.0.6", jdk = "11") +class TomeeSmokeTest extends AppServerTest { + + protected String getTargetImage(String jdk, String serverVersion) { + "ghcr.io/open-telemetry/java-test-containers:tomee-${serverVersion}-jdk$jdk-20210202.531569197" + } + + @Override + protected WaitStrategy getWaitStrategy() { + return Wait + .forLogMessage(".*Server startup in.*", 1) + .withStartupTimeout(Duration.ofMinutes(3)) + } + + @Override + protected String getSpanName(String path) { + switch (path) { + case "/app/WEB-INF/web.xml": + return "CoyoteAdapter.service" + } + return path + } +} diff --git a/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/TraceInspector.java b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/TraceInspector.java new file mode 100644 index 000000000..e876dc20d --- /dev/null +++ b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/TraceInspector.java @@ -0,0 +1,105 @@ +/* + * Copyright The Hypertrace 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 org.hypertrace.agent.smoketest; + +import com.google.protobuf.ByteString; +import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest; +import io.opentelemetry.proto.common.v1.AnyValue; +import io.opentelemetry.proto.common.v1.KeyValue; +import io.opentelemetry.proto.trace.v1.ResourceSpans; +import io.opentelemetry.proto.trace.v1.Span; +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class TraceInspector { + final Collection traces; + + public TraceInspector(Collection traces) { + this.traces = traces; + } + + public Stream getSpanStream() { + return traces.stream() + .flatMap(it -> it.getResourceSpansList().stream()) + .flatMap(it -> it.getInstrumentationLibrarySpansList().stream()) + .flatMap(it -> it.getSpansList().stream()); + } + + public Stream findResourceAttribute(String attributeKey) { + return traces.stream() + .flatMap(it -> it.getResourceSpansList().stream()) + .flatMap(it -> it.getResource().getAttributesList().stream()) + .filter(it -> it.getKey().equals(attributeKey)) + .map(KeyValue::getValue); + } + + public long countFilteredResourceAttributes(String attributeName, Object attributeValue) { + return traces.stream() + .flatMap(it -> it.getResourceSpansList().stream()) + .map(ResourceSpans::getResource) + .flatMap(it -> it.getAttributesList().stream()) + .filter(a -> a.getKey().equals(attributeName)) + .map(a -> a.getValue().getStringValue()) + .filter(s -> s.equals(attributeValue)) + .count(); + } + + public long countFilteredAttributes(String attributeName, Object attributeValue) { + return getSpanStream() + .flatMap(s -> s.getAttributesList().stream()) + .filter(a -> a.getKey().equals(attributeName)) + .map(a -> a.getValue().getStringValue()) + .filter(s -> s.equals(attributeValue)) + .count(); + } + + public long countFilteredEventAttributes(String attributeName, Object attributeValue) { + return getSpanStream() + .flatMap(s -> s.getEventsList().stream()) + .flatMap(e -> e.getAttributesList().stream()) + .filter(a -> a.getKey().equals(attributeName)) + .map(a -> a.getValue().getStringValue()) + .filter(s -> s.equals(attributeValue)) + .count(); + } + + protected int countSpansByName(String spanName) { + return (int) getSpanStream().filter(it -> it.getName().equals(spanName)).count(); + } + + protected int countSpansByKind(Span.SpanKind spanKind) { + return (int) getSpanStream().filter(it -> it.getKind().equals(spanKind)).count(); + } + + protected int countSpans() { + return (int) getSpanStream().count(); + } + + public int size() { + return traces.size(); + } + + public Set getTraceIds() { + return getSpanStream() + .map(Span::getTraceId) + .map(ByteString::toByteArray) + .map(SmokeTest::bytesToHex) + .collect(Collectors.toSet()); + } +} diff --git a/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/WildflySmokeTest.groovy b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/WildflySmokeTest.groovy new file mode 100644 index 000000000..8e576d5d0 --- /dev/null +++ b/smoke-tests/src/test/groovy/org/hypertrace/agent/smoketest/WildflySmokeTest.groovy @@ -0,0 +1,52 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.hypertrace.agent.smoketest + +import io.opentelemetry.proto.trace.v1.Span +import okhttp3.Request +import spock.lang.Unroll + +@AppServer(version = "13.0.0.Final", jdk = "8") +@AppServer(version = "17.0.1.Final", jdk = "11") +@AppServer(version = "21.0.0.Final", jdk = "11") +class WildflySmokeTest extends AppServerTest { + + protected String getTargetImage(String jdk, String serverVersion) { + "ghcr.io/open-telemetry/java-test-containers:wildfly-${serverVersion}-jdk$jdk-20201215.422527843" + } + + @Override + protected String getSpanName(String path) { + switch (path) { + case "/app/WEB-INF/web.xml": + case "/this-is-definitely-not-there-but-there-should-be-a-trace-nevertheless": + return "DisallowedMethodsHandler.handleRequest" + } + return path + } + + @Unroll + def "JSP smoke test on WildFly"() { + String url = "http://localhost:${target.getMappedPort(8080)}/app/jsp" + def request = new Request.Builder().url(url).get().build() + + when: + def response = CLIENT.newCall(request).execute() + TraceInspector traces = new TraceInspector(waitForTraces()) + String responseBody = response.body().string() + + then: + response.successful + responseBody.contains("Successful JSP test") + + traces.countSpansByKind(Span.SpanKind.SPAN_KIND_SERVER) == 1 + + traces.countSpansByName('/app/jsp') == 1 + + where: + [appServer, jdk] << getTestParams() + } +} diff --git a/smoke-tests/src/test/java/org/hypertrace/agent/smoketest/AppServer.java b/smoke-tests/src/test/java/org/hypertrace/agent/smoketest/AppServer.java new file mode 100644 index 000000000..45bbc6c74 --- /dev/null +++ b/smoke-tests/src/test/java/org/hypertrace/agent/smoketest/AppServer.java @@ -0,0 +1,34 @@ +/* + * Copyright The Hypertrace 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 org.hypertrace.agent.smoketest; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Repeatable(org.hypertrace.agent.smoketest.AppServers.class) +@Inherited +public @interface AppServer { + String version(); + + String jdk(); +} diff --git a/smoke-tests/src/test/java/org/hypertrace/agent/smoketest/AppServerTestRunner.java b/smoke-tests/src/test/java/org/hypertrace/agent/smoketest/AppServerTestRunner.java new file mode 100644 index 000000000..3110e77e9 --- /dev/null +++ b/smoke-tests/src/test/java/org/hypertrace/agent/smoketest/AppServerTestRunner.java @@ -0,0 +1,70 @@ +/* + * Copyright The Hypertrace 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 org.hypertrace.agent.smoketest; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.model.InitializationError; +import org.spockframework.runtime.Sputnik; + +/** + * Customized spock test runner that runs tests on multiple app server versions based on {@link + * AppServer} annotations. This runner selects first server based on {@link AppServer} annotation + * calls setupSpec, all test method and cleanupSpec, selects next {@link AppServer} and calls the + * same methods. This process is repeated until tests have run for all {@link AppServer} + * annotations. Tests should start server in setupSpec and stop it in cleanupSpec. + */ +public class AppServerTestRunner extends Sputnik { + private static final Map, AppServer> runningAppServer = + Collections.synchronizedMap(new HashMap<>()); + private final Class testClass; + private final AppServer[] appServers; + + public AppServerTestRunner(Class clazz) throws InitializationError { + super(clazz); + testClass = clazz; + appServers = clazz.getAnnotationsByType(AppServer.class); + if (appServers.length == 0) { + throw new IllegalStateException("Add AppServer or AppServers annotation to test class"); + } + } + + @Override + public void run(RunNotifier notifier) { + // run tests for all app servers + try { + for (AppServer appServer : appServers) { + runningAppServer.put(testClass, appServer); + super.run(notifier); + } + } finally { + runningAppServer.remove(testClass); + } + } + + // expose currently running app server + // used to get current server and jvm version inside the test class + public static AppServer currentAppServer(Class testClass) { + AppServer appServer = runningAppServer.get(testClass); + if (appServer == null) { + throw new IllegalStateException("Test not running for " + testClass); + } + return appServer; + } +} diff --git a/smoke-tests/src/test/java/org/hypertrace/agent/smoketest/AppServers.java b/smoke-tests/src/test/java/org/hypertrace/agent/smoketest/AppServers.java new file mode 100644 index 000000000..788c333b8 --- /dev/null +++ b/smoke-tests/src/test/java/org/hypertrace/agent/smoketest/AppServers.java @@ -0,0 +1,30 @@ +/* + * Copyright The Hypertrace 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 org.hypertrace.agent.smoketest; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +public @interface AppServers { + AppServer[] value(); +} diff --git a/smoke-tests/src/test/resources/liberty-servlet.xml b/smoke-tests/src/test/resources/liberty-servlet.xml new file mode 100644 index 000000000..8157a50ba --- /dev/null +++ b/smoke-tests/src/test/resources/liberty-servlet.xml @@ -0,0 +1,12 @@ + + + + + servlet-4.0 + + + + + + + \ No newline at end of file diff --git a/smoke-tests/src/test/resources/otel.yaml b/smoke-tests/src/test/resources/otel.yaml new file mode 100644 index 000000000..8d38db49a --- /dev/null +++ b/smoke-tests/src/test/resources/otel.yaml @@ -0,0 +1,34 @@ +extensions: + health_check: + pprof: + endpoint: 0.0.0.0:1777 + zpages: + endpoint: 0.0.0.0:55679 + +receivers: + otlp: + protocols: + grpc: + zipkin: + jaeger: + protocols: + grpc: + +processors: + batch: + +exporters: + logging: + loglevel: debug + otlp: + endpoint: backend:8080 + insecure: true + +service: + pipelines: + traces: + receivers: [otlp, zipkin, jaeger] + processors: [batch] + exporters: [logging, otlp] + + extensions: [health_check, pprof, zpages] diff --git a/testing-common/build.gradle.kts b/testing-common/build.gradle.kts index 4bc82931a..afcde5ad7 100644 --- a/testing-common/build.gradle.kts +++ b/testing-common/build.gradle.kts @@ -16,6 +16,7 @@ dependencies { api("io.opentelemetry:opentelemetry-sdk:${versions["opentelemetry"]}") compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:${versions["opentelemetry"]}-alpha") api("com.squareup.okhttp3:okhttp:4.9.0") + api("com.squareup.okhttp3:logging-interceptor:4.9.0") implementation("io.opentelemetry.javaagent:opentelemetry-javaagent-tooling:${versions["opentelemetry_java_agent"]}") implementation("io.opentelemetry.javaagent:opentelemetry-javaagent-spi:${versions["opentelemetry_java_agent"]}") implementation("io.opentelemetry.instrumentation:opentelemetry-instrumentation-api:${versions["opentelemetry_java_agent"]}") diff --git a/testing-common/src/main/java/org/hypertrace/agent/testing/OkHttpUtils.java b/testing-common/src/main/java/org/hypertrace/agent/testing/OkHttpUtils.java new file mode 100644 index 000000000..ba0fcf18a --- /dev/null +++ b/testing-common/src/main/java/org/hypertrace/agent/testing/OkHttpUtils.java @@ -0,0 +1,67 @@ +/* + * Copyright The Hypertrace 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 org.hypertrace.agent.testing; + +import java.util.concurrent.TimeUnit; +import okhttp3.OkHttpClient; +import okhttp3.logging.HttpLoggingInterceptor; +import okhttp3.logging.HttpLoggingInterceptor.Level; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class was moved from groovy to java because groovy kept trying to introspect on the + * OkHttpClient class which contains java 8 only classes, which caused the build to fail for java 7. + */ +public class OkHttpUtils { + + private static final Logger CLIENT_LOGGER = LoggerFactory.getLogger("http-client"); + + static { + ((ch.qos.logback.classic.Logger) CLIENT_LOGGER).setLevel(ch.qos.logback.classic.Level.DEBUG); + } + + private static final HttpLoggingInterceptor LOGGING_INTERCEPTOR = + new HttpLoggingInterceptor( + new HttpLoggingInterceptor.Logger() { + @Override + public void log(String message) { + CLIENT_LOGGER.debug(message); + } + }); + + static { + LOGGING_INTERCEPTOR.setLevel(Level.BASIC); + } + + static OkHttpClient.Builder clientBuilder() { + TimeUnit unit = TimeUnit.MINUTES; + return new OkHttpClient.Builder() + .addInterceptor(LOGGING_INTERCEPTOR) + .connectTimeout(1, unit) + .writeTimeout(1, unit) + .readTimeout(1, unit); + } + + public static OkHttpClient client() { + return client(false); + } + + public static OkHttpClient client(boolean followRedirects) { + return clientBuilder().followRedirects(followRedirects).build(); + } +} From 4b68a9c7b881b66614662058509f00498e7516db Mon Sep 17 00:00:00 2001 From: samarth-gupta-traceable Date: Wed, 17 Feb 2021 15:57:00 +0530 Subject: [PATCH 02/11] Remove redundant deps --- gradle/dependencies.gradle | 57 ++------------------------------------ gradle/java.gradle | 36 ------------------------ 2 files changed, 3 insertions(+), 90 deletions(-) diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 03d1a649f..73cd5c150 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -8,8 +8,6 @@ configurations.all { ext { versions = [ - opentelemetry : '0.15.0', - opentelemetryAlpha: "0.15.0-alpha", slf4j : "1.7.30", guava : "30.1-jre", @@ -17,60 +15,15 @@ ext { spock : "1.3-groovy-$spockGroovyVer", groovy : groovyVer, logback : "1.2.3", - bytebuddy : "1.10.18", // Also explicitly specified in buildSrc - scala : "2.11.12", // Last version to support Java 7 (2.12+ require Java 8+) - kotlin : "1.4.0", - coroutines : "1.3.0", - springboot : "2.3.1.RELEASE", + // TODO(anuraaga): Switch off of milestones, this version fixes compatibility with Spock Unroll - junit5 : "5.7.0-M1", - checkerFramework : "3.6.1", - errorprone : "2.4.0", - nullaway : "0.8.0", - autoValue : "1.7.4", - systemLambda : "1.1.0", - prometheus : "0.9.0" + junit5 : "5.7.0-M1" ] deps = [ - // OpenTelemetry - opentelemetryApi : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-api', version: versions.opentelemetry), - opentelemetryApiMetrics : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-api-metrics', version: versions.opentelemetryAlpha), - opentelemetryExtAnnotations : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-annotations', version: versions.opentelemetry), - opentelemetryContext : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-context', version: versions.opentelemetry), - opentelemetryKotlin : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-kotlin', version: versions.opentelemetry), - opentelemetryLogging : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-logging', version: versions.opentelemetry), - opentelemetryTraceProps : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-trace-propagators', version: versions.opentelemetry), - opentelemetrySdk : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk', version: versions.opentelemetry), - opentelemetrySdkAutoconfigure: dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-extension-autoconfigure', version: versions.opentelemetryAlpha), - opentelemetrySdkMetrics : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-metrics', version: versions.opentelemetryAlpha), - opentelemetryJaeger : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-jaeger', version: versions.opentelemetry), - opentelemetryOtlp : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-otlp', version: versions.opentelemetry), - opentelemetryOtlpMetrics : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-otlp-metrics', version: versions.opentelemetryAlpha), - opentelemetryZipkin : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-zipkin', version: versions.opentelemetry), - opentelemetryPrometheus : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-prometheus', version: versions.opentelemetryAlpha), - opentelemetryLogging : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-logging', version: versions.opentelemetry), - opentelemetryProto : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-proto', version: versions.opentelemetry), - opentelemetryResources : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-extension-resources', version: versions.opentelemetry), - opentelemetrySdkTesting : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-testing', version: versions.opentelemetry), - opentelemetrySemConv : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-semconv', version: versions.opentelemetryAlpha), // General slf4j : "org.slf4j:slf4j-api:${versions.slf4j}", - guava : "com.google.guava:guava:$versions.guava", - bytebuddy : dependencies.create(group: 'net.bytebuddy', name: 'byte-buddy', version: "${versions.bytebuddy}"), - bytebuddyagent : dependencies.create(group: 'net.bytebuddy', name: 'byte-buddy-agent', version: "${versions.bytebuddy}"), - autoservice : [ - dependencies.create(group: 'com.google.auto.service', name: 'auto-service', version: '1.0-rc7'), - dependencies.create(group: 'com.google.auto', name: 'auto-common', version: '0.8'), - ], - autoValueAnnotations : "com.google.auto.value:auto-value-annotations:${versions.autoValue}", - // annotation processor - autoValue : "com.google.auto.value:auto-value:${versions.autoValue}", - prometheus : [ - dependencies.create(group: 'io.prometheus', name: 'simpleclient', version: "${versions.prometheus}"), - dependencies.create(group: 'io.prometheus', name: 'simpleclient_httpserver', version: "${versions.prometheus}"), - ], // Testing @@ -82,16 +35,12 @@ ext { dependencies.create(group: 'org.objenesis', name: 'objenesis', version: '3.1') ], groovy : "org.codehaus.groovy:groovy-all:${versions.groovy}", - systemLambda : "com.github.stefanbirkner:system-lambda:${versions.systemLambda}", testcontainers : "org.testcontainers:testcontainers:1.15.0-rc2", testLogging : [ dependencies.create(group: 'ch.qos.logback', name: 'logback-classic', version: versions.logback), dependencies.create(group: 'org.slf4j', name: 'log4j-over-slf4j', version: versions.slf4j), dependencies.create(group: 'org.slf4j', name: 'jcl-over-slf4j', version: versions.slf4j), dependencies.create(group: 'org.slf4j', name: 'jul-to-slf4j', version: versions.slf4j), - ], - scala : dependencies.create(group: 'org.scala-lang', name: 'scala-library', version: "${versions.scala}"), - kotlin : dependencies.create(group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: "${versions.kotlin}"), - coroutines : dependencies.create(group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: "${versions.coroutines}"), + ] ] } diff --git a/gradle/java.gradle b/gradle/java.gradle index f39339635..ab36bd51f 100644 --- a/gradle/java.gradle +++ b/gradle/java.gradle @@ -9,42 +9,6 @@ apply from: "$rootDir/gradle/dependencies.gradle" // Version to use to compile code and run tests. def DEFAULT_JAVA_VERSION = 11 - -/*java { - sourceCompatibility = JavaVersion.toVersion(project.ext.release) - targetCompatibility = JavaVersion.toVersion(project.ext.release) - - toolchain { - languageVersion = JavaLanguageVersion.of(Math.max(project.ext.release.majorVersion.toInteger(), DEFAULT_JAVA_VERSION)) - } - - // See https://docs.gradle.org/current/userguide/upgrading_version_5.html, Automatic target JVM version - disableAutoTargetJvm() - withJavadocJar() - withSourcesJar() -}*/ - -/*tasks.withType(JavaCompile) { - options.release = project.ext.release.majorVersion.toInteger() -} -tasks.withType(GroovyCompile) { - options.release = project.ext.release.majorVersion.toInteger() -} -tasks.withType(ScalaCompile) { - options.release = project.ext.release.majorVersion.toInteger() -}*/ - -/*apply plugin: "eclipse" -eclipse { - classpath { - downloadSources = true - downloadJavadoc = true - } -} -if (configurations.find { it.name == 'jmh' }) { - eclipse.classpath.plusConfigurations += [configurations.jmh] -}*/ - jar { /* Make Jar build fail on duplicate files From bfecca1c1d0b7bef9732388ade6f03a9edd56619 Mon Sep 17 00:00:00 2001 From: samarth-gupta-traceable Date: Wed, 17 Feb 2021 16:01:34 +0530 Subject: [PATCH 03/11] Add all deps --- gradle/dependencies.gradle | 57 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index 73cd5c150..03d1a649f 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -8,6 +8,8 @@ configurations.all { ext { versions = [ + opentelemetry : '0.15.0', + opentelemetryAlpha: "0.15.0-alpha", slf4j : "1.7.30", guava : "30.1-jre", @@ -15,15 +17,60 @@ ext { spock : "1.3-groovy-$spockGroovyVer", groovy : groovyVer, logback : "1.2.3", - + bytebuddy : "1.10.18", // Also explicitly specified in buildSrc + scala : "2.11.12", // Last version to support Java 7 (2.12+ require Java 8+) + kotlin : "1.4.0", + coroutines : "1.3.0", + springboot : "2.3.1.RELEASE", // TODO(anuraaga): Switch off of milestones, this version fixes compatibility with Spock Unroll - junit5 : "5.7.0-M1" + junit5 : "5.7.0-M1", + checkerFramework : "3.6.1", + errorprone : "2.4.0", + nullaway : "0.8.0", + autoValue : "1.7.4", + systemLambda : "1.1.0", + prometheus : "0.9.0" ] deps = [ + // OpenTelemetry + opentelemetryApi : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-api', version: versions.opentelemetry), + opentelemetryApiMetrics : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-api-metrics', version: versions.opentelemetryAlpha), + opentelemetryExtAnnotations : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-annotations', version: versions.opentelemetry), + opentelemetryContext : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-context', version: versions.opentelemetry), + opentelemetryKotlin : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-kotlin', version: versions.opentelemetry), + opentelemetryLogging : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-logging', version: versions.opentelemetry), + opentelemetryTraceProps : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-trace-propagators', version: versions.opentelemetry), + opentelemetrySdk : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk', version: versions.opentelemetry), + opentelemetrySdkAutoconfigure: dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-extension-autoconfigure', version: versions.opentelemetryAlpha), + opentelemetrySdkMetrics : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-metrics', version: versions.opentelemetryAlpha), + opentelemetryJaeger : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-jaeger', version: versions.opentelemetry), + opentelemetryOtlp : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-otlp', version: versions.opentelemetry), + opentelemetryOtlpMetrics : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-otlp-metrics', version: versions.opentelemetryAlpha), + opentelemetryZipkin : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-zipkin', version: versions.opentelemetry), + opentelemetryPrometheus : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-prometheus', version: versions.opentelemetryAlpha), + opentelemetryLogging : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-logging', version: versions.opentelemetry), + opentelemetryProto : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-proto', version: versions.opentelemetry), + opentelemetryResources : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-extension-resources', version: versions.opentelemetry), + opentelemetrySdkTesting : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-testing', version: versions.opentelemetry), + opentelemetrySemConv : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-semconv', version: versions.opentelemetryAlpha), // General slf4j : "org.slf4j:slf4j-api:${versions.slf4j}", + guava : "com.google.guava:guava:$versions.guava", + bytebuddy : dependencies.create(group: 'net.bytebuddy', name: 'byte-buddy', version: "${versions.bytebuddy}"), + bytebuddyagent : dependencies.create(group: 'net.bytebuddy', name: 'byte-buddy-agent', version: "${versions.bytebuddy}"), + autoservice : [ + dependencies.create(group: 'com.google.auto.service', name: 'auto-service', version: '1.0-rc7'), + dependencies.create(group: 'com.google.auto', name: 'auto-common', version: '0.8'), + ], + autoValueAnnotations : "com.google.auto.value:auto-value-annotations:${versions.autoValue}", + // annotation processor + autoValue : "com.google.auto.value:auto-value:${versions.autoValue}", + prometheus : [ + dependencies.create(group: 'io.prometheus', name: 'simpleclient', version: "${versions.prometheus}"), + dependencies.create(group: 'io.prometheus', name: 'simpleclient_httpserver', version: "${versions.prometheus}"), + ], // Testing @@ -35,12 +82,16 @@ ext { dependencies.create(group: 'org.objenesis', name: 'objenesis', version: '3.1') ], groovy : "org.codehaus.groovy:groovy-all:${versions.groovy}", + systemLambda : "com.github.stefanbirkner:system-lambda:${versions.systemLambda}", testcontainers : "org.testcontainers:testcontainers:1.15.0-rc2", testLogging : [ dependencies.create(group: 'ch.qos.logback', name: 'logback-classic', version: versions.logback), dependencies.create(group: 'org.slf4j', name: 'log4j-over-slf4j', version: versions.slf4j), dependencies.create(group: 'org.slf4j', name: 'jcl-over-slf4j', version: versions.slf4j), dependencies.create(group: 'org.slf4j', name: 'jul-to-slf4j', version: versions.slf4j), - ] + ], + scala : dependencies.create(group: 'org.scala-lang', name: 'scala-library', version: "${versions.scala}"), + kotlin : dependencies.create(group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: "${versions.kotlin}"), + coroutines : dependencies.create(group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: "${versions.coroutines}"), ] } From 757e9e2ccdd8f55d1af6ddbf67782135e9cdde5b Mon Sep 17 00:00:00 2001 From: samarth-gupta-traceable Date: Wed, 17 Feb 2021 16:23:15 +0530 Subject: [PATCH 04/11] Increase no outout timeout --- .circleci/config.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5f1a544cb..f44c7e487 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -63,7 +63,9 @@ jobs: steps: - setup_build_environment - populate_and_save_cache - - run: make smoke-test + - run: + no_output_timeout: 30m + command: make smoke-test muzzle: docker: From cb4fb51bab491a49999c8eeb92a328d3d9f9470d Mon Sep 17 00:00:00 2001 From: samarth-gupta-traceable Date: Wed, 17 Feb 2021 18:44:14 +0530 Subject: [PATCH 05/11] Add debug to smoke test --- .circleci/config.yml | 2 +- Makefile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f44c7e487..b1df8c82c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -64,7 +64,7 @@ jobs: - setup_build_environment - populate_and_save_cache - run: - no_output_timeout: 30m + no_output_timeout: 10m command: make smoke-test muzzle: diff --git a/Makefile b/Makefile index 8934e4aae..6d876e1ca 100644 --- a/Makefile +++ b/Makefile @@ -7,11 +7,11 @@ assemble: .PHONY: build build: - ./gradlew build -x :smoke-tests:test --stacktrace + ./gradlew build -x :smoke-tests:test --debug --stacktrace .PHONY: smoke-test smoke-test: - ./gradlew :smoke-tests:test --stacktrace + ./gradlew :smoke-tests:test --debug --stacktrace .PHONY: muzzle muzzle: From 4a9ff340d7c95a5a9a9a69c9b8e53e4d02ff58cf Mon Sep 17 00:00:00 2001 From: samarth-gupta-traceable Date: Wed, 17 Feb 2021 20:20:19 +0530 Subject: [PATCH 06/11] Delete circle CI config. Add github action pr build --- .circleci/config.yml | 148 --------------------------------- .github/workflows/pr-build.yml | 0 2 files changed, 148 deletions(-) delete mode 100644 .circleci/config.yml create mode 100644 .github/workflows/pr-build.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index b1df8c82c..000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,148 +0,0 @@ -version: 2.1 - -executors: - gradle_docker: - docker: - - image: cimg/openjdk:11.0 - auth: - username: $DOCKERHUB_USERNAME - password: $DOCKERHUB_PASSWORD - -commands: - setup_build_environment: - description: "Checkout, update submodules, restore the cache, and setup docker" - steps: - - checkout - - run: - name: Generate cache key - command: find . -type f -name "*.gradle*" -o -name "gradle-wrapper*" -exec shasum {} + | sort > /tmp/checksum.txt && cat /tmp/checksum.txt - - run: make init-submodules - - restore_cache: - keys: - - v1-dependencies-{{ checksum "/tmp/checksum.txt" }} - # fallback to using the latest cache if no exact match is found - - v1-dependencies- - docker_login: - description: "Login to dockerhub with readonly credentials" - steps: - - run: - name: Dockerhub login - command: echo $DOCKER_PASSWORD | docker login --username $DOCKER_USERNAME --password-stdin - populate_and_save_cache: - description: "Downloads all gradle dependencies and uploads cache for later use" - steps: - - run: ./gradlew downloadDependencies - - save_cache: - paths: - - ~/.gradle - key: v1-dependencies-{{ checksum "/tmp/checksum.txt" }} - -jobs: - build: - docker: - - image: cimg/openjdk:11.0 - working_directory: ~/repo - environment: - # Customize the JVM maximum heap limit - JVM_OPTS: -Xmx1g - TERM: dumb - steps: - - setup_build_environment - - populate_and_save_cache - - run: make build - - smoke-test: - # For testcontainers.org - machine: - image: ubuntu-1604:202007-01 - working_directory: ~/repo - environment: - # Customize the JVM maximum heap limit - JVM_OPTS: -Xmx1g - TERM: dumb - steps: - - setup_build_environment - - populate_and_save_cache - - run: - no_output_timeout: 10m - command: make smoke-test - - muzzle: - docker: - - image: cimg/openjdk:11.0 - working_directory: ~/repo - environment: - # Customize the JVM maximum heap limit - JVM_OPTS: -Xmx1g - TERM: dumb - steps: - - setup_build_environment - - run: make muzzle - - release-bintray-publish: - executor: gradle_docker - steps: - - setup_build_environment - - setup_remote_docker: - version: 19.03.13 - - docker_login - - run: echo "Releasing version" && ./gradlew printVersion - - run: ./gradlew publish - - run: DOCKER_TAG=${CIRCLE_TAG} make docker docker-push - - run: - name: "Copy artifacts to workspace" - command: | - mkdir artifacts - cp javaagent/build/libs/*-all.jar artifacts/hypertrace-agent-all.jar - - persist_to_workspace: - root: . - paths: - - artifacts - - release-github-publish: - docker: - - image: cibuilds/github:0.13 - steps: - - attach_workspace: - at: . - - run: - name: "Publish Release on GitHub" - command: | - ghr -t ${GH_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -n "Release ${CIRCLE_TAG}" -b "..." --soft ${CIRCLE_TAG} ./artifacts/ - -workflows: - version: 2 - build-and-publish: - jobs: - - build: - filters: - tags: - only: /.*/ - - smoke-test: - filters: - tags: - only: /.*/ - - muzzle: - filters: - tags: - only: /.*/ - - release-bintray-publish: - context: hypertrace-publishing - requires: - - build - - muzzle - - smoke-test - filters: - branches: - ignore: /.*/ - tags: - only: /^[0-9]+\.[0-9]+\.[0-9]+/ - - release-github-publish: - context: hypertrace-publishing - requires: - - release-bintray-publish - filters: - branches: - ignore: /.*/ - tags: - only: /^[0-9]+\.[0-9]+\.[0-9]+/ diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml new file mode 100644 index 000000000..e69de29bb From e7b2abe2a5a5c344c640e4e7b02bf5c182dbfb15 Mon Sep 17 00:00:00 2001 From: samarth-gupta-traceable Date: Wed, 17 Feb 2021 20:36:29 +0530 Subject: [PATCH 07/11] Put back circle CI --- .circleci/config.yml | 147 +++++++++++++++++++++++++++++++++ .github/workflows/pr-build.yml | 0 Makefile | 4 +- smoke-tests/build.gradle.kts | 1 + 4 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 .circleci/config.yml delete mode 100644 .github/workflows/pr-build.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 000000000..a38ebc9a3 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,147 @@ +version: 2.1 + +executors: + gradle_docker: + docker: + - image: cimg/openjdk:11.0 + auth: + username: $DOCKERHUB_USERNAME + password: $DOCKERHUB_PASSWORD + +commands: + setup_build_environment: + description: "Checkout, update submodules, restore the cache, and setup docker" + steps: + - checkout + - run: + name: Generate cache key + command: find . -type f -name "*.gradle*" -o -name "gradle-wrapper*" -exec shasum {} + | sort > /tmp/checksum.txt && cat /tmp/checksum.txt + - run: make init-submodules + - restore_cache: + keys: + - v1-dependencies-{{ checksum "/tmp/checksum.txt" }} + # fallback to using the latest cache if no exact match is found + - v1-dependencies- + docker_login: + description: "Login to dockerhub with readonly credentials" + steps: + - run: + name: Dockerhub login + command: echo $DOCKER_PASSWORD | docker login --username $DOCKER_USERNAME --password-stdin + populate_and_save_cache: + description: "Downloads all gradle dependencies and uploads cache for later use" + steps: + - run: ./gradlew downloadDependencies + - save_cache: + paths: + - ~/.gradle + key: v1-dependencies-{{ checksum "/tmp/checksum.txt" }} + +jobs: + build: + docker: + - image: cimg/openjdk:11.0 + working_directory: ~/repo + environment: + # Customize the JVM maximum heap limit + JVM_OPTS: -Xmx1g + TERM: dumb + steps: + - setup_build_environment + - populate_and_save_cache + - run: make build + + smoke-test: + # For testcontainers.org + machine: + image: ubuntu-2004:202101-01 + working_directory: ~/repo + environment: + # Customize the JVM maximum heap limit + TERM: dumb + steps: + - setup_build_environment + - populate_and_save_cache + - run: + no_output_timeout: 60m + command: make smoke-test + + muzzle: + docker: + - image: cimg/openjdk:11.0 + working_directory: ~/repo + environment: + # Customize the JVM maximum heap limit + JVM_OPTS: -Xmx1g + TERM: dumb + steps: + - setup_build_environment + - run: make muzzle + + release-bintray-publish: + executor: gradle_docker + steps: + - setup_build_environment + - setup_remote_docker: + version: 19.03.13 + - docker_login + - run: echo "Releasing version" && ./gradlew printVersion + - run: ./gradlew publish + - run: DOCKER_TAG=${CIRCLE_TAG} make docker docker-push + - run: + name: "Copy artifacts to workspace" + command: | + mkdir artifacts + cp javaagent/build/libs/*-all.jar artifacts/hypertrace-agent-all.jar + - persist_to_workspace: + root: . + paths: + - artifacts + + release-github-publish: + docker: + - image: cibuilds/github:0.13 + steps: + - attach_workspace: + at: . + - run: + name: "Publish Release on GitHub" + command: | + ghr -t ${GH_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -n "Release ${CIRCLE_TAG}" -b "..." --soft ${CIRCLE_TAG} ./artifacts/ + +workflows: + version: 2 + build-and-publish: + jobs: + - build: + filters: + tags: + only: /.*/ + - smoke-test: + filters: + tags: + only: /.*/ + - muzzle: + filters: + tags: + only: /.*/ + - release-bintray-publish: + context: hypertrace-publishing + requires: + - build + - muzzle + - smoke-test + filters: + branches: + ignore: /.*/ + tags: + only: /^[0-9]+\.[0-9]+\.[0-9]+/ + - release-github-publish: + context: hypertrace-publishing + requires: + - release-bintray-publish + filters: + branches: + ignore: /.*/ + tags: + only: /^[0-9]+\.[0-9]+\.[0-9]+/ diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml deleted file mode 100644 index e69de29bb..000000000 diff --git a/Makefile b/Makefile index 6d876e1ca..8934e4aae 100644 --- a/Makefile +++ b/Makefile @@ -7,11 +7,11 @@ assemble: .PHONY: build build: - ./gradlew build -x :smoke-tests:test --debug --stacktrace + ./gradlew build -x :smoke-tests:test --stacktrace .PHONY: smoke-test smoke-test: - ./gradlew :smoke-tests:test --debug --stacktrace + ./gradlew :smoke-tests:test --stacktrace .PHONY: muzzle muzzle: diff --git a/smoke-tests/build.gradle.kts b/smoke-tests/build.gradle.kts index 5fc395699..2453afbdb 100644 --- a/smoke-tests/build.gradle.kts +++ b/smoke-tests/build.gradle.kts @@ -30,6 +30,7 @@ tasks.test { junitXml.isOutputPerTestCase = true } + maxParallelForks = 2 val shadowTask : Jar = project(":javaagent").tasks.named("shadowJar").get() inputs.files(layout.files(shadowTask)) From 3c2bac359cac5a587931e2e80b0dbd92d65ef45c Mon Sep 17 00:00:00 2001 From: samarth-gupta-traceable Date: Wed, 17 Feb 2021 21:51:59 +0530 Subject: [PATCH 08/11] 4 parllel forks --- .github/workflows/pr-build.yml | 0 smoke-tests/build.gradle.kts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 .github/workflows/pr-build.yml diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml new file mode 100644 index 000000000..e69de29bb diff --git a/smoke-tests/build.gradle.kts b/smoke-tests/build.gradle.kts index 2453afbdb..5016c18f6 100644 --- a/smoke-tests/build.gradle.kts +++ b/smoke-tests/build.gradle.kts @@ -30,7 +30,7 @@ tasks.test { junitXml.isOutputPerTestCase = true } - maxParallelForks = 2 + maxParallelForks = 4 val shadowTask : Jar = project(":javaagent").tasks.named("shadowJar").get() inputs.files(layout.files(shadowTask)) From c83c0239bf66e94de880cf0e1e103ddf2c60a1f8 Mon Sep 17 00:00:00 2001 From: samarth-gupta-traceable Date: Thu, 18 Feb 2021 14:37:06 +0530 Subject: [PATCH 09/11] test smoke with GHA --- .circleci/config.yml | 20 ----------------- .github/workflows/pr-build.yml | 0 .github/workflows/pr-test.yml | 41 ++++++++++++++++++++++++++++++++++ smoke-tests/build.gradle.kts | 4 ++-- 4 files changed, 43 insertions(+), 22 deletions(-) delete mode 100644 .github/workflows/pr-build.yml create mode 100644 .github/workflows/pr-test.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index a38ebc9a3..a2941e360 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -51,21 +51,6 @@ jobs: - populate_and_save_cache - run: make build - smoke-test: - # For testcontainers.org - machine: - image: ubuntu-2004:202101-01 - working_directory: ~/repo - environment: - # Customize the JVM maximum heap limit - TERM: dumb - steps: - - setup_build_environment - - populate_and_save_cache - - run: - no_output_timeout: 60m - command: make smoke-test - muzzle: docker: - image: cimg/openjdk:11.0 @@ -117,10 +102,6 @@ workflows: filters: tags: only: /.*/ - - smoke-test: - filters: - tags: - only: /.*/ - muzzle: filters: tags: @@ -130,7 +111,6 @@ workflows: requires: - build - muzzle - - smoke-test filters: branches: ignore: /.*/ diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml deleted file mode 100644 index e69de29bb..000000000 diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml new file mode 100644 index 000000000..d80ebfaaf --- /dev/null +++ b/.github/workflows/pr-test.yml @@ -0,0 +1,41 @@ +name: test +on: + push: + branches: + - main + pull_request: + +jobs: + smoke-test: + runs-on: ubuntu-20.04 + steps: + # Set fetch-depth: 0 to fetch commit history and tags for use in version calculation + - name: Check out code + uses: actions/checkout@v2.3.4 + with: + fetch-depth: 0 + submodules: true + + - name: create checksum file + uses: hypertrace/github-actions/checksum@main + + - name: Cache packages + id: cache-packages + uses: actions/cache@v2 + with: + path: ~/.gradle + key: gradle-packages-${{ runner.os }}-${{ github.job }}-${{ hashFiles('**/checksum.txt') }} + restore-keys: | + gradle-packages-${{ runner.os }}-${{ github.job }} + gradle-packages-${{ runner.os }} + - name: Login to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_READ_USER }} + password: ${{ secrets.DOCKERHUB_READ_TOKEN }} + + - name: smoke-test + run: make smoke-test + env: + JVM_OPTS: -Xmx1g + TERM: dumb \ No newline at end of file diff --git a/smoke-tests/build.gradle.kts b/smoke-tests/build.gradle.kts index 5016c18f6..edb9090ee 100644 --- a/smoke-tests/build.gradle.kts +++ b/smoke-tests/build.gradle.kts @@ -12,7 +12,7 @@ val versions: Map by extra dependencies{ testImplementation(project(":testing-common")) testImplementation(project(":javaagent-core")) - testImplementation("org.testcontainers:testcontainers:1.15.0") + testImplementation("org.testcontainers:testcontainers:1.15.2") testImplementation("com.squareup.okhttp3:okhttp:4.9.0") testImplementation("org.awaitility:awaitility:4.0.3") testImplementation("io.opentelemetry:opentelemetry-proto:${versions["opentelemetry"]}") @@ -30,7 +30,7 @@ tasks.test { junitXml.isOutputPerTestCase = true } - maxParallelForks = 4 + maxParallelForks = 2 val shadowTask : Jar = project(":javaagent").tasks.named("shadowJar").get() inputs.files(layout.files(shadowTask)) From a96e56155831d64f26673a46cc11496c44178ff6 Mon Sep 17 00:00:00 2001 From: samarth-gupta-traceable Date: Thu, 18 Feb 2021 15:02:33 +0530 Subject: [PATCH 10/11] local undo --- .circleci/config.yml | 20 +++++++++++++++++ .github/workflows/pr-test.yml | 41 ----------------------------------- 2 files changed, 20 insertions(+), 41 deletions(-) delete mode 100644 .github/workflows/pr-test.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index a2941e360..a38ebc9a3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -51,6 +51,21 @@ jobs: - populate_and_save_cache - run: make build + smoke-test: + # For testcontainers.org + machine: + image: ubuntu-2004:202101-01 + working_directory: ~/repo + environment: + # Customize the JVM maximum heap limit + TERM: dumb + steps: + - setup_build_environment + - populate_and_save_cache + - run: + no_output_timeout: 60m + command: make smoke-test + muzzle: docker: - image: cimg/openjdk:11.0 @@ -102,6 +117,10 @@ workflows: filters: tags: only: /.*/ + - smoke-test: + filters: + tags: + only: /.*/ - muzzle: filters: tags: @@ -111,6 +130,7 @@ workflows: requires: - build - muzzle + - smoke-test filters: branches: ignore: /.*/ diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml deleted file mode 100644 index d80ebfaaf..000000000 --- a/.github/workflows/pr-test.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: test -on: - push: - branches: - - main - pull_request: - -jobs: - smoke-test: - runs-on: ubuntu-20.04 - steps: - # Set fetch-depth: 0 to fetch commit history and tags for use in version calculation - - name: Check out code - uses: actions/checkout@v2.3.4 - with: - fetch-depth: 0 - submodules: true - - - name: create checksum file - uses: hypertrace/github-actions/checksum@main - - - name: Cache packages - id: cache-packages - uses: actions/cache@v2 - with: - path: ~/.gradle - key: gradle-packages-${{ runner.os }}-${{ github.job }}-${{ hashFiles('**/checksum.txt') }} - restore-keys: | - gradle-packages-${{ runner.os }}-${{ github.job }} - gradle-packages-${{ runner.os }} - - name: Login to Docker Hub - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKERHUB_READ_USER }} - password: ${{ secrets.DOCKERHUB_READ_TOKEN }} - - - name: smoke-test - run: make smoke-test - env: - JVM_OPTS: -Xmx1g - TERM: dumb \ No newline at end of file From 90f1b3d316090e95517d43d2d4c4136d4527ec16 Mon Sep 17 00:00:00 2001 From: samarth-gupta-traceable Date: Thu, 18 Feb 2021 15:37:37 +0530 Subject: [PATCH 11/11] remove dependencies.gradle --- gradle/dependencies.gradle | 97 -------------------------------------- gradle/java.gradle | 29 +++++++++--- 2 files changed, 23 insertions(+), 103 deletions(-) delete mode 100644 gradle/dependencies.gradle diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle deleted file mode 100644 index 03d1a649f..000000000 --- a/gradle/dependencies.gradle +++ /dev/null @@ -1,97 +0,0 @@ -def groovyVer = "2.5.11" -def spockGroovyVer = groovyVer.replaceAll(/\.\d+$/, '') - -// this is only needed for the working against unreleased otel-java snapshots -configurations.all { - resolutionStrategy.cacheChangingModulesFor 12, 'hours' -} - -ext { - versions = [ - opentelemetry : '0.15.0', - opentelemetryAlpha: "0.15.0-alpha", - - slf4j : "1.7.30", - guava : "30.1-jre", - - spock : "1.3-groovy-$spockGroovyVer", - groovy : groovyVer, - logback : "1.2.3", - bytebuddy : "1.10.18", // Also explicitly specified in buildSrc - scala : "2.11.12", // Last version to support Java 7 (2.12+ require Java 8+) - kotlin : "1.4.0", - coroutines : "1.3.0", - springboot : "2.3.1.RELEASE", - // TODO(anuraaga): Switch off of milestones, this version fixes compatibility with Spock Unroll - junit5 : "5.7.0-M1", - checkerFramework : "3.6.1", - errorprone : "2.4.0", - nullaway : "0.8.0", - autoValue : "1.7.4", - systemLambda : "1.1.0", - prometheus : "0.9.0" - ] - - deps = [ - // OpenTelemetry - opentelemetryApi : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-api', version: versions.opentelemetry), - opentelemetryApiMetrics : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-api-metrics', version: versions.opentelemetryAlpha), - opentelemetryExtAnnotations : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-annotations', version: versions.opentelemetry), - opentelemetryContext : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-context', version: versions.opentelemetry), - opentelemetryKotlin : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-kotlin', version: versions.opentelemetry), - opentelemetryLogging : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-logging', version: versions.opentelemetry), - opentelemetryTraceProps : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-trace-propagators', version: versions.opentelemetry), - opentelemetrySdk : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk', version: versions.opentelemetry), - opentelemetrySdkAutoconfigure: dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-extension-autoconfigure', version: versions.opentelemetryAlpha), - opentelemetrySdkMetrics : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-metrics', version: versions.opentelemetryAlpha), - opentelemetryJaeger : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-jaeger', version: versions.opentelemetry), - opentelemetryOtlp : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-otlp', version: versions.opentelemetry), - opentelemetryOtlpMetrics : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-otlp-metrics', version: versions.opentelemetryAlpha), - opentelemetryZipkin : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-zipkin', version: versions.opentelemetry), - opentelemetryPrometheus : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-prometheus', version: versions.opentelemetryAlpha), - opentelemetryLogging : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-logging', version: versions.opentelemetry), - opentelemetryProto : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-proto', version: versions.opentelemetry), - opentelemetryResources : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-extension-resources', version: versions.opentelemetry), - opentelemetrySdkTesting : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-testing', version: versions.opentelemetry), - opentelemetrySemConv : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-semconv', version: versions.opentelemetryAlpha), - - // General - slf4j : "org.slf4j:slf4j-api:${versions.slf4j}", - guava : "com.google.guava:guava:$versions.guava", - bytebuddy : dependencies.create(group: 'net.bytebuddy', name: 'byte-buddy', version: "${versions.bytebuddy}"), - bytebuddyagent : dependencies.create(group: 'net.bytebuddy', name: 'byte-buddy-agent', version: "${versions.bytebuddy}"), - autoservice : [ - dependencies.create(group: 'com.google.auto.service', name: 'auto-service', version: '1.0-rc7'), - dependencies.create(group: 'com.google.auto', name: 'auto-common', version: '0.8'), - ], - autoValueAnnotations : "com.google.auto.value:auto-value-annotations:${versions.autoValue}", - // annotation processor - autoValue : "com.google.auto.value:auto-value:${versions.autoValue}", - prometheus : [ - dependencies.create(group: 'io.prometheus', name: 'simpleclient', version: "${versions.prometheus}"), - dependencies.create(group: 'io.prometheus', name: 'simpleclient_httpserver', version: "${versions.prometheus}"), - ], - - // Testing - - spock : [ - dependencies.create("org.spockframework:spock-core:${versions.spock}", { - exclude group: 'org.codehaus.groovy', module: 'groovy-all' - }), - // Used by Spock for mocking: - dependencies.create(group: 'org.objenesis', name: 'objenesis', version: '3.1') - ], - groovy : "org.codehaus.groovy:groovy-all:${versions.groovy}", - systemLambda : "com.github.stefanbirkner:system-lambda:${versions.systemLambda}", - testcontainers : "org.testcontainers:testcontainers:1.15.0-rc2", - testLogging : [ - dependencies.create(group: 'ch.qos.logback', name: 'logback-classic', version: versions.logback), - dependencies.create(group: 'org.slf4j', name: 'log4j-over-slf4j', version: versions.slf4j), - dependencies.create(group: 'org.slf4j', name: 'jcl-over-slf4j', version: versions.slf4j), - dependencies.create(group: 'org.slf4j', name: 'jul-to-slf4j', version: versions.slf4j), - ], - scala : dependencies.create(group: 'org.scala-lang', name: 'scala-library', version: "${versions.scala}"), - kotlin : dependencies.create(group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: "${versions.kotlin}"), - coroutines : dependencies.create(group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: "${versions.coroutines}"), - ] -} diff --git a/gradle/java.gradle b/gradle/java.gradle index ab36bd51f..53b15c8a9 100644 --- a/gradle/java.gradle +++ b/gradle/java.gradle @@ -4,8 +4,6 @@ apply plugin: 'java-library' apply plugin: 'groovy' apply plugin: 'org.gradle.test-retry' -apply from: "$rootDir/gradle/dependencies.gradle" - // Version to use to compile code and run tests. def DEFAULT_JAVA_VERSION = 11 @@ -42,10 +40,29 @@ repositories { } } +ext { + deps = [ + spock : [ + dependencies.create("org.spockframework:spock-core:1.3-groovy-2.5", { + exclude group: 'org.codehaus.groovy', module: 'groovy-all' + }), + // Used by Spock for mocking: + dependencies.create(group: 'org.objenesis', name: 'objenesis', version: '3.1') + ], + groovy : "org.codehaus.groovy:groovy-all:2.5.11", + testLogging: [ + dependencies.create(group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3'), + dependencies.create(group: 'org.slf4j', name: 'log4j-over-slf4j', version: '1.7.30'), + dependencies.create(group: 'org.slf4j', name: 'jcl-over-slf4j', version: '1.7.30'), + dependencies.create(group: 'org.slf4j', name: 'jul-to-slf4j', version: '1.7.30'), + ] + ] +} + dependencies { - compileOnly group: 'org.checkerframework', name: 'checker-qual', version: versions.checkerFramework + compileOnly group: 'org.checkerframework', name: 'checker-qual', version: '3.6.1' - testImplementation enforcedPlatform(group: 'org.junit', name: 'junit-bom', version: versions.junit5) + testImplementation enforcedPlatform(group: 'org.junit', name: 'junit-bom', version: '5.7.0-M1') testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api' testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-params' testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine' @@ -148,9 +165,9 @@ if (testJavaVersion != null) { tasks.withType(Test).configureEach { useJUnitPlatform() - // All tests must complete within 15 minutes. + // All tests must complete within 30 minutes. // This value is quite big because with lower values (3 mins) we were experiencing large number of false positives - timeout = Duration.ofMinutes(60) + timeout = Duration.ofMinutes(30) retry { // You can see tests that were retried by this mechanism in the collected test reports and build scans.