Merge tag 'v0.48.0' into dd-merge
This commit is contained in:
commit
d24159c8d2
|
@ -19,18 +19,18 @@ import java.io.File;
|
|||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.regex.Pattern;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
@ -46,6 +46,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||
@Slf4j
|
||||
@ToString(includeFieldNames = true)
|
||||
public class Config {
|
||||
|
||||
/** Config keys below */
|
||||
private static final String PREFIX = "ota.";
|
||||
|
||||
|
@ -250,13 +251,14 @@ public class Config {
|
|||
}
|
||||
|
||||
/**
|
||||
* @deprecated This method should only be used internally. Use the instance getter instead {@link
|
||||
* #isIntegrationEnabled(SortedSet, boolean)}.
|
||||
* @param integrationNames
|
||||
* @param defaultEnabled
|
||||
* @return
|
||||
* @deprecated This method should only be used internally. Use the instance getter instead {@link
|
||||
* #isIntegrationEnabled(SortedSet, boolean)}.
|
||||
*/
|
||||
public static boolean integrationEnabled(
|
||||
@Deprecated
|
||||
private static boolean integrationEnabled(
|
||||
final SortedSet<String> integrationNames, final boolean defaultEnabled) {
|
||||
// If default is enabled, we want to enable individually,
|
||||
// if default is disabled, we want to disable individually.
|
||||
|
@ -286,9 +288,10 @@ public class Config {
|
|||
*/
|
||||
public static String getSettingFromEnvironment(final String name, final String defaultValue) {
|
||||
String value;
|
||||
final String systemPropertyName = propertyNameToSystemPropertyName(name);
|
||||
|
||||
// System properties and properties provided from command line have the highest precedence
|
||||
value = System.getProperties().getProperty(propertyNameToSystemPropertyName(name));
|
||||
value = System.getProperties().getProperty(systemPropertyName);
|
||||
if (null != value) {
|
||||
return value;
|
||||
}
|
||||
|
@ -300,7 +303,7 @@ public class Config {
|
|||
}
|
||||
|
||||
// If value is not defined yet, we look at properties optionally defined in a properties file
|
||||
value = propertiesFromConfigFile.getProperty(propertyNameToSystemPropertyName(name));
|
||||
value = propertiesFromConfigFile.getProperty(systemPropertyName);
|
||||
if (null != value) {
|
||||
return value;
|
||||
}
|
||||
|
@ -314,7 +317,8 @@ public class Config {
|
|||
*
|
||||
* @deprecated This method should only be used internally. Use the explicit getter instead.
|
||||
*/
|
||||
public static List<String> getListSettingFromEnvironment(
|
||||
@NonNull
|
||||
private static List<String> getListSettingFromEnvironment(
|
||||
final String name, final String defaultValue) {
|
||||
return parseList(getSettingFromEnvironment(name, defaultValue));
|
||||
}
|
||||
|
@ -326,8 +330,7 @@ public class Config {
|
|||
*/
|
||||
public static Boolean getBooleanSettingFromEnvironment(
|
||||
final String name, final Boolean defaultValue) {
|
||||
final String value = getSettingFromEnvironment(name, null);
|
||||
return value == null || value.trim().isEmpty() ? defaultValue : Boolean.valueOf(value);
|
||||
return getSettingFromEnvironmentWithLog(name, Boolean.class, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -336,13 +339,7 @@ public class Config {
|
|||
* @deprecated This method should only be used internally. Use the explicit getter instead.
|
||||
*/
|
||||
public static Float getFloatSettingFromEnvironment(final String name, final Float defaultValue) {
|
||||
final String value = getSettingFromEnvironment(name, null);
|
||||
try {
|
||||
return value == null ? defaultValue : Float.valueOf(value);
|
||||
} catch (final NumberFormatException e) {
|
||||
log.warn("Invalid configuration for " + name, e);
|
||||
return defaultValue;
|
||||
}
|
||||
return getSettingFromEnvironmentWithLog(name, Float.class, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -350,41 +347,20 @@ public class Config {
|
|||
*/
|
||||
private static Integer getIntegerSettingFromEnvironment(
|
||||
final String name, final Integer defaultValue) {
|
||||
final String value = getSettingFromEnvironment(name, null);
|
||||
return getSettingFromEnvironmentWithLog(name, Integer.class, defaultValue);
|
||||
}
|
||||
|
||||
private static <T> T getSettingFromEnvironmentWithLog(
|
||||
final String name, final Class<T> tClass, final T defaultValue) {
|
||||
try {
|
||||
return value == null ? defaultValue : Integer.valueOf(value);
|
||||
return valueOf(getSettingFromEnvironment(name, null), tClass, defaultValue);
|
||||
} catch (final NumberFormatException e) {
|
||||
log.warn("Invalid configuration for " + name, e);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #getSettingFromEnvironment(String, String)} and converts the result to a set of
|
||||
* strings splitting by space or comma.
|
||||
*/
|
||||
private static <T extends Enum<T>> Set<T> getEnumSetSettingFromEnvironment(
|
||||
final String name,
|
||||
final String defaultValue,
|
||||
final Class<T> clazz,
|
||||
final boolean emptyResultMeansUseDefault) {
|
||||
final String value = getSettingFromEnvironment(name, defaultValue);
|
||||
Set<T> result =
|
||||
convertStringSetToEnumSet(
|
||||
parseStringIntoSetOfNonEmptyStrings(value, SPLIT_BY_SPACE_OR_COMMA_REGEX), clazz);
|
||||
|
||||
if (emptyResultMeansUseDefault && result.isEmpty()) {
|
||||
// Treat empty parsing result as no value and use default instead
|
||||
result =
|
||||
convertStringSetToEnumSet(
|
||||
parseStringIntoSetOfNonEmptyStrings(defaultValue, SPLIT_BY_SPACE_OR_COMMA_REGEX),
|
||||
clazz);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Set<Integer> getIntegerRangeSettingFromEnvironment(
|
||||
private static Set<Integer> getIntegerRangeSettingFromEnvironment(
|
||||
final String name, final Set<Integer> defaultValue) {
|
||||
final String value = getSettingFromEnvironment(name, null);
|
||||
try {
|
||||
|
@ -402,6 +378,7 @@ public class Config {
|
|||
* @param setting The setting name, e.g. `trace.enabled`
|
||||
* @return The public facing environment variable name
|
||||
*/
|
||||
@NonNull
|
||||
private static String propertyNameToEnvironmentVariableName(final String setting) {
|
||||
return ENV_REPLACEMENT
|
||||
.matcher(propertyNameToSystemPropertyName(setting).toUpperCase())
|
||||
|
@ -415,14 +392,39 @@ public class Config {
|
|||
* @param setting The setting name, e.g. `trace.config`
|
||||
* @return The public facing system property name
|
||||
*/
|
||||
@NonNull
|
||||
private static String propertyNameToSystemPropertyName(final String setting) {
|
||||
return PREFIX + setting;
|
||||
}
|
||||
|
||||
private static Map<String, String> getPropertyMapValue(
|
||||
final Properties properties, final String name, final Map<String, String> defaultValue) {
|
||||
final String value = properties.getProperty(name);
|
||||
return value == null || value.trim().isEmpty() ? defaultValue : parseMap(value, name);
|
||||
/**
|
||||
* @param value to parse by tClass::valueOf
|
||||
* @param tClass should contain static parsing method "T valueOf(String)"
|
||||
* @param defaultValue
|
||||
* @param <T>
|
||||
* @return value == null || value.trim().isEmpty() ? defaultValue : tClass.valueOf(value)
|
||||
* @throws NumberFormatException
|
||||
*/
|
||||
private static <T> T valueOf(
|
||||
final String value, @NonNull final Class<T> tClass, final T defaultValue) {
|
||||
if (value == null || value.trim().isEmpty()) {
|
||||
log.debug("valueOf: using defaultValue '{}' for '{}' of '{}' ", defaultValue, value, tClass);
|
||||
return defaultValue;
|
||||
}
|
||||
try {
|
||||
return (T)
|
||||
MethodHandles.publicLookup()
|
||||
.findStatic(tClass, "valueOf", MethodType.methodType(tClass, String.class))
|
||||
.invoke(value);
|
||||
} catch (final NumberFormatException e) {
|
||||
throw e;
|
||||
} catch (final NoSuchMethodException | IllegalAccessException e) {
|
||||
log.debug("Can't invoke or access 'valueOf': ", e);
|
||||
throw new NumberFormatException(e.toString());
|
||||
} catch (final Throwable e) {
|
||||
log.debug("Can't parse: ", e);
|
||||
throw new NumberFormatException(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> getPropertyListValue(
|
||||
|
@ -433,32 +435,15 @@ public class Config {
|
|||
|
||||
private static Boolean getPropertyBooleanValue(
|
||||
final Properties properties, final String name, final Boolean defaultValue) {
|
||||
final String value = properties.getProperty(name);
|
||||
return value == null || value.trim().isEmpty() ? defaultValue : Boolean.valueOf(value);
|
||||
return valueOf(properties.getProperty(name), Boolean.class, defaultValue);
|
||||
}
|
||||
|
||||
private static Integer getPropertyIntegerValue(
|
||||
final Properties properties, final String name, final Integer defaultValue) {
|
||||
final String value = properties.getProperty(name);
|
||||
return value == null || value.trim().isEmpty() ? defaultValue : Integer.valueOf(value);
|
||||
return valueOf(properties.getProperty(name), Integer.class, defaultValue);
|
||||
}
|
||||
|
||||
private static <T extends Enum<T>> Set<T> getPropertySetValue(
|
||||
final Properties properties, final String name, final Class<T> clazz) {
|
||||
final String value = properties.getProperty(name);
|
||||
if (value != null) {
|
||||
final Set<T> result =
|
||||
convertStringSetToEnumSet(
|
||||
parseStringIntoSetOfNonEmptyStrings(value, SPLIT_BY_SPACE_OR_COMMA_REGEX), clazz);
|
||||
if (!result.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// null means parent value should be used
|
||||
return null;
|
||||
}
|
||||
|
||||
private Set<Integer> getPropertyIntegerRangeValue(
|
||||
private static Set<Integer> getPropertyIntegerRangeValue(
|
||||
final Properties properties, final String name, final Set<Integer> defaultValue) {
|
||||
final String value = properties.getProperty(name);
|
||||
try {
|
||||
|
@ -469,38 +454,9 @@ public class Config {
|
|||
}
|
||||
}
|
||||
|
||||
private static Map<String, String> parseMap(final String str, final String settingName) {
|
||||
// If we ever want to have default values besides an empty map, this will need to change.
|
||||
if (str == null || str.trim().isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
if (!str.matches("(([^,:]+:[^,:]*,)*([^,:]+:[^,:]*),?)?")) {
|
||||
log.warn(
|
||||
"Invalid config for {}: '{}'. Must match 'key1:value1,key2:value2'.", settingName, str);
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
final String[] tokens = str.split(",", -1);
|
||||
final Map<String, String> map = newHashMap(tokens.length);
|
||||
|
||||
for (final String token : tokens) {
|
||||
final String[] keyValue = token.split(":", -1);
|
||||
if (keyValue.length == 2) {
|
||||
final String key = keyValue[0].trim();
|
||||
final String value = keyValue[1].trim();
|
||||
if (value.length() <= 0) {
|
||||
log.warn("Ignoring empty value for key '{}' in config for {}", key, settingName);
|
||||
continue;
|
||||
}
|
||||
map.put(key, value);
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
private static Set<Integer> parseIntegerRangeSet(String str, final String settingName)
|
||||
@NonNull
|
||||
private static Set<Integer> parseIntegerRangeSet(@NonNull String str, final String settingName)
|
||||
throws NumberFormatException {
|
||||
assert str != null;
|
||||
str = str.replaceAll("\\s", "");
|
||||
if (!str.matches("\\d{3}(?:-\\d{3})?(?:,\\d{3}(?:-\\d{3})?)*")) {
|
||||
log.warn(
|
||||
|
@ -530,10 +486,7 @@ public class Config {
|
|||
return Collections.unmodifiableSet(set);
|
||||
}
|
||||
|
||||
private static Map<String, String> newHashMap(final int size) {
|
||||
return new HashMap<>(size + 1, 1f);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static List<String> parseList(final String str) {
|
||||
if (str == null || str.trim().isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
|
@ -547,34 +500,6 @@ public class Config {
|
|||
return Collections.unmodifiableList(Arrays.asList(tokens));
|
||||
}
|
||||
|
||||
private static Set<String> parseStringIntoSetOfNonEmptyStrings(
|
||||
final String str, final String regex) {
|
||||
// Using LinkedHashSet to preserve original string order
|
||||
final Set<String> result = new LinkedHashSet<>();
|
||||
// Java returns single value when splitting an empty string. We do not need that value, so
|
||||
// we need to throw it out.
|
||||
for (final String value : str.split(regex)) {
|
||||
if (!value.isEmpty()) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableSet(result);
|
||||
}
|
||||
|
||||
private static <V extends Enum<V>> Set<V> convertStringSetToEnumSet(
|
||||
final Set<String> input, final Class<V> clazz) {
|
||||
// Using LinkedHashSet to preserve original string order
|
||||
final Set<V> result = new LinkedHashSet<>();
|
||||
for (final String value : input) {
|
||||
try {
|
||||
result.add(Enum.valueOf(clazz, value.toUpperCase()));
|
||||
} catch (final IllegalArgumentException e) {
|
||||
log.debug("Cannot recognize config string value: {}, {}", value, clazz);
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableSet(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the optional configuration properties file into the global {@link Properties} object.
|
||||
*
|
||||
|
@ -606,23 +531,13 @@ public class Config {
|
|||
return properties;
|
||||
}
|
||||
|
||||
FileReader fileReader = null;
|
||||
try {
|
||||
fileReader = new FileReader(configurationFile);
|
||||
try (final FileReader fileReader = new FileReader(configurationFile)) {
|
||||
properties.load(fileReader);
|
||||
} catch (final FileNotFoundException fnf) {
|
||||
log.error("Configuration file '{}' not found.", configurationFilePath);
|
||||
} catch (final IOException ioe) {
|
||||
log.error(
|
||||
"Configuration file '{}' cannot be accessed or correctly parsed.", configurationFilePath);
|
||||
} finally {
|
||||
if (fileReader != null) {
|
||||
try {
|
||||
fileReader.close();
|
||||
} catch (final IOException ioe) {
|
||||
log.error("Configuration file '{}' was not closed correctly.", configurationFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return properties;
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry 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 io.opentelemetry.auto.tooling;
|
||||
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.TypeConstantAdjustment;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.utility.JavaModule;
|
||||
|
||||
public class AgentTransformers {
|
||||
|
||||
private static final AgentBuilder.Transformer CONSTANT_ADJUSTER =
|
||||
new AgentBuilder.Transformer() {
|
||||
@Override
|
||||
public DynamicType.Builder<?> transform(
|
||||
final DynamicType.Builder<?> builder,
|
||||
final TypeDescription typeDescription,
|
||||
final ClassLoader classLoader,
|
||||
final JavaModule javaModule) {
|
||||
return builder.visit(TypeConstantAdjustment.INSTANCE);
|
||||
}
|
||||
};
|
||||
|
||||
public static AgentBuilder.Transformer defaultTransformers() {
|
||||
return CONSTANT_ADJUSTER;
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
|
|||
import static net.bytebuddy.matcher.ElementMatchers.not;
|
||||
|
||||
import io.opentelemetry.auto.config.Config;
|
||||
import io.opentelemetry.auto.tooling.bytebuddy.AgentTransformers;
|
||||
import io.opentelemetry.auto.tooling.bytebuddy.ExceptionHandlers;
|
||||
import io.opentelemetry.auto.tooling.context.FieldBackedProvider;
|
||||
import io.opentelemetry.auto.tooling.context.InstrumentationContextProvider;
|
||||
|
@ -122,7 +123,7 @@ public interface Instrumenter {
|
|||
if (helperClassNames.length > 0) {
|
||||
agentBuilder =
|
||||
agentBuilder.transform(
|
||||
new HelperInjector(this.getClass().getSimpleName(), helperClassNames));
|
||||
new HelperInjector(getClass().getSimpleName(), helperClassNames));
|
||||
}
|
||||
return agentBuilder;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.gradle.api.model.ObjectFactory
|
|||
import java.lang.reflect.Method
|
||||
import java.security.SecureClassLoader
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/**
|
||||
* muzzle task plugin which runs muzzle validation against a range of dependencies.
|
||||
|
@ -36,7 +37,8 @@ class MuzzlePlugin implements Plugin<Project> {
|
|||
private static final AtomicReference<ClassLoader> TOOLING_LOADER = new AtomicReference<>()
|
||||
static {
|
||||
RemoteRepository central = new RemoteRepository.Builder("central", "default", "https://repo1.maven.org/maven2/").build()
|
||||
MUZZLE_REPOS = new ArrayList<RemoteRepository>(Arrays.asList(central))
|
||||
RemoteRepository typesafe = new RemoteRepository.Builder("typesafe", "default", "https://repo.typesafe.com/typesafe/releases").build()
|
||||
MUZZLE_REPOS = new ArrayList<RemoteRepository>(Arrays.asList(central, typesafe))
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -343,6 +345,8 @@ class MuzzlePlugin implements Plugin<Project> {
|
|||
return session
|
||||
}
|
||||
|
||||
private static final Pattern GIT_SHA_PATTERN = Pattern.compile('^.*-[0-9a-f]{7,}$')
|
||||
|
||||
/**
|
||||
* Filter out snapshot-type builds from versions list.
|
||||
*/
|
||||
|
@ -357,7 +361,8 @@ class MuzzlePlugin implements Plugin<Project> {
|
|||
version.contains(".m") ||
|
||||
version.contains("-m") ||
|
||||
version.contains("-dev") ||
|
||||
version.contains("public_draft")
|
||||
version.contains("public_draft") ||
|
||||
version.matches(GIT_SHA_PATTERN)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
test-api-key-very-old
|
|
@ -7,6 +7,7 @@ ext {
|
|||
|
||||
slf4j : "1.7.29",
|
||||
guava : "20.0", // Last version to support Java 7
|
||||
okhttp : "3.12.8", // 3.12.x is last version to support Java7
|
||||
|
||||
spock : "1.3-groovy-$spockGroovyVer",
|
||||
groovy : groovyVer,
|
||||
|
|
|
@ -133,6 +133,9 @@ repositories {
|
|||
maven {
|
||||
url "https://adoptopenjdk.jfrog.io/adoptopenjdk/jmc-libs-snapshots"
|
||||
}
|
||||
maven {
|
||||
url "https://repo.typesafe.com/typesafe/releases"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
|
|||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
|
|
|
@ -22,9 +22,11 @@ import akka.stream.ActorMaterializer
|
|||
import io.opentelemetry.auto.bootstrap.instrumentation.decorator.HttpClientDecorator
|
||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Timeout
|
||||
|
||||
import static io.opentelemetry.trace.Span.Kind.CLIENT
|
||||
|
||||
@Timeout(5)
|
||||
class AkkaHttpClientInstrumentationTest extends HttpClientTest {
|
||||
|
||||
@Shared
|
||||
|
@ -55,6 +57,12 @@ class AkkaHttpClientInstrumentationTest extends HttpClientTest {
|
|||
false
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRemoteConnection() {
|
||||
// Not sure how to properly set timeouts...
|
||||
return false
|
||||
}
|
||||
|
||||
def "singleRequest exception trace"() {
|
||||
when:
|
||||
// Passing null causes NPE in singleRequest
|
||||
|
|
|
@ -15,19 +15,28 @@
|
|||
*/
|
||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||
import org.apache.http.HttpResponse
|
||||
import org.apache.http.client.config.RequestConfig
|
||||
import org.apache.http.concurrent.FutureCallback
|
||||
import org.apache.http.impl.nio.client.HttpAsyncClients
|
||||
import org.apache.http.message.BasicHeader
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Timeout
|
||||
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
@Timeout(5)
|
||||
class ApacheHttpAsyncClientCallbackTest extends HttpClientTest {
|
||||
|
||||
@Shared
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setConnectTimeout(CONNECT_TIMEOUT_MS)
|
||||
.setSocketTimeout(READ_TIMEOUT_MS)
|
||||
.build()
|
||||
|
||||
@AutoCleanup
|
||||
@Shared
|
||||
def client = HttpAsyncClients.createDefault()
|
||||
def client = HttpAsyncClients.custom().setDefaultRequestConfig(requestConfig).build()
|
||||
|
||||
def setupSpec() {
|
||||
client.start()
|
||||
|
@ -68,4 +77,9 @@ class ApacheHttpAsyncClientCallbackTest extends HttpClientTest {
|
|||
Integer statusOnRedirectError() {
|
||||
return 302
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRemoteConnection() {
|
||||
false // otherwise SocketTimeoutException for https requests
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,18 +14,27 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||
import org.apache.http.client.config.RequestConfig
|
||||
import org.apache.http.impl.nio.client.HttpAsyncClients
|
||||
import org.apache.http.message.BasicHeader
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Timeout
|
||||
|
||||
import java.util.concurrent.Future
|
||||
|
||||
@Timeout(5)
|
||||
class ApacheHttpAsyncClientNullCallbackTest extends HttpClientTest {
|
||||
|
||||
@Shared
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setConnectTimeout(CONNECT_TIMEOUT_MS)
|
||||
.setSocketTimeout(READ_TIMEOUT_MS)
|
||||
.build()
|
||||
|
||||
@AutoCleanup
|
||||
@Shared
|
||||
def client = HttpAsyncClients.createDefault()
|
||||
def client = HttpAsyncClients.custom().setDefaultRequestConfig(requestConfig).build()
|
||||
|
||||
def setupSpec() {
|
||||
client.start()
|
||||
|
@ -53,4 +62,9 @@ class ApacheHttpAsyncClientNullCallbackTest extends HttpClientTest {
|
|||
Integer statusOnRedirectError() {
|
||||
return 302
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRemoteConnection() {
|
||||
false // otherwise SocketTimeoutException for https requests
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,19 +15,28 @@
|
|||
*/
|
||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||
import org.apache.http.HttpResponse
|
||||
import org.apache.http.client.config.RequestConfig
|
||||
import org.apache.http.concurrent.FutureCallback
|
||||
import org.apache.http.impl.nio.client.HttpAsyncClients
|
||||
import org.apache.http.message.BasicHeader
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Timeout
|
||||
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
||||
@Timeout(5)
|
||||
class ApacheHttpAsyncClientTest extends HttpClientTest {
|
||||
|
||||
@Shared
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
.setConnectTimeout(CONNECT_TIMEOUT_MS)
|
||||
.setSocketTimeout(READ_TIMEOUT_MS)
|
||||
.build()
|
||||
|
||||
@AutoCleanup
|
||||
@Shared
|
||||
def client = HttpAsyncClients.createDefault()
|
||||
def client = HttpAsyncClients.custom().setDefaultRequestConfig(requestConfig).build()
|
||||
|
||||
def setupSpec() {
|
||||
client.start()
|
||||
|
@ -74,4 +83,9 @@ class ApacheHttpAsyncClientTest extends HttpClientTest {
|
|||
Integer statusOnRedirectError() {
|
||||
return 302
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRemoteConnection() {
|
||||
false // otherwise SocketTimeoutException for https requests
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,11 +24,18 @@ import org.apache.commons.httpclient.methods.PostMethod
|
|||
import org.apache.commons.httpclient.methods.PutMethod
|
||||
import org.apache.commons.httpclient.methods.TraceMethod
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Timeout
|
||||
|
||||
@Timeout(5)
|
||||
class CommonsHttpClientTest extends HttpClientTest {
|
||||
@Shared
|
||||
HttpClient client = new HttpClient()
|
||||
|
||||
def setupSpec() {
|
||||
client.setConnectionTimeout(CONNECT_TIMEOUT_MS)
|
||||
client.setTimeout(READ_TIMEOUT_MS)
|
||||
}
|
||||
|
||||
@Override
|
||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||
HttpMethod httpMethod
|
||||
|
|
|
@ -18,8 +18,12 @@ import org.apache.http.HttpResponse
|
|||
import org.apache.http.client.ResponseHandler
|
||||
import org.apache.http.impl.client.DefaultHttpClient
|
||||
import org.apache.http.message.BasicHeader
|
||||
import org.apache.http.params.HttpConnectionParams
|
||||
import org.apache.http.params.HttpParams
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Timeout
|
||||
|
||||
@Timeout(5)
|
||||
class ApacheHttpClientResponseHandlerTest extends HttpClientTest {
|
||||
|
||||
@Shared
|
||||
|
@ -33,6 +37,12 @@ class ApacheHttpClientResponseHandlerTest extends HttpClientTest {
|
|||
}
|
||||
}
|
||||
|
||||
def setupSpec() {
|
||||
HttpParams httpParams = client.getParams()
|
||||
HttpConnectionParams.setConnectionTimeout(httpParams, CONNECT_TIMEOUT_MS)
|
||||
HttpConnectionParams.setSoTimeout(httpParams, READ_TIMEOUT_MS)
|
||||
}
|
||||
|
||||
@Override
|
||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||
def request = new HttpUriRequest(method, uri)
|
||||
|
|
|
@ -20,13 +20,22 @@ import org.apache.http.HttpResponse
|
|||
import org.apache.http.impl.client.DefaultHttpClient
|
||||
import org.apache.http.message.BasicHeader
|
||||
import org.apache.http.message.BasicHttpRequest
|
||||
import org.apache.http.params.HttpConnectionParams
|
||||
import org.apache.http.params.HttpParams
|
||||
import org.apache.http.protocol.BasicHttpContext
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Timeout
|
||||
|
||||
abstract class ApacheHttpClientTest<T extends HttpRequest> extends HttpClientTest {
|
||||
@Shared
|
||||
def client = new DefaultHttpClient()
|
||||
|
||||
def setupSpec() {
|
||||
HttpParams httpParams = client.getParams()
|
||||
HttpConnectionParams.setConnectionTimeout(httpParams, CONNECT_TIMEOUT_MS)
|
||||
HttpConnectionParams.setSoTimeout(httpParams, READ_TIMEOUT_MS)
|
||||
}
|
||||
|
||||
@Override
|
||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||
def request = createRequest(method, uri)
|
||||
|
@ -64,6 +73,7 @@ abstract class ApacheHttpClientTest<T extends HttpRequest> extends HttpClientTes
|
|||
}
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class ApacheClientHostRequest extends ApacheHttpClientTest<BasicHttpRequest> {
|
||||
@Override
|
||||
BasicHttpRequest createRequest(String method, URI uri) {
|
||||
|
@ -74,8 +84,14 @@ class ApacheClientHostRequest extends ApacheHttpClientTest<BasicHttpRequest> {
|
|||
HttpResponse executeRequest(BasicHttpRequest request, URI uri) {
|
||||
return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request)
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRemoteConnection() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class ApacheClientHostRequestContext extends ApacheHttpClientTest<BasicHttpRequest> {
|
||||
@Override
|
||||
BasicHttpRequest createRequest(String method, URI uri) {
|
||||
|
@ -86,8 +102,14 @@ class ApacheClientHostRequestContext extends ApacheHttpClientTest<BasicHttpReque
|
|||
HttpResponse executeRequest(BasicHttpRequest request, URI uri) {
|
||||
return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request, new BasicHttpContext())
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRemoteConnection() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class ApacheClientHostRequestResponseHandler extends ApacheHttpClientTest<BasicHttpRequest> {
|
||||
@Override
|
||||
BasicHttpRequest createRequest(String method, URI uri) {
|
||||
|
@ -98,8 +120,14 @@ class ApacheClientHostRequestResponseHandler extends ApacheHttpClientTest<BasicH
|
|||
HttpResponse executeRequest(BasicHttpRequest request, URI uri) {
|
||||
return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request, { response -> response })
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRemoteConnection() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class ApacheClientHostRequestResponseHandlerContext extends ApacheHttpClientTest<BasicHttpRequest> {
|
||||
@Override
|
||||
BasicHttpRequest createRequest(String method, URI uri) {
|
||||
|
@ -110,8 +138,14 @@ class ApacheClientHostRequestResponseHandlerContext extends ApacheHttpClientTest
|
|||
HttpResponse executeRequest(BasicHttpRequest request, URI uri) {
|
||||
return client.execute(new HttpHost(uri.getHost(), uri.getPort()), request, { response -> response }, new BasicHttpContext())
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRemoteConnection() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class ApacheClientUriRequest extends ApacheHttpClientTest<HttpUriRequest> {
|
||||
@Override
|
||||
HttpUriRequest createRequest(String method, URI uri) {
|
||||
|
@ -124,6 +158,7 @@ class ApacheClientUriRequest extends ApacheHttpClientTest<HttpUriRequest> {
|
|||
}
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class ApacheClientUriRequestContext extends ApacheHttpClientTest<HttpUriRequest> {
|
||||
@Override
|
||||
HttpUriRequest createRequest(String method, URI uri) {
|
||||
|
@ -136,6 +171,7 @@ class ApacheClientUriRequestContext extends ApacheHttpClientTest<HttpUriRequest>
|
|||
}
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class ApacheClientUriRequestResponseHandler extends ApacheHttpClientTest<HttpUriRequest> {
|
||||
@Override
|
||||
HttpUriRequest createRequest(String method, URI uri) {
|
||||
|
@ -148,6 +184,7 @@ class ApacheClientUriRequestResponseHandler extends ApacheHttpClientTest<HttpUri
|
|||
}
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class ApacheClientUriRequestResponseHandlerContext extends ApacheHttpClientTest<HttpUriRequest> {
|
||||
@Override
|
||||
HttpUriRequest createRequest(String method, URI uri) {
|
||||
|
|
|
@ -38,6 +38,8 @@ abstract class AbstractGoogleHttpClientTest extends HttpClientTest {
|
|||
GenericUrl genericUrl = new GenericUrl(uri)
|
||||
|
||||
HttpRequest request = requestFactory.buildRequest(method, genericUrl, null)
|
||||
request.connectTimeout = CONNECT_TIMEOUT_MS
|
||||
request.readTimeout = READ_TIMEOUT_MS
|
||||
request.getHeaders().putAll(headers)
|
||||
request.setThrowExceptionOnExecuteError(throwExceptionOnError)
|
||||
|
||||
|
|
|
@ -15,7 +15,11 @@
|
|||
*/
|
||||
import com.google.api.client.http.HttpRequest
|
||||
import com.google.api.client.http.HttpResponse
|
||||
import spock.lang.Retry
|
||||
import spock.lang.Timeout
|
||||
|
||||
@Retry(condition = { !invocation.method.name.contains('circular redirects') })
|
||||
@Timeout(5)
|
||||
class GoogleHttpClientAsyncTest extends AbstractGoogleHttpClientTest {
|
||||
@Override
|
||||
HttpResponse executeRequest(HttpRequest request) {
|
||||
|
|
|
@ -15,7 +15,11 @@
|
|||
*/
|
||||
import com.google.api.client.http.HttpRequest
|
||||
import com.google.api.client.http.HttpResponse
|
||||
import spock.lang.Retry
|
||||
import spock.lang.Timeout
|
||||
|
||||
@Retry(condition = { !invocation.method.name.contains('circular redirects') })
|
||||
@Timeout(5)
|
||||
class GoogleHttpClientTest extends AbstractGoogleHttpClientTest {
|
||||
@Override
|
||||
HttpResponse executeRequest(HttpRequest request) {
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||
import spock.lang.Timeout
|
||||
|
||||
@Timeout(5)
|
||||
class HttpUrlConnectionResponseCodeOnlyTest extends HttpClientTest {
|
||||
|
||||
@Override
|
||||
|
@ -22,6 +24,8 @@ class HttpUrlConnectionResponseCodeOnlyTest extends HttpClientTest {
|
|||
HttpURLConnection connection = uri.toURL().openConnection()
|
||||
try {
|
||||
connection.setRequestMethod(method)
|
||||
connection.connectTimeout = CONNECT_TIMEOUT_MS
|
||||
connection.readTimeout = READ_TIMEOUT_MS
|
||||
headers.each { connection.setRequestProperty(it.key, it.value) }
|
||||
connection.setRequestProperty("Connection", "close")
|
||||
return connection.getResponseCode()
|
||||
|
|
|
@ -18,11 +18,13 @@ import io.opentelemetry.auto.instrumentation.api.Tags
|
|||
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||
import spock.lang.Ignore
|
||||
import spock.lang.Requires
|
||||
import spock.lang.Timeout
|
||||
import sun.net.www.protocol.https.HttpsURLConnectionImpl
|
||||
|
||||
import static io.opentelemetry.auto.test.utils.TraceUtils.runUnderTrace
|
||||
import static io.opentelemetry.trace.Span.Kind.CLIENT
|
||||
|
||||
@Timeout(5)
|
||||
class HttpUrlConnectionTest extends HttpClientTest {
|
||||
|
||||
static final RESPONSE = "Hello."
|
||||
|
@ -36,6 +38,8 @@ class HttpUrlConnectionTest extends HttpClientTest {
|
|||
headers.each { connection.setRequestProperty(it.key, it.value) }
|
||||
connection.setRequestProperty("Connection", "close")
|
||||
connection.useCaches = true
|
||||
connection.connectTimeout = CONNECT_TIMEOUT_MS
|
||||
connection.readTimeout = READ_TIMEOUT_MS
|
||||
def parentSpan = TEST_TRACER.getCurrentSpan()
|
||||
def stream = connection.inputStream
|
||||
assert TEST_TRACER.getCurrentSpan() == parentSpan
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||
import spock.lang.Timeout
|
||||
|
||||
@Timeout(5)
|
||||
class HttpUrlConnectionUseCachesFalseTest extends HttpClientTest {
|
||||
|
||||
@Override
|
||||
|
@ -25,6 +27,8 @@ class HttpUrlConnectionUseCachesFalseTest extends HttpClientTest {
|
|||
headers.each { connection.setRequestProperty(it.key, it.value) }
|
||||
connection.setRequestProperty("Connection", "close")
|
||||
connection.useCaches = false
|
||||
connection.connectTimeout = CONNECT_TIMEOUT_MS
|
||||
connection.readTimeout = READ_TIMEOUT_MS
|
||||
def parentSpan = TEST_TRACER.getCurrentSpan()
|
||||
def stream = connection.inputStream
|
||||
assert TEST_TRACER.getCurrentSpan() == parentSpan
|
||||
|
|
|
@ -18,13 +18,24 @@ import org.springframework.http.HttpEntity
|
|||
import org.springframework.http.HttpHeaders
|
||||
import org.springframework.http.HttpMethod
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.http.client.ClientHttpRequestFactory
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory
|
||||
import org.springframework.web.client.RestTemplate
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Timeout
|
||||
|
||||
@Timeout(5)
|
||||
class SpringRestTemplateTest extends HttpClientTest {
|
||||
|
||||
@Shared
|
||||
RestTemplate restTemplate = new RestTemplate()
|
||||
ClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory()
|
||||
@Shared
|
||||
RestTemplate restTemplate = new RestTemplate(factory)
|
||||
|
||||
def setupSpec() {
|
||||
factory.connectTimeout = CONNECT_TIMEOUT_MS
|
||||
factory.readTimeout = READ_TIMEOUT_MS
|
||||
}
|
||||
|
||||
@Override
|
||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||
|
@ -45,4 +56,10 @@ class SpringRestTemplateTest extends HttpClientTest {
|
|||
boolean testConnectionFailure() {
|
||||
false
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRemoteConnection() {
|
||||
// FIXME: exception wrapped in ResourceAccessException
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,13 +19,17 @@ import com.sun.jersey.api.client.filter.GZIPContentEncodingFilter
|
|||
import com.sun.jersey.api.client.filter.LoggingFilter
|
||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Timeout
|
||||
|
||||
@Timeout(5)
|
||||
class JaxRsClientV1Test extends HttpClientTest {
|
||||
|
||||
@Shared
|
||||
Client client = Client.create()
|
||||
|
||||
def setupSpec() {
|
||||
client.setConnectTimeout(CONNECT_TIMEOUT_MS)
|
||||
client.setReadTimeout(READ_TIMEOUT_MS)
|
||||
// Add filters to ensure spans aren't duplicated.
|
||||
client.addFilter(new LoggingFilter())
|
||||
client.addFilter(new GZIPContentEncodingFilter())
|
||||
|
|
|
@ -32,7 +32,8 @@ dependencies {
|
|||
testCompile group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.0.1'
|
||||
|
||||
testCompile group: 'org.glassfish.jersey.core', name: 'jersey-client', version: '2.0'
|
||||
testCompile group: 'org.jboss.resteasy', name: 'resteasy-client', version: '3.0.0.Final'
|
||||
testCompile group: 'org.jboss.resteasy', name: 'resteasy-client', version: '3.0.5.Final'
|
||||
// ^ This version has timeouts https://issues.redhat.com/browse/RESTEASY-975
|
||||
testCompile group: 'org.apache.cxf', name: 'cxf-rt-rs-client', version: '3.1.0'
|
||||
// Doesn't work with CXF 3.0.x because their context is wrong:
|
||||
// https://github.com/apache/cxf/commit/335c7bad2436f08d6d54180212df5a52157c9f21
|
||||
|
|
|
@ -15,8 +15,11 @@
|
|||
*/
|
||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||
import org.apache.cxf.jaxrs.client.spec.ClientBuilderImpl
|
||||
import org.glassfish.jersey.client.ClientConfig
|
||||
import org.glassfish.jersey.client.ClientProperties
|
||||
import org.glassfish.jersey.client.JerseyClientBuilder
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder
|
||||
import spock.lang.Timeout
|
||||
|
||||
import javax.ws.rs.client.AsyncInvoker
|
||||
import javax.ws.rs.client.Client
|
||||
|
@ -27,6 +30,7 @@ import javax.ws.rs.client.WebTarget
|
|||
import javax.ws.rs.core.MediaType
|
||||
import javax.ws.rs.core.Response
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
abstract class JaxRsClientAsyncTest extends HttpClientTest {
|
||||
|
||||
|
@ -61,11 +65,15 @@ abstract class JaxRsClientAsyncTest extends HttpClientTest {
|
|||
abstract ClientBuilder builder()
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class JerseyClientAsyncTest extends JaxRsClientAsyncTest {
|
||||
|
||||
@Override
|
||||
ClientBuilder builder() {
|
||||
return new JerseyClientBuilder()
|
||||
ClientConfig config = new ClientConfig()
|
||||
config.property(ClientProperties.CONNECT_TIMEOUT, CONNECT_TIMEOUT_MS)
|
||||
config.property(ClientProperties.READ_TIMEOUT, READ_TIMEOUT_MS)
|
||||
return new JerseyClientBuilder().withConfig(config)
|
||||
}
|
||||
|
||||
boolean testCircularRedirects() {
|
||||
|
@ -73,11 +81,14 @@ class JerseyClientAsyncTest extends JaxRsClientAsyncTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class ResteasyClientAsyncTest extends JaxRsClientAsyncTest {
|
||||
|
||||
@Override
|
||||
ClientBuilder builder() {
|
||||
return new ResteasyClientBuilder()
|
||||
.establishConnectionTimeout(CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||
.socketTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||
}
|
||||
|
||||
boolean testRedirects() {
|
||||
|
@ -85,6 +96,7 @@ class ResteasyClientAsyncTest extends JaxRsClientAsyncTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class CxfClientAsyncTest extends JaxRsClientAsyncTest {
|
||||
|
||||
@Override
|
||||
|
@ -99,4 +111,9 @@ class CxfClientAsyncTest extends JaxRsClientAsyncTest {
|
|||
boolean testConnectionFailure() {
|
||||
false
|
||||
}
|
||||
|
||||
boolean testRemoteConnection() {
|
||||
// FIXME: span not reported correctly.
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,11 @@
|
|||
*/
|
||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||
import org.apache.cxf.jaxrs.client.spec.ClientBuilderImpl
|
||||
import org.glassfish.jersey.client.ClientConfig
|
||||
import org.glassfish.jersey.client.ClientProperties
|
||||
import org.glassfish.jersey.client.JerseyClientBuilder
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder
|
||||
import spock.lang.Timeout
|
||||
|
||||
import javax.ws.rs.client.Client
|
||||
import javax.ws.rs.client.ClientBuilder
|
||||
|
@ -25,6 +28,7 @@ import javax.ws.rs.client.Invocation
|
|||
import javax.ws.rs.client.WebTarget
|
||||
import javax.ws.rs.core.MediaType
|
||||
import javax.ws.rs.core.Response
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
abstract class JaxRsClientTest extends HttpClientTest {
|
||||
|
||||
|
@ -45,11 +49,15 @@ abstract class JaxRsClientTest extends HttpClientTest {
|
|||
abstract ClientBuilder builder()
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class JerseyClientTest extends JaxRsClientTest {
|
||||
|
||||
@Override
|
||||
ClientBuilder builder() {
|
||||
return new JerseyClientBuilder()
|
||||
ClientConfig config = new ClientConfig()
|
||||
config.property(ClientProperties.CONNECT_TIMEOUT, CONNECT_TIMEOUT_MS)
|
||||
config.property(ClientProperties.READ_TIMEOUT, READ_TIMEOUT_MS)
|
||||
return new JerseyClientBuilder().withConfig(config)
|
||||
}
|
||||
|
||||
boolean testCircularRedirects() {
|
||||
|
@ -57,24 +65,29 @@ class JerseyClientTest extends JaxRsClientTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class ResteasyClientTest extends JaxRsClientTest {
|
||||
|
||||
@Override
|
||||
ClientBuilder builder() {
|
||||
return new ResteasyClientBuilder()
|
||||
.establishConnectionTimeout(CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||
.socketTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||
}
|
||||
|
||||
boolean testRedirects() {
|
||||
false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class CxfClientTest extends JaxRsClientTest {
|
||||
|
||||
@Override
|
||||
ClientBuilder builder() {
|
||||
return new ClientBuilderImpl()
|
||||
// .property(ClientImpl.HTTP_CONNECTION_TIMEOUT_PROP, (long) CONNECT_TIMEOUT_MS)
|
||||
// .property(ClientImpl.HTTP_RECEIVE_TIMEOUT_PROP, (long) READ_TIMEOUT_MS)
|
||||
}
|
||||
|
||||
boolean testRedirects() {
|
||||
|
@ -84,4 +97,9 @@ class CxfClientTest extends JaxRsClientTest {
|
|||
boolean testConnectionFailure() {
|
||||
false
|
||||
}
|
||||
|
||||
boolean testRemoteConnection() {
|
||||
// FIXME: span not reported correctly.
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import com.ning.http.client.AsyncCompletionHandler
|
|||
import com.ning.http.client.AsyncHttpClient
|
||||
import com.ning.http.client.AsyncHttpClientConfig
|
||||
import com.ning.http.client.Response
|
||||
import io.opentelemetry.auto.instrumentation.api.Tags
|
||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Shared
|
||||
|
@ -65,6 +64,11 @@ class Netty38ClientTest extends HttpClientTest {
|
|||
false
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRemoteConnection() {
|
||||
return false
|
||||
}
|
||||
|
||||
def "connection error (unopened port)"() {
|
||||
given:
|
||||
def uri = new URI("http://127.0.0.1:$UNUSABLE_PORT/")
|
||||
|
@ -88,7 +92,6 @@ class Netty38ClientTest extends HttpClientTest {
|
|||
childOf span(0)
|
||||
errored true
|
||||
tags {
|
||||
"$Tags.COMPONENT" "netty"
|
||||
Class errorClass = ConnectException
|
||||
try {
|
||||
errorClass = Class.forName('io.netty.channel.AbstractChannel$AnnotatedConnectException')
|
||||
|
|
|
@ -17,9 +17,9 @@ import io.opentelemetry.auto.test.base.HttpServerTest
|
|||
import org.jboss.netty.bootstrap.ServerBootstrap
|
||||
import org.jboss.netty.buffer.ChannelBuffer
|
||||
import org.jboss.netty.buffer.ChannelBuffers
|
||||
import org.jboss.netty.channel.Channel
|
||||
import org.jboss.netty.channel.ChannelHandlerContext
|
||||
import org.jboss.netty.channel.ChannelPipeline
|
||||
import org.jboss.netty.channel.ChannelPipelineFactory
|
||||
import org.jboss.netty.channel.DefaultChannelPipeline
|
||||
import org.jboss.netty.channel.DownstreamMessageEvent
|
||||
import org.jboss.netty.channel.ExceptionEvent
|
||||
|
@ -35,6 +35,8 @@ import org.jboss.netty.handler.codec.http.HttpResponseStatus
|
|||
import org.jboss.netty.handler.codec.http.HttpServerCodec
|
||||
import org.jboss.netty.handler.logging.LoggingHandler
|
||||
import org.jboss.netty.logging.InternalLogLevel
|
||||
import org.jboss.netty.logging.InternalLoggerFactory
|
||||
import org.jboss.netty.logging.Slf4JLoggerFactory
|
||||
import org.jboss.netty.util.CharsetUtil
|
||||
|
||||
import static io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint.ERROR
|
||||
|
@ -49,10 +51,17 @@ import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE
|
|||
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.LOCATION
|
||||
import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1
|
||||
|
||||
class Netty38ServerTest extends HttpServerTest<Channel> {
|
||||
class Netty38ServerTest extends HttpServerTest<ServerBootstrap> {
|
||||
|
||||
static final LoggingHandler LOGGING_HANDLER
|
||||
static {
|
||||
InternalLoggerFactory.setDefaultFactory(new Slf4JLoggerFactory())
|
||||
LOGGING_HANDLER = new LoggingHandler(SERVER_LOGGER.name, InternalLogLevel.DEBUG, true)
|
||||
}
|
||||
|
||||
ChannelPipeline channelPipeline() {
|
||||
ChannelPipeline channelPipeline = new DefaultChannelPipeline()
|
||||
channelPipeline.addFirst("logger", LOGGING_HANDLER)
|
||||
|
||||
channelPipeline.addLast("http-codec", new HttpServerCodec())
|
||||
channelPipeline.addLast("controller", new SimpleChannelHandler() {
|
||||
|
@ -103,7 +112,8 @@ class Netty38ServerTest extends HttpServerTest<Channel> {
|
|||
|
||||
@Override
|
||||
void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent ex) throws Exception {
|
||||
ChannelBuffer buffer = ChannelBuffers.copiedBuffer(ex.getCause().getMessage(), CharsetUtil.UTF_8)
|
||||
def message = ex.getCause() == null ? "<no cause> " + ex.message : ex.cause.message == null ? "<null>" : ex.cause.message
|
||||
ChannelBuffer buffer = ChannelBuffers.copiedBuffer(message, CharsetUtil.UTF_8)
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR)
|
||||
response.setContent(buffer)
|
||||
response.headers().set(CONTENT_TYPE, "text/plain")
|
||||
|
@ -120,17 +130,23 @@ class Netty38ServerTest extends HttpServerTest<Channel> {
|
|||
}
|
||||
|
||||
@Override
|
||||
Channel startServer(int port) {
|
||||
ServerBootstrap startServer(int port) {
|
||||
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory())
|
||||
bootstrap.setParentHandler(new LoggingHandler(InternalLogLevel.INFO))
|
||||
bootstrap.setPipeline(channelPipeline())
|
||||
bootstrap.setParentHandler(LOGGING_HANDLER)
|
||||
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
|
||||
@Override
|
||||
ChannelPipeline getPipeline() throws Exception {
|
||||
return channelPipeline()
|
||||
}
|
||||
})
|
||||
|
||||
InetSocketAddress address = new InetSocketAddress(port)
|
||||
return bootstrap.bind(address)
|
||||
bootstrap.bind(address)
|
||||
return bootstrap
|
||||
}
|
||||
|
||||
@Override
|
||||
void stopServer(Channel server) {
|
||||
server?.disconnect()
|
||||
void stopServer(ServerBootstrap server) {
|
||||
server?.shutdown()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
|||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.auto.bootstrap.ContextStore;
|
||||
import io.opentelemetry.auto.bootstrap.InstrumentationContext;
|
||||
import io.opentelemetry.auto.instrumentation.api.Tags;
|
||||
import io.opentelemetry.auto.instrumentation.netty.v3_8.server.NettyHttpServerDecorator;
|
||||
import io.opentelemetry.auto.tooling.Instrumenter;
|
||||
import io.opentelemetry.context.Scope;
|
||||
|
@ -113,11 +112,7 @@ public class ChannelFutureListenerInstrumentation extends Instrumenter.Default {
|
|||
final Scope parentScope = NettyHttpServerDecorator.TRACER.withSpan(continuation);
|
||||
|
||||
final Span errorSpan =
|
||||
NettyHttpServerDecorator.TRACER
|
||||
.spanBuilder("CONNECT")
|
||||
.setSpanKind(CLIENT)
|
||||
.setAttribute(Tags.COMPONENT, "netty")
|
||||
.startSpan();
|
||||
NettyHttpServerDecorator.TRACER.spanBuilder("CONNECT").setSpanKind(CLIENT).startSpan();
|
||||
try (final Scope scope = NettyHttpServerDecorator.TRACER.withSpan(errorSpan)) {
|
||||
NettyHttpServerDecorator.DECORATE.onError(errorSpan, cause);
|
||||
NettyHttpServerDecorator.DECORATE.beforeFinish(errorSpan);
|
||||
|
|
|
@ -17,7 +17,6 @@ import com.ning.http.client.AsyncCompletionHandler
|
|||
import com.ning.http.client.AsyncHttpClient
|
||||
import com.ning.http.client.AsyncHttpClientConfig
|
||||
import com.ning.http.client.Response
|
||||
import io.opentelemetry.auto.instrumentation.api.Tags
|
||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Shared
|
||||
|
@ -65,6 +64,11 @@ class Netty38ClientTest extends HttpClientTest {
|
|||
false
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRemoteConnection() {
|
||||
return false
|
||||
}
|
||||
|
||||
def "connection error (unopened port)"() {
|
||||
given:
|
||||
def uri = new URI("http://127.0.0.1:$UNUSABLE_PORT/")
|
||||
|
@ -88,7 +92,6 @@ class Netty38ClientTest extends HttpClientTest {
|
|||
childOf span(0)
|
||||
errored true
|
||||
tags {
|
||||
"$Tags.COMPONENT" "netty"
|
||||
Class errorClass = ConnectException
|
||||
try {
|
||||
errorClass = Class.forName('io.netty.channel.AbstractChannel$AnnotatedConnectException')
|
||||
|
|
|
@ -17,9 +17,9 @@ import io.opentelemetry.auto.test.base.HttpServerTest
|
|||
import org.jboss.netty.bootstrap.ServerBootstrap
|
||||
import org.jboss.netty.buffer.ChannelBuffer
|
||||
import org.jboss.netty.buffer.ChannelBuffers
|
||||
import org.jboss.netty.channel.Channel
|
||||
import org.jboss.netty.channel.ChannelHandlerContext
|
||||
import org.jboss.netty.channel.ChannelPipeline
|
||||
import org.jboss.netty.channel.ChannelPipelineFactory
|
||||
import org.jboss.netty.channel.DefaultChannelPipeline
|
||||
import org.jboss.netty.channel.DownstreamMessageEvent
|
||||
import org.jboss.netty.channel.ExceptionEvent
|
||||
|
@ -35,6 +35,8 @@ import org.jboss.netty.handler.codec.http.HttpResponseStatus
|
|||
import org.jboss.netty.handler.codec.http.HttpServerCodec
|
||||
import org.jboss.netty.handler.logging.LoggingHandler
|
||||
import org.jboss.netty.logging.InternalLogLevel
|
||||
import org.jboss.netty.logging.InternalLoggerFactory
|
||||
import org.jboss.netty.logging.Slf4JLoggerFactory
|
||||
import org.jboss.netty.util.CharsetUtil
|
||||
|
||||
import static io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint.ERROR
|
||||
|
@ -49,10 +51,17 @@ import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE
|
|||
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.LOCATION
|
||||
import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1
|
||||
|
||||
class Netty38ServerTest extends HttpServerTest<Channel> {
|
||||
class Netty38ServerTest extends HttpServerTest<ServerBootstrap> {
|
||||
|
||||
static final LoggingHandler LOGGING_HANDLER
|
||||
static {
|
||||
InternalLoggerFactory.setDefaultFactory(new Slf4JLoggerFactory())
|
||||
LOGGING_HANDLER = new LoggingHandler(SERVER_LOGGER.name, InternalLogLevel.DEBUG, true)
|
||||
}
|
||||
|
||||
ChannelPipeline channelPipeline() {
|
||||
ChannelPipeline channelPipeline = new DefaultChannelPipeline()
|
||||
channelPipeline.addFirst("logger", LOGGING_HANDLER)
|
||||
|
||||
channelPipeline.addLast("http-codec", new HttpServerCodec())
|
||||
channelPipeline.addLast("controller", new SimpleChannelHandler() {
|
||||
|
@ -103,7 +112,8 @@ class Netty38ServerTest extends HttpServerTest<Channel> {
|
|||
|
||||
@Override
|
||||
void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent ex) throws Exception {
|
||||
ChannelBuffer buffer = ChannelBuffers.copiedBuffer(ex.getCause().getMessage(), CharsetUtil.UTF_8)
|
||||
def message = ex.cause == null ? "<no cause> " + ex.message : ex.cause.message == null ? "<null>" : ex.cause.message
|
||||
ChannelBuffer buffer = ChannelBuffers.copiedBuffer(message, CharsetUtil.UTF_8)
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR)
|
||||
response.setContent(buffer)
|
||||
response.headers().set(CONTENT_TYPE, "text/plain")
|
||||
|
@ -120,17 +130,23 @@ class Netty38ServerTest extends HttpServerTest<Channel> {
|
|||
}
|
||||
|
||||
@Override
|
||||
Channel startServer(int port) {
|
||||
ServerBootstrap startServer(int port) {
|
||||
ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory())
|
||||
bootstrap.setParentHandler(new LoggingHandler(InternalLogLevel.INFO))
|
||||
bootstrap.setPipeline(channelPipeline())
|
||||
bootstrap.setParentHandler(LOGGING_HANDLER)
|
||||
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
|
||||
@Override
|
||||
ChannelPipeline getPipeline() throws Exception {
|
||||
return channelPipeline()
|
||||
}
|
||||
})
|
||||
|
||||
InetSocketAddress address = new InetSocketAddress(port)
|
||||
return bootstrap.bind(address)
|
||||
bootstrap.bind(address)
|
||||
return bootstrap
|
||||
}
|
||||
|
||||
@Override
|
||||
void stopServer(Channel server) {
|
||||
server?.disconnect()
|
||||
void stopServer(ServerBootstrap server) {
|
||||
server?.shutdown()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.asynchttpclient.DefaultAsyncHttpClientConfig
|
|||
import org.asynchttpclient.Response
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Timeout
|
||||
|
||||
import java.util.concurrent.ExecutionException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -29,6 +30,7 @@ import static io.opentelemetry.auto.test.utils.TraceUtils.basicSpan
|
|||
import static io.opentelemetry.auto.test.utils.TraceUtils.runUnderTrace
|
||||
import static org.asynchttpclient.Dsl.asyncHttpClient
|
||||
|
||||
@Timeout(5)
|
||||
class Netty40ClientTest extends HttpClientTest {
|
||||
|
||||
@Shared
|
||||
|
@ -62,6 +64,11 @@ class Netty40ClientTest extends HttpClientTest {
|
|||
false
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRemoteConnection() {
|
||||
return false
|
||||
}
|
||||
|
||||
def "connection error (unopened port)"() {
|
||||
given:
|
||||
def uri = new URI("http://127.0.0.1:$UNUSABLE_PORT/") // Use numeric address to avoid ipv4/ipv6 confusion
|
||||
|
|
|
@ -48,16 +48,20 @@ import static io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint.SUCC
|
|||
|
||||
class Netty40ServerTest extends HttpServerTest<EventLoopGroup> {
|
||||
|
||||
static final LoggingHandler LOGGING_HANDLER = new LoggingHandler(SERVER_LOGGER.name, LogLevel.DEBUG)
|
||||
|
||||
@Override
|
||||
EventLoopGroup startServer(int port) {
|
||||
def eventLoopGroup = new NioEventLoopGroup()
|
||||
|
||||
ServerBootstrap bootstrap = new ServerBootstrap()
|
||||
.group(eventLoopGroup)
|
||||
.handler(new LoggingHandler(LogLevel.INFO))
|
||||
.handler(LOGGING_HANDLER)
|
||||
.childHandler([
|
||||
initChannel: { ch ->
|
||||
ChannelPipeline pipeline = ch.pipeline()
|
||||
pipeline.addFirst("logger", LOGGING_HANDLER)
|
||||
|
||||
def handlers = [new HttpRequestDecoder(), new HttpResponseEncoder()]
|
||||
handlers.each { pipeline.addLast(it) }
|
||||
pipeline.addLast([
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.asynchttpclient.DefaultAsyncHttpClientConfig
|
|||
import org.asynchttpclient.Response
|
||||
import spock.lang.Retry
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Timeout
|
||||
|
||||
import java.util.concurrent.ExecutionException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -39,6 +40,7 @@ import static io.opentelemetry.auto.test.utils.TraceUtils.runUnderTrace
|
|||
import static org.asynchttpclient.Dsl.asyncHttpClient
|
||||
|
||||
@Retry
|
||||
@Timeout(5)
|
||||
class Netty41ClientTest extends HttpClientTest {
|
||||
|
||||
@Shared
|
||||
|
@ -71,6 +73,11 @@ class Netty41ClientTest extends HttpClientTest {
|
|||
false
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRemoteConnection() {
|
||||
return false
|
||||
}
|
||||
|
||||
def "connection error (unopened port)"() {
|
||||
given:
|
||||
def uri = new URI("http://localhost:$UNUSABLE_PORT/")
|
||||
|
|
|
@ -47,16 +47,20 @@ import static io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint.SUCC
|
|||
|
||||
class Netty41ServerTest extends HttpServerTest<EventLoopGroup> {
|
||||
|
||||
static final LoggingHandler LOGGING_HANDLER = new LoggingHandler(SERVER_LOGGER.name, LogLevel.DEBUG)
|
||||
|
||||
@Override
|
||||
EventLoopGroup startServer(int port) {
|
||||
def eventLoopGroup = new NioEventLoopGroup()
|
||||
|
||||
ServerBootstrap bootstrap = new ServerBootstrap()
|
||||
.group(eventLoopGroup)
|
||||
.handler(new LoggingHandler(LogLevel.INFO))
|
||||
.handler(LOGGING_HANDLER)
|
||||
.childHandler([
|
||||
initChannel: { ch ->
|
||||
ChannelPipeline pipeline = ch.pipeline()
|
||||
pipeline.addFirst("logger", LOGGING_HANDLER)
|
||||
|
||||
def handlers = [new HttpServerCodec()]
|
||||
handlers.each { pipeline.addLast(it) }
|
||||
pipeline.addLast([
|
||||
|
|
|
@ -20,10 +20,18 @@ import okhttp3.OkHttpClient
|
|||
import okhttp3.Request
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.internal.http.HttpMethod
|
||||
import spock.lang.Timeout
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@Timeout(5)
|
||||
class OkHttp3Test extends HttpClientTest {
|
||||
|
||||
def client = new OkHttpClient()
|
||||
def client = new OkHttpClient.Builder()
|
||||
.connectTimeout(CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||
.readTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||
.writeTimeout(READ_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||
.build()
|
||||
|
||||
@Override
|
||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||
|
|
|
@ -23,9 +23,11 @@ import scala.concurrent.ExecutionContext
|
|||
import scala.concurrent.Future
|
||||
import scala.concurrent.duration.Duration
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Timeout
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@Timeout(5)
|
||||
class PlayJavaWSClientTest extends PlayWSClientTestBase {
|
||||
@Shared
|
||||
StandaloneWSClient wsClient
|
||||
|
@ -52,6 +54,7 @@ class PlayJavaWSClientTest extends PlayWSClientTestBase {
|
|||
}
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class PlayJavaStreamedWSClientTest extends PlayWSClientTestBase {
|
||||
@Shared
|
||||
StandaloneWSClient wsClient
|
||||
|
@ -81,6 +84,7 @@ class PlayJavaStreamedWSClientTest extends PlayWSClientTestBase {
|
|||
}
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class PlayScalaWSClientTest extends PlayWSClientTestBase {
|
||||
@Shared
|
||||
play.api.libs.ws.StandaloneWSClient wsClient
|
||||
|
@ -111,6 +115,7 @@ class PlayScalaWSClientTest extends PlayWSClientTestBase {
|
|||
}
|
||||
}
|
||||
|
||||
@Timeout(5)
|
||||
class PlayScalaStreamedWSClientTest extends PlayWSClientTestBase {
|
||||
@Shared
|
||||
play.api.libs.ws.StandaloneWSClient wsClient
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
logs/
|
|
@ -0,0 +1,57 @@
|
|||
ext {
|
||||
minJavaVersionForTests = JavaVersion.VERSION_1_8
|
||||
// Play doesn't work with Java 9+ until 2.6.12
|
||||
maxJavaVersionForTests = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
apply from: "${rootDir}/gradle/instrumentation.gradle"
|
||||
apply from: "${rootDir}/gradle/test-with-scala.gradle"
|
||||
apply plugin: 'org.unbroken-dome.test-sets'
|
||||
|
||||
muzzle {
|
||||
pass {
|
||||
group = 'com.typesafe.play'
|
||||
module = 'play_2.11'
|
||||
versions = '[2.3.0,2.4)'
|
||||
assertInverse = true
|
||||
}
|
||||
fail {
|
||||
group = 'com.typesafe.play'
|
||||
module = 'play_2.12'
|
||||
versions = '[,]'
|
||||
}
|
||||
fail {
|
||||
group = 'com.typesafe.play'
|
||||
module = 'play_2.13'
|
||||
versions = '[,]'
|
||||
}
|
||||
}
|
||||
|
||||
testSets {
|
||||
latestDepTest {
|
||||
dirName = 'test'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
main_java8Compile group: 'com.typesafe.play', name: 'play_2.11', version: '2.3.0'
|
||||
|
||||
testCompile project(':instrumentation:netty:netty-3.8')
|
||||
|
||||
testCompile group: 'com.typesafe.play', name: 'play-java_2.11', version: '2.3.0'
|
||||
testCompile group: 'com.typesafe.play', name: 'play-java-ws_2.11', version: '2.3.0'
|
||||
testCompile(group: 'com.typesafe.play', name: 'play-test_2.11', version: '2.3.0') {
|
||||
exclude group: 'org.eclipse.jetty', module: 'jetty-websocket'
|
||||
}
|
||||
|
||||
latestDepTestCompile group: 'com.typesafe.play', name: 'play-java_2.11', version: '2.3.+'
|
||||
latestDepTestCompile group: 'com.typesafe.play', name: 'play-java-ws_2.11', version: '2.3.+'
|
||||
latestDepTestCompile(group: 'com.typesafe.play', name: 'play-test_2.11', version: '2.3.+') {
|
||||
exclude group: 'org.eclipse.jetty', module: 'jetty-websocket'
|
||||
}
|
||||
}
|
||||
|
||||
compileLatestDepTestGroovy {
|
||||
classpath = classpath.plus(files(compileLatestDepTestScala.destinationDir))
|
||||
dependsOn compileLatestDepTestScala
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry 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 io.opentelemetry.auto.instrumentation.play.v2_3;
|
||||
|
||||
import static io.opentelemetry.auto.tooling.ClassLoaderMatcher.hasClassesNamed;
|
||||
import static io.opentelemetry.auto.tooling.bytebuddy.matcher.AgentElementMatchers.implementsInterface;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.returns;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.auto.tooling.Instrumenter;
|
||||
import java.util.Map;
|
||||
import net.bytebuddy.description.method.MethodDescription;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
@AutoService(Instrumenter.class)
|
||||
public final class PlayInstrumentation extends Instrumenter.Default {
|
||||
|
||||
public PlayInstrumentation() {
|
||||
super("play", "play-action");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<ClassLoader> classLoaderMatcher() {
|
||||
// Optimization for expensive typeMatcher.
|
||||
return hasClassesNamed("play.api.mvc.Action");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||
return implementsInterface(named("play.api.mvc.Action"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] helperClassNames() {
|
||||
return new String[] {
|
||||
packageName + ".PlayHttpServerDecorator",
|
||||
packageName + ".RequestCompleteCallback",
|
||||
packageName + ".PlayHeaders",
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
|
||||
return singletonMap(
|
||||
named("apply")
|
||||
.and(takesArgument(0, named("play.api.mvc.Request")))
|
||||
.and(returns(named("scala.concurrent.Future"))),
|
||||
packageName + ".PlayAdvice");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry 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 io.opentelemetry.auto.instrumentation.play.v2_3;
|
||||
|
||||
import static io.opentelemetry.auto.bootstrap.instrumentation.decorator.BaseDecorator.extract;
|
||||
import static io.opentelemetry.auto.instrumentation.play.v2_3.PlayHeaders.GETTER;
|
||||
import static io.opentelemetry.auto.instrumentation.play.v2_3.PlayHttpServerDecorator.DECORATE;
|
||||
import static io.opentelemetry.auto.instrumentation.play.v2_3.PlayHttpServerDecorator.TRACER;
|
||||
import static io.opentelemetry.trace.TracingContextUtils.currentContextWith;
|
||||
|
||||
import io.opentelemetry.auto.instrumentation.api.SpanWithScope;
|
||||
import io.opentelemetry.auto.instrumentation.api.Tags;
|
||||
import io.opentelemetry.trace.Span;
|
||||
import io.opentelemetry.trace.SpanContext;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import play.api.mvc.Action;
|
||||
import play.api.mvc.Request;
|
||||
import play.api.mvc.Result;
|
||||
import scala.concurrent.Future;
|
||||
|
||||
public class PlayAdvice {
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static SpanWithScope onEnter(@Advice.Argument(0) final Request req) {
|
||||
final Span.Builder spanBuilder = TRACER.spanBuilder("play.request");
|
||||
if (!TRACER.getCurrentSpan().getContext().isValid()) {
|
||||
final SpanContext extractedContext = extract(req.headers(), GETTER);
|
||||
if (extractedContext.isValid()) {
|
||||
spanBuilder.setParent(extractedContext);
|
||||
}
|
||||
} else {
|
||||
// An upstream framework (e.g. akka-http, netty) has already started the span.
|
||||
// Do not extract the context.
|
||||
}
|
||||
final Span span = spanBuilder.startSpan();
|
||||
DECORATE.afterStart(span);
|
||||
DECORATE.onConnection(span, req);
|
||||
|
||||
return new SpanWithScope(span, currentContextWith(span));
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void stopTraceOnResponse(
|
||||
@Advice.Enter final SpanWithScope playControllerScope,
|
||||
@Advice.This final Object thisAction,
|
||||
@Advice.Thrown final Throwable throwable,
|
||||
@Advice.Argument(0) final Request req,
|
||||
@Advice.Return(readOnly = false) final Future<Result> responseFuture) {
|
||||
final Span playControllerSpan = playControllerScope.getSpan();
|
||||
|
||||
// Call onRequest on return after tags are populated.
|
||||
DECORATE.onRequest(playControllerSpan, req);
|
||||
|
||||
if (throwable == null) {
|
||||
responseFuture.onComplete(
|
||||
new RequestCompleteCallback(playControllerSpan),
|
||||
((Action) thisAction).executionContext());
|
||||
} else {
|
||||
DECORATE.onError(playControllerSpan, throwable);
|
||||
playControllerSpan.setAttribute(Tags.HTTP_STATUS, 500);
|
||||
DECORATE.beforeFinish(playControllerSpan);
|
||||
playControllerSpan.end();
|
||||
}
|
||||
playControllerScope.closeScope();
|
||||
|
||||
final Span rootSpan = TRACER.getCurrentSpan();
|
||||
// set the resource name on the upstream akka/netty span
|
||||
DECORATE.onRequest(rootSpan, req);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry 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 io.opentelemetry.auto.instrumentation.play.v2_3;
|
||||
|
||||
import io.opentelemetry.context.propagation.HttpTextFormat;
|
||||
import play.api.mvc.Headers;
|
||||
import scala.Option;
|
||||
|
||||
public class PlayHeaders implements HttpTextFormat.Getter<Headers> {
|
||||
|
||||
public static final PlayHeaders GETTER = new PlayHeaders();
|
||||
|
||||
@Override
|
||||
public String get(final Headers headers, final String key) {
|
||||
final Option<String> option = headers.get(key);
|
||||
if (option.isDefined()) {
|
||||
return option.get();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry 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 io.opentelemetry.auto.instrumentation.play.v2_3;
|
||||
|
||||
import io.opentelemetry.OpenTelemetry;
|
||||
import io.opentelemetry.auto.bootstrap.instrumentation.decorator.HttpServerDecorator;
|
||||
import io.opentelemetry.auto.instrumentation.api.Tags;
|
||||
import io.opentelemetry.trace.Span;
|
||||
import io.opentelemetry.trace.Tracer;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import play.api.mvc.Request;
|
||||
import play.api.mvc.Result;
|
||||
import scala.Option;
|
||||
|
||||
@Slf4j
|
||||
public class PlayHttpServerDecorator extends HttpServerDecorator<Request, Request, Result> {
|
||||
public static final PlayHttpServerDecorator DECORATE = new PlayHttpServerDecorator();
|
||||
|
||||
public static final Tracer TRACER =
|
||||
OpenTelemetry.getTracerProvider().get("io.opentelemetry.auto.play-2.4");
|
||||
|
||||
@Override
|
||||
protected String getComponentName() {
|
||||
return "play-action";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String method(final Request httpRequest) {
|
||||
return httpRequest.method();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URI url(final Request request) throws URISyntaxException {
|
||||
return new URI((request.secure() ? "https://" : "http://") + request.host() + request.uri());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String peerHostIP(final Request request) {
|
||||
return request.remoteAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer peerPort(final Request request) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer status(final Result httpResponse) {
|
||||
return httpResponse.header().status();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span onRequest(final Span span, final Request request) {
|
||||
super.onRequest(span, request);
|
||||
if (request != null) {
|
||||
// more about routes here:
|
||||
// https://github.com/playframework/playframework/blob/master/documentation/manual/releases/release26/migration26/Migration26.md#router-tags-are-now-attributes
|
||||
final Option pathOption = request.tags().get("ROUTE_PATTERN");
|
||||
if (!pathOption.isEmpty()) {
|
||||
final String path = (String) pathOption.get();
|
||||
span.updateName(request.method() + " " + path);
|
||||
}
|
||||
}
|
||||
return span;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span onError(final Span span, Throwable throwable) {
|
||||
span.setAttribute(Tags.HTTP_STATUS, 500);
|
||||
if (throwable != null
|
||||
// This can be moved to instanceof check when using Java 8.
|
||||
&& throwable.getClass().getName().equals("java.util.concurrent.CompletionException")
|
||||
&& throwable.getCause() != null) {
|
||||
throwable = throwable.getCause();
|
||||
}
|
||||
while ((throwable instanceof InvocationTargetException
|
||||
|| throwable instanceof UndeclaredThrowableException)
|
||||
&& throwable.getCause() != null) {
|
||||
throwable = throwable.getCause();
|
||||
}
|
||||
return super.onError(span, throwable);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry 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 io.opentelemetry.auto.instrumentation.play.v2_3;
|
||||
|
||||
import static io.opentelemetry.auto.instrumentation.play.v2_3.PlayHttpServerDecorator.DECORATE;
|
||||
|
||||
import io.opentelemetry.trace.Span;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import play.api.mvc.Result;
|
||||
import scala.util.Try;
|
||||
|
||||
@Slf4j
|
||||
public class RequestCompleteCallback extends scala.runtime.AbstractFunction1<Try<Result>, Object> {
|
||||
private final Span span;
|
||||
|
||||
public RequestCompleteCallback(final Span span) {
|
||||
this.span = span;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object apply(final Try<Result> result) {
|
||||
try {
|
||||
if (result.isFailure()) {
|
||||
DECORATE.onError(span, result.failed().get());
|
||||
} else {
|
||||
DECORATE.onResponse(span, result.get());
|
||||
}
|
||||
DECORATE.beforeFinish(span);
|
||||
} catch (final Throwable t) {
|
||||
log.debug("error in play instrumentation", t);
|
||||
} finally {
|
||||
span.end();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry 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 client
|
||||
|
||||
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||
import play.GlobalSettings
|
||||
import play.libs.ws.WS
|
||||
import play.test.FakeApplication
|
||||
import play.test.Helpers
|
||||
import spock.lang.Shared
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class PlayWSClientTest extends HttpClientTest {
|
||||
@Shared
|
||||
def application = new FakeApplication(
|
||||
new File("."),
|
||||
FakeApplication.getClassLoader(),
|
||||
[
|
||||
"ws.timeout.connection": CONNECT_TIMEOUT_MS,
|
||||
"ws.timeout.request" : READ_TIMEOUT_MS
|
||||
],
|
||||
Collections.emptyList(),
|
||||
new GlobalSettings()
|
||||
)
|
||||
|
||||
@Shared
|
||||
def client
|
||||
|
||||
def setupSpec() {
|
||||
Helpers.start(application)
|
||||
client = WS.client()
|
||||
}
|
||||
|
||||
def cleanupSpec() {
|
||||
Helpers.stop(application)
|
||||
}
|
||||
|
||||
@Override
|
||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||
def request = client.url(uri.toString())
|
||||
headers.entrySet().each {
|
||||
request.setHeader(it.key, it.value)
|
||||
}
|
||||
|
||||
def status = request.execute(method).map({
|
||||
callback?.call()
|
||||
it
|
||||
}).map({
|
||||
it.status
|
||||
})
|
||||
return status.get(1, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRedirects() {
|
||||
false
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testConnectionFailure() {
|
||||
false
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRemoteConnection() {
|
||||
// On connection failures the operation and resource names end up different from expected.
|
||||
// This would require a lot of changes to the base client test class to support
|
||||
// span.operationName = "netty.connect"
|
||||
// span.resourceName = "netty.connect"
|
||||
false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry 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 server;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.auto.test.base.HttpServerTestAdvice;
|
||||
import io.opentelemetry.auto.tooling.Instrumenter;
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
|
||||
@AutoService(Instrumenter.class)
|
||||
public class NettyServerTestInstrumentation implements Instrumenter {
|
||||
|
||||
@Override
|
||||
public AgentBuilder instrument(final AgentBuilder agentBuilder) {
|
||||
return agentBuilder
|
||||
.type(named("org.jboss.netty.handler.codec.http.HttpRequestDecoder"))
|
||||
.transform(
|
||||
new AgentBuilder.Transformer.ForAdvice()
|
||||
.advice(
|
||||
named("createMessage"),
|
||||
HttpServerTestAdvice.ServerEntryAdvice.class.getName()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry 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 server
|
||||
|
||||
import play.api.test.TestServer
|
||||
|
||||
class PlayAsyncServerTest extends PlayServerTest {
|
||||
@Override
|
||||
TestServer startServer(int port) {
|
||||
def server = AsyncServer.server(port)
|
||||
server.start()
|
||||
return server
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry 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 server
|
||||
|
||||
import io.opentelemetry.auto.instrumentation.api.MoreTags
|
||||
import io.opentelemetry.auto.instrumentation.api.Tags
|
||||
import io.opentelemetry.auto.test.asserts.TraceAssert
|
||||
import io.opentelemetry.auto.test.base.HttpServerTest
|
||||
import io.opentelemetry.sdk.trace.data.SpanData
|
||||
import play.api.test.TestServer
|
||||
|
||||
import static io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint.ERROR
|
||||
import static io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint.EXCEPTION
|
||||
import static io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint.SUCCESS
|
||||
import static io.opentelemetry.trace.Span.Kind.INTERNAL
|
||||
|
||||
class PlayServerTest extends HttpServerTest<TestServer> {
|
||||
@Override
|
||||
TestServer startServer(int port) {
|
||||
def server = SyncServer.server(port)
|
||||
server.start()
|
||||
return server
|
||||
}
|
||||
|
||||
@Override
|
||||
void stopServer(TestServer server) {
|
||||
server.stop()
|
||||
}
|
||||
|
||||
// We don't have instrumentation for this version of netty yet
|
||||
@Override
|
||||
boolean hasHandlerSpan() {
|
||||
true
|
||||
}
|
||||
|
||||
@Override
|
||||
void handlerSpan(TraceAssert trace, int index, Object parent, String method = "GET", ServerEndpoint endpoint = SUCCESS) {
|
||||
trace.span(index) {
|
||||
operationName "play.request"
|
||||
spanKind INTERNAL
|
||||
errored endpoint == ERROR || endpoint == EXCEPTION
|
||||
childOf((SpanData) parent)
|
||||
tags {
|
||||
"$MoreTags.NET_PEER_IP" { it == null || it == "127.0.0.1" } // Optional
|
||||
"$Tags.HTTP_URL" String
|
||||
"$Tags.HTTP_METHOD" String
|
||||
"$Tags.HTTP_STATUS" Long
|
||||
if (endpoint == EXCEPTION) {
|
||||
errorTags(Exception, EXCEPTION.body)
|
||||
}
|
||||
if (endpoint.query) {
|
||||
"$MoreTags.HTTP_QUERY" endpoint.query
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry 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 server
|
||||
|
||||
import io.opentelemetry.auto.test.base.HttpServerTest
|
||||
import io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint._
|
||||
import play.api.mvc.{Action, Handler, Results}
|
||||
import play.api.test.{FakeApplication, TestServer}
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
object AsyncServer {
|
||||
val routes: PartialFunction[(String, String), Handler] = {
|
||||
case ("GET", "/success") => Action.async { request => HttpServerTest.controller(SUCCESS, new AsyncControllerClosureAdapter(Future.successful(Results.Status(SUCCESS.getStatus).apply(SUCCESS.getBody)))) }
|
||||
case ("GET", "/redirect") => Action.async { request => HttpServerTest.controller(REDIRECT, new AsyncControllerClosureAdapter(Future.successful(Results.Redirect(REDIRECT.getBody, REDIRECT.getStatus)))) }
|
||||
case ("GET", "/query") => Action.async { result => HttpServerTest.controller(QUERY_PARAM, new AsyncControllerClosureAdapter(Future.successful(Results.Status(QUERY_PARAM.getStatus).apply(QUERY_PARAM.getBody)))) }
|
||||
case ("GET", "/error-status") => Action.async { result => HttpServerTest.controller(ERROR, new AsyncControllerClosureAdapter(Future.successful(Results.Status(ERROR.getStatus).apply(ERROR.getBody)))) }
|
||||
case ("GET", "/exception") => Action.async { result =>
|
||||
HttpServerTest.controller(EXCEPTION, new AsyncBlockClosureAdapter(() => {
|
||||
throw new Exception(EXCEPTION.getBody)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
def server(port: Int): TestServer = {
|
||||
TestServer(port, FakeApplication(withGlobal = Some(new Settings()), withRoutes = routes))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry 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 server
|
||||
|
||||
import groovy.lang.Closure
|
||||
import play.api.mvc.Result
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
class ControllerClosureAdapter(response: Result) extends Closure[Result] {
|
||||
override def call(): Result = response
|
||||
}
|
||||
|
||||
class BlockClosureAdapter(block: () => Result) extends Closure[Result] {
|
||||
override def call(): Result = block()
|
||||
}
|
||||
|
||||
class AsyncControllerClosureAdapter(response: Future[Result]) extends Closure[Future[Result]] {
|
||||
override def call(): Future[Result] = response
|
||||
}
|
||||
|
||||
class AsyncBlockClosureAdapter(block: () => Future[Result]) extends Closure[Future[Result]] {
|
||||
override def call(): Future[Result] = block()
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry 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 server
|
||||
|
||||
import play.api.GlobalSettings
|
||||
import play.api.mvc.{RequestHeader, Result, Results}
|
||||
|
||||
import scala.concurrent.Future
|
||||
|
||||
class Settings extends GlobalSettings {
|
||||
override def onError(request: RequestHeader, ex: Throwable): Future[Result] = {
|
||||
Future.successful(Results.InternalServerError(ex.getCause.getMessage))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2020, OpenTelemetry 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 server
|
||||
|
||||
import io.opentelemetry.auto.test.base.HttpServerTest
|
||||
import io.opentelemetry.auto.test.base.HttpServerTest.ServerEndpoint._
|
||||
import play.api.mvc.{Action, Handler, Results}
|
||||
import play.api.test.{FakeApplication, TestServer}
|
||||
|
||||
object SyncServer {
|
||||
val routes: PartialFunction[(String, String), Handler] = {
|
||||
case ("GET", "/success") => Action { request =>
|
||||
HttpServerTest.controller(SUCCESS, new ControllerClosureAdapter(Results.Status(SUCCESS.getStatus).apply(SUCCESS.getBody)))
|
||||
}
|
||||
case ("GET", "/redirect") => Action { request =>
|
||||
HttpServerTest.controller(REDIRECT, new ControllerClosureAdapter(Results.Redirect(REDIRECT.getBody, REDIRECT.getStatus)))
|
||||
}
|
||||
case ("GET", "/query") => Action { request =>
|
||||
HttpServerTest.controller(QUERY_PARAM, new ControllerClosureAdapter(Results.Status(QUERY_PARAM.getStatus).apply(QUERY_PARAM.getBody)))
|
||||
}
|
||||
case ("GET", "/error-status") => Action { request =>
|
||||
HttpServerTest.controller(ERROR, new ControllerClosureAdapter(Results.Status(ERROR.getStatus).apply(ERROR.getBody)))
|
||||
}
|
||||
case ("GET", "/exception") => Action { request =>
|
||||
HttpServerTest.controller(EXCEPTION, new BlockClosureAdapter(() => {
|
||||
throw new Exception(EXCEPTION.getBody)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
def server(port: Int): TestServer = {
|
||||
TestServer(port, FakeApplication(withGlobal = Some(new Settings()), withRoutes = routes))
|
||||
}
|
||||
}
|
|
@ -20,9 +20,11 @@ import play.libs.ws.WS
|
|||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Subject
|
||||
import spock.lang.Timeout
|
||||
|
||||
// Play 2.6+ uses a separately versioned client that shades the underlying dependency
|
||||
// This means our built in instrumentation won't work.
|
||||
@Timeout(5)
|
||||
class PlayWSClientTest extends HttpClientTest {
|
||||
@Subject
|
||||
@Shared
|
||||
|
@ -54,4 +56,9 @@ class PlayWSClientTest extends HttpClientTest {
|
|||
boolean testConnectionFailure() {
|
||||
false
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRemoteConnection() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,11 @@ import ratpack.http.client.HttpClient
|
|||
import ratpack.test.exec.ExecHarness
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Timeout
|
||||
|
||||
import java.time.Duration
|
||||
|
||||
@Timeout(5)
|
||||
class RatpackHttpClientTest extends HttpClientTest {
|
||||
|
||||
@AutoCleanup
|
||||
|
@ -29,12 +33,16 @@ class RatpackHttpClientTest extends HttpClientTest {
|
|||
ExecHarness exec = ExecHarness.harness()
|
||||
|
||||
@Shared
|
||||
def client = HttpClient.of {}
|
||||
def client = HttpClient.of {
|
||||
it.readTimeout(Duration.ofSeconds(2))
|
||||
// Connect timeout added in 1.5
|
||||
}
|
||||
|
||||
@Override
|
||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||
ExecResult<Integer> result = exec.yield {
|
||||
def resp = client.request(uri) { spec ->
|
||||
spec.connectTimeout(Duration.ofSeconds(2))
|
||||
spec.method(method)
|
||||
spec.headers { headersSpec ->
|
||||
headers.entrySet().each {
|
||||
|
@ -59,4 +67,9 @@ class RatpackHttpClientTest extends HttpClientTest {
|
|||
boolean testConnectionFailure() {
|
||||
false
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRemoteConnection() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,12 +24,14 @@ import org.springframework.web.reactive.function.client.ClientResponse
|
|||
import org.springframework.web.reactive.function.client.WebClient
|
||||
import spock.lang.Ignore
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Timeout
|
||||
|
||||
import static io.opentelemetry.trace.Span.Kind.CLIENT
|
||||
|
||||
// FIXME this instrumentation is not currently reliable and so is currently disabled
|
||||
// see DefaultWebClientInstrumentation and DefaultWebClientAdvice
|
||||
@Ignore
|
||||
@Timeout(5)
|
||||
class SpringWebfluxHttpClientTest extends HttpClientTest {
|
||||
|
||||
@Shared
|
||||
|
@ -93,4 +95,9 @@ class SpringWebfluxHttpClientTest extends HttpClientTest {
|
|||
boolean testConnectionFailure() {
|
||||
false
|
||||
}
|
||||
|
||||
boolean testRemoteConnection() {
|
||||
// FIXME: figure out how to configure timeouts.
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ package client
|
|||
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||
import io.vertx.core.Vertx
|
||||
import io.vertx.core.VertxOptions
|
||||
import io.vertx.core.http.HttpClient
|
||||
import io.vertx.core.http.HttpClientOptions
|
||||
import io.vertx.core.http.HttpClientResponse
|
||||
import io.vertx.core.http.HttpMethod
|
||||
import spock.lang.Shared
|
||||
|
@ -30,9 +30,11 @@ import java.util.concurrent.CompletableFuture
|
|||
class VertxHttpClientTest extends HttpClientTest {
|
||||
|
||||
@Shared
|
||||
Vertx vertx = Vertx.vertx(new VertxOptions())
|
||||
def vertx = Vertx.vertx(new VertxOptions())
|
||||
@Shared
|
||||
HttpClient httpClient = vertx.createHttpClient()
|
||||
def clientOptions = new HttpClientOptions().setConnectTimeout(CONNECT_TIMEOUT_MS).setIdleTimeout(READ_TIMEOUT_MS)
|
||||
@Shared
|
||||
def httpClient = vertx.createHttpClient(clientOptions)
|
||||
|
||||
@Override
|
||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||
|
@ -57,4 +59,9 @@ class VertxHttpClientTest extends HttpClientTest {
|
|||
boolean testConnectionFailure() {
|
||||
false
|
||||
}
|
||||
|
||||
boolean testRemoteConnection() {
|
||||
// FIXME: figure out how to configure timeouts.
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import io.opentelemetry.auto.test.base.HttpClientTest
|
|||
import io.vertx.circuitbreaker.CircuitBreakerOptions
|
||||
import io.vertx.core.VertxOptions
|
||||
import io.vertx.core.http.HttpMethod
|
||||
import io.vertx.ext.web.client.WebClientOptions
|
||||
import io.vertx.reactivex.circuitbreaker.CircuitBreaker
|
||||
import io.vertx.reactivex.core.Vertx
|
||||
import io.vertx.reactivex.ext.web.client.WebClient
|
||||
|
@ -33,7 +34,9 @@ class VertxRxCircuitBreakerWebClientTest extends HttpClientTest {
|
|||
@Shared
|
||||
Vertx vertx = Vertx.vertx(new VertxOptions())
|
||||
@Shared
|
||||
WebClient client = WebClient.create(vertx)
|
||||
def clientOptions = new WebClientOptions().setConnectTimeout(CONNECT_TIMEOUT_MS).setIdleTimeout(READ_TIMEOUT_MS)
|
||||
@Shared
|
||||
WebClient client = WebClient.create(vertx, clientOptions)
|
||||
@Shared
|
||||
CircuitBreaker breaker = CircuitBreaker.create("my-circuit-breaker", vertx,
|
||||
new CircuitBreakerOptions()
|
||||
|
@ -73,4 +76,9 @@ class VertxRxCircuitBreakerWebClientTest extends HttpClientTest {
|
|||
boolean testConnectionFailure() {
|
||||
false
|
||||
}
|
||||
|
||||
boolean testRemoteConnection() {
|
||||
// FIXME: figure out how to configure timeouts.
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package client
|
|||
import io.opentelemetry.auto.test.base.HttpClientTest
|
||||
import io.vertx.core.VertxOptions
|
||||
import io.vertx.core.http.HttpMethod
|
||||
import io.vertx.ext.web.client.WebClientOptions
|
||||
import io.vertx.reactivex.core.Vertx
|
||||
import io.vertx.reactivex.ext.web.client.WebClient
|
||||
import spock.lang.Shared
|
||||
|
@ -29,7 +30,9 @@ class VertxRxWebClientTest extends HttpClientTest {
|
|||
@Shared
|
||||
Vertx vertx = Vertx.vertx(new VertxOptions())
|
||||
@Shared
|
||||
WebClient client = WebClient.create(vertx)
|
||||
def clientOptions = new WebClientOptions().setConnectTimeout(CONNECT_TIMEOUT_MS).setIdleTimeout(READ_TIMEOUT_MS)
|
||||
@Shared
|
||||
WebClient client = WebClient.create(vertx, clientOptions)
|
||||
|
||||
@Override
|
||||
int doRequest(String method, URI uri, Map<String, String> headers, Closure callback) {
|
||||
|
@ -52,4 +55,9 @@ class VertxRxWebClientTest extends HttpClientTest {
|
|||
boolean testConnectionFailure() {
|
||||
false
|
||||
}
|
||||
|
||||
boolean testRemoteConnection() {
|
||||
// FIXME: figure out how to configure timeouts.
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,6 +111,7 @@ include ':instrumentation:netty:netty-4.0'
|
|||
include ':instrumentation:netty:netty-4.1'
|
||||
include ':instrumentation:okhttp-3.0'
|
||||
include ':instrumentation:opentelemetry-api-0.3'
|
||||
include ':instrumentation:play:play-2.3'
|
||||
include ':instrumentation:play:play-2.4'
|
||||
include ':instrumentation:play:play-2.6'
|
||||
include ':instrumentation:play-ws:play-ws-1.0'
|
||||
|
|
|
@ -21,7 +21,7 @@ import spock.lang.Specification
|
|||
|
||||
abstract class AbstractSmokeTest extends Specification {
|
||||
|
||||
public static final PROFILING_API_KEY = "org2_api_key"
|
||||
public static final API_KEY = "some-api-key"
|
||||
public static final PROFILING_START_DELAY_SECONDS = 1
|
||||
public static final int PROFILING_RECORDING_UPLOAD_PERIOD_SECONDS = 5
|
||||
|
||||
|
@ -68,7 +68,7 @@ abstract class AbstractSmokeTest extends Specification {
|
|||
ProcessBuilder processBuilder = createProcessBuilder()
|
||||
|
||||
processBuilder.environment().put("JAVA_HOME", System.getProperty("java.home"))
|
||||
processBuilder.environment().put("DD_PROFILING_APIKEY", PROFILING_API_KEY)
|
||||
processBuilder.environment().put("DD_API_KEY", API_KEY)
|
||||
|
||||
processBuilder.redirectErrorStream(true)
|
||||
logfile = new File("${buildDirectory}/reports/testProcess.${this.getClass().getName()}.log")
|
||||
|
|
|
@ -23,6 +23,7 @@ import io.opentelemetry.auto.test.AgentTestRunner
|
|||
import io.opentelemetry.auto.test.asserts.TraceAssert
|
||||
import io.opentelemetry.sdk.trace.data.SpanData
|
||||
import spock.lang.AutoCleanup
|
||||
import spock.lang.Requires
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Unroll
|
||||
|
||||
|
@ -40,6 +41,8 @@ import static org.junit.Assume.assumeTrue
|
|||
@Unroll
|
||||
abstract class HttpClientTest extends AgentTestRunner {
|
||||
protected static final BODY_METHODS = ["POST", "PUT"]
|
||||
protected static final CONNECT_TIMEOUT_MS = 1000
|
||||
protected static final READ_TIMEOUT_MS = 2000
|
||||
|
||||
@AutoCleanup
|
||||
@Shared
|
||||
|
@ -250,8 +253,7 @@ abstract class HttpClientTest extends AgentTestRunner {
|
|||
|
||||
def "basic #method request with circular redirects"() {
|
||||
given:
|
||||
assumeTrue(testRedirects())
|
||||
assumeTrue(testCircularRedirects())
|
||||
assumeTrue(testRedirects() && testCircularRedirects())
|
||||
def uri = server.address.resolve("/circular-redirect")
|
||||
|
||||
when:
|
||||
|
@ -300,6 +302,77 @@ abstract class HttpClientTest extends AgentTestRunner {
|
|||
method = "GET"
|
||||
}
|
||||
|
||||
def "connection error dropped request"() {
|
||||
given:
|
||||
assumeTrue(testRemoteConnection())
|
||||
// https://stackoverflow.com/a/100859
|
||||
def uri = new URI("http://www.google.com:81/")
|
||||
|
||||
when:
|
||||
runUnderTrace("parent") {
|
||||
doRequest(method, uri)
|
||||
}
|
||||
|
||||
then:
|
||||
def ex = thrown(Exception)
|
||||
def thrownException = ex instanceof ExecutionException ? ex.cause : ex
|
||||
assertTraces(1) {
|
||||
trace(0, 2 + extraClientSpans()) {
|
||||
basicSpan(it, 0, "parent", null, thrownException)
|
||||
clientSpan(it, 1, span(0), method, false, uri, null, thrownException)
|
||||
}
|
||||
}
|
||||
|
||||
where:
|
||||
method = "HEAD"
|
||||
}
|
||||
|
||||
def "connection error non routable address"() {
|
||||
given:
|
||||
assumeTrue(testRemoteConnection())
|
||||
def uri = new URI("https://192.0.2.1/")
|
||||
|
||||
when:
|
||||
runUnderTrace("parent") {
|
||||
doRequest(method, uri)
|
||||
}
|
||||
|
||||
then:
|
||||
def ex = thrown(Exception)
|
||||
def thrownException = ex instanceof ExecutionException ? ex.cause : ex
|
||||
assertTraces(1) {
|
||||
trace(0, 2 + extraClientSpans()) {
|
||||
basicSpan(it, 0, "parent", null, thrownException)
|
||||
clientSpan(it, 1, span(0), method, false, uri, null, thrownException)
|
||||
}
|
||||
}
|
||||
|
||||
where:
|
||||
method = "HEAD"
|
||||
}
|
||||
|
||||
// IBM JVM has different protocol support for TLS
|
||||
@Requires({ !System.getProperty("java.vm.name").contains("IBM J9 VM") })
|
||||
def "test https request"() {
|
||||
given:
|
||||
assumeTrue(testRemoteConnection())
|
||||
def uri = new URI("https://www.google.com/")
|
||||
|
||||
when:
|
||||
def status = doRequest(method, uri)
|
||||
|
||||
then:
|
||||
status == 200
|
||||
assertTraces(1) {
|
||||
trace(0, 1 + extraClientSpans()) {
|
||||
clientSpan(it, 0, null, method, false, uri)
|
||||
}
|
||||
}
|
||||
|
||||
where:
|
||||
method = "HEAD"
|
||||
}
|
||||
|
||||
// parent span must be cast otherwise it breaks debugging classloading (junit loads it early)
|
||||
void clientSpan(TraceAssert trace, int index, Object parentSpan, String method = "GET", boolean tagQueryString = false, URI uri = server.address.resolve("/success"), Integer status = 200, Throwable exception = null) {
|
||||
trace.span(index) {
|
||||
|
@ -312,9 +385,9 @@ abstract class HttpClientTest extends AgentTestRunner {
|
|||
spanKind CLIENT
|
||||
errored exception != null
|
||||
tags {
|
||||
"$MoreTags.NET_PEER_NAME" "localhost"
|
||||
"$MoreTags.NET_PEER_NAME" uri.host
|
||||
"$MoreTags.NET_PEER_IP" { it == null || it == "127.0.0.1" } // Optional
|
||||
"$MoreTags.NET_PEER_PORT" uri.port
|
||||
"$MoreTags.NET_PEER_PORT" uri.port > 0 ? uri.port : { it == null || it == 443 } // Optional
|
||||
"$Tags.HTTP_URL" { it == "${uri}" || it == "${removeFragment(uri)}" }
|
||||
"$Tags.HTTP_METHOD" method
|
||||
if (status) {
|
||||
|
@ -366,6 +439,10 @@ abstract class HttpClientTest extends AgentTestRunner {
|
|||
true
|
||||
}
|
||||
|
||||
boolean testRemoteConnection() {
|
||||
true
|
||||
}
|
||||
|
||||
boolean testCallbackWithParent() {
|
||||
// FIXME: this hack is here because callback with parent is broken in play-ws when the stream()
|
||||
// function is used. There is no way to stop a test from a derived class hence the flag
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package io.opentelemetry.auto.test.base
|
||||
|
||||
import ch.qos.logback.classic.Level
|
||||
import io.opentelemetry.auto.bootstrap.instrumentation.decorator.HttpServerDecorator
|
||||
import io.opentelemetry.auto.instrumentation.api.MoreTags
|
||||
import io.opentelemetry.auto.instrumentation.api.Tags
|
||||
|
@ -28,6 +29,8 @@ import okhttp3.HttpUrl
|
|||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Unroll
|
||||
|
||||
|
@ -48,6 +51,11 @@ import static org.junit.Assume.assumeTrue
|
|||
@Unroll
|
||||
abstract class HttpServerTest<SERVER> extends AgentTestRunner {
|
||||
|
||||
public static final Logger SERVER_LOGGER = LoggerFactory.getLogger("http-server")
|
||||
static {
|
||||
((ch.qos.logback.classic.Logger) SERVER_LOGGER).setLevel(Level.DEBUG)
|
||||
}
|
||||
|
||||
@Shared
|
||||
SERVER server
|
||||
@Shared
|
||||
|
|
|
@ -41,17 +41,14 @@ class TestHttpServer implements AutoCloseable {
|
|||
|
||||
private static final Tracer TRACER = OpenTelemetry.getTracerProvider().get("io.opentelemetry.auto")
|
||||
|
||||
static TestHttpServer httpServer(boolean start = true,
|
||||
@DelegatesTo(value = TestHttpServer, strategy = Closure.DELEGATE_FIRST) Closure spec) {
|
||||
static TestHttpServer httpServer(@DelegatesTo(value = TestHttpServer, strategy = Closure.DELEGATE_FIRST) Closure spec) {
|
||||
|
||||
def server = new TestHttpServer()
|
||||
def clone = (Closure) spec.clone()
|
||||
clone.delegate = server
|
||||
clone.resolveStrategy = Closure.DELEGATE_FIRST
|
||||
clone(server)
|
||||
if (start) {
|
||||
server.start()
|
||||
}
|
||||
return server
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,10 @@ package io.opentelemetry.auto.test.utils;
|
|||
|
||||
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
|
||||
|
@ -24,9 +28,29 @@ import okhttp3.OkHttpClient;
|
|||
*/
|
||||
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(final String message) {
|
||||
CLIENT_LOGGER.debug(message);
|
||||
}
|
||||
});
|
||||
|
||||
static {
|
||||
LOGGING_INTERCEPTOR.setLevel(Level.BASIC);
|
||||
}
|
||||
|
||||
static OkHttpClient.Builder clientBuilder() {
|
||||
final TimeUnit unit = TimeUnit.MINUTES;
|
||||
return new OkHttpClient.Builder()
|
||||
.addInterceptor(LOGGING_INTERCEPTOR)
|
||||
.connectTimeout(1, unit)
|
||||
.writeTimeout(1, unit)
|
||||
.readTimeout(1, unit);
|
||||
|
|
|
@ -31,12 +31,12 @@ class ServerTest extends AgentTestRunner {
|
|||
|
||||
def "test server lifecycle"() {
|
||||
setup:
|
||||
def server = httpServer(startAutomatically) {
|
||||
def server = httpServer {
|
||||
handlers {}
|
||||
}
|
||||
|
||||
expect:
|
||||
server.internalServer.isRunning() == startAutomatically
|
||||
server.internalServer.isRunning()
|
||||
|
||||
when:
|
||||
server.start()
|
||||
|
@ -57,16 +57,13 @@ class ServerTest extends AgentTestRunner {
|
|||
server.internalServer.isRunning()
|
||||
|
||||
when:
|
||||
server.stop()
|
||||
server.close()
|
||||
|
||||
then:
|
||||
!server.internalServer.isRunning()
|
||||
|
||||
cleanup:
|
||||
server.stop()
|
||||
|
||||
where:
|
||||
startAutomatically << [true, false]
|
||||
server.close()
|
||||
}
|
||||
|
||||
def "server 404's with no handlers"() {
|
||||
|
|
|
@ -26,6 +26,7 @@ dependencies {
|
|||
compile group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.11.0' // Last version to support Java7
|
||||
|
||||
compile group: 'org.eclipse.jetty', name: 'jetty-server', version: '8.0.0.v20110901'
|
||||
compile group: 'com.squareup.okhttp3', name: 'logging-interceptor', version: versions.okhttp
|
||||
|
||||
compile(project(':auto-tooling')) {
|
||||
// including :opentelemetry-sdk-shaded-for-testing above instead
|
||||
|
|
Loading…
Reference in New Issue