You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zipkin.apache.org by ad...@apache.org on 2019/05/08 07:06:15 UTC
[incubator-zipkin] 01/01: Ports all zipkin-server tests to Kotlin
This is an automated email from the ASF dual-hosted git repository.
adriancole pushed a commit to branch server-tests-kotlin
in repository https://gitbox.apache.org/repos/asf/incubator-zipkin.git
commit f7f4232a4a830e445b3c46d0b25ba01dcbfef82f
Author: Adrian Cole <ac...@pivotal.io>
AuthorDate: Wed May 8 15:05:28 2019 +0800
Ports all zipkin-server tests to Kotlin
This reduces the amount of code to maintain and helps us learn Kotlin.
---
.../server/internal/ZipkinHttpCollector.java | 4 +
.../java/zipkin/server/ITEnableZipkinServer.java | 63 ----
...ZipkinKafkaCollectorPropertiesOverrideTest.java | 81 -----
...kinRabbitMQCollectorPropertiesOverrideTest.java | 89 -----
...nElasticsearchStorageAutoConfigurationTest.java | 400 ---------------------
.../server/internal/ITZipkinMetricsHealth.java | 238 ------------
.../internal/ITZipkinMetricsHealthDirty.java | 131 -------
.../zipkin2/server/internal/ITZipkinServer.java | 180 ----------
.../internal/ITZipkinServerAutocomplete.java | 94 -----
.../server/internal/ITZipkinServerCORS.java | 124 -------
.../ITZipkinServerHttpCollectorDisabled.java | 69 ----
.../internal/ITZipkinServerQueryDisabled.java | 63 ----
.../zipkin2/server/internal/ITZipkinServerSsl.java | 84 -----
.../internal/ZipkinServerConfigurationTest.java | 155 --------
.../server/internal/brave/ITZipkinSelfTracing.java | 101 ------
.../elasticsearch/BasicAuthInterceptorTest.java | 63 ----
.../ZipkinKafkaCollectorConfigurationTest.java | 107 ------
.../kafka/ZipkinKafkaCollectorPropertiesTest.java | 34 --
.../ZipkinRabbitMQCollectorConfigurationTest.java | 112 ------
.../ZipkinRabbitMQCollectorPropertiesTest.java | 57 ---
.../internal/ui/ITZipkinUiConfiguration.java | 160 ---------
.../internal/ui/ZipkinUiConfigurationTest.java | 214 -----------
...ipkinCassandraStorageAutoConfigurationTest.java | 154 --------
.../ZipkinCassandraStorageConfigurationTest.java | 140 --------
.../v1/ZipkinMySQLStorageConfigurationTest.java | 158 --------
.../kotlin/zipkin/server/ITEnableZipkinServer.kt | 46 +++
.../ZipkinKafkaCollectorPropertiesOverrideTest.kt | 72 ++++
...ipkinRabbitMQCollectorPropertiesOverrideTest.kt | 83 +++++
...kinElasticsearchStorageAutoConfigurationTest.kt | 360 +++++++++++++++++++
.../test/kotlin/zipkin2/server/internal/Http.kt | 66 ++++
.../server/internal/ITZipkinGrpcCollector.kt | 17 +-
.../server/internal/ITZipkinHttpCollector.kt | 150 +++-----
.../server/internal/ITZipkinMetricsHealth.kt | 195 ++++++++++
.../server/internal/ITZipkinMetricsHealthDirty.kt | 88 +++++
.../zipkin2/server/internal/ITZipkinServer.kt | 156 ++++++++
.../server/internal/ITZipkinServerAutocomplete.kt | 72 ++++
.../zipkin2/server/internal/ITZipkinServerCORS.kt | 106 ++++++
.../ITZipkinServerHttpCollectorDisabled.kt | 53 +++
.../server/internal/ITZipkinServerQueryDisabled.kt | 52 +++
.../zipkin2/server/internal/ITZipkinServerSsl.kt | 75 ++++
.../internal/InMemoryCollectorConfiguration.kt | 23 ++
.../internal/ZipkinServerConfigurationTest.kt | 150 ++++++++
.../server/internal/brave/ITZipkinSelfTracing.kt | 67 ++++
.../zipkin2/server/internal/cassandra/Access.kt} | 18 +-
.../zipkin2/server/internal/cassandra3/Access.kt} | 18 +-
.../server/internal/elasticsearch/Access.kt} | 18 +-
.../elasticsearch/BasicAuthInterceptorTest.kt | 44 +++
.../zipkin2/server/internal/kafka/Access.kt} | 36 +-
.../kafka/ZipkinKafkaCollectorConfigurationTest.kt | 67 ++++
.../kafka/ZipkinKafkaCollectorPropertiesTest.kt} | 21 +-
.../zipkin2/server/internal/mysql/Access.kt} | 19 +-
.../ZipkinPrometheusMetricsConfigurationTest.kt} | 78 ++--
.../zipkin2/server/internal/rabbitmq/Access.kt} | 36 +-
.../ZipkinRabbitMQCollectorConfigurationTest.kt | 70 ++++
.../ZipkinRabbitMQCollectorPropertiesTest.kt | 53 +++
.../server/internal/ui/ITZipkinUiConfiguration.kt | 124 +++++++
.../internal/ui/ZipkinUiConfigurationTest.kt | 185 ++++++++++
.../ZipkinCassandraStorageAutoConfigurationTest.kt | 125 +++++++
.../v1/ZipkinCassandraStorageConfigurationTest.kt | 114 ++++++
.../v1/ZipkinMySQLStorageConfigurationTest.kt | 130 +++++++
60 files changed, 2752 insertions(+), 3310 deletions(-)
diff --git a/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinHttpCollector.java b/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinHttpCollector.java
index 251c641..897f63e 100644
--- a/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinHttpCollector.java
+++ b/zipkin-server/src/main/java/zipkin2/server/internal/ZipkinHttpCollector.java
@@ -185,6 +185,10 @@ final class UnzippingBytesRequestConverter implements RequestConverterFunction {
}
if (content.isEmpty()) ZipkinHttpCollector.maybeLog("Empty POST body", ctx, request);
+ if (content.length() == 2 && "[]".equals(content.toStringAscii())) {
+ ZipkinHttpCollector.maybeLog("Empty JSON list POST body", ctx, request);
+ content = HttpData.EMPTY_DATA;
+ }
byte[] result = content.array();
ZipkinHttpCollector.metrics.incrementBytes(result.length);
diff --git a/zipkin-server/src/test/java/zipkin/server/ITEnableZipkinServer.java b/zipkin-server/src/test/java/zipkin/server/ITEnableZipkinServer.java
deleted file mode 100644
index b080743..0000000
--- a/zipkin-server/src/test/java/zipkin/server/ITEnableZipkinServer.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin.server;
-
-import com.linecorp.armeria.server.Server;
-import java.io.IOException;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.Response;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static zipkin2.server.internal.ITZipkinServer.url;
-
-@SpringBootTest(
- classes = CustomServer.class,
- webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
- properties = "spring.config.name=zipkin-server"
-)
-@RunWith(SpringRunner.class)
-public class ITEnableZipkinServer {
-
- @Autowired Server server;
-
- OkHttpClient client = new OkHttpClient.Builder().followRedirects(false).build();
-
- @Test public void writeSpans_noContentTypeIsJson() throws Exception {
- Response response = get("/api/v2/services");
-
- assertThat(response.code())
- .isEqualTo(200);
- }
-
- Response get(String path) throws IOException {
- return client.newCall(new Request.Builder()
- .url(url(server, path))
- .build()).execute();
- }
-}
-@SpringBootApplication
-@EnableZipkinServer
-class CustomServer {
-
-}
diff --git a/zipkin-server/src/test/java/zipkin2/collector/kafka/ZipkinKafkaCollectorPropertiesOverrideTest.java b/zipkin-server/src/test/java/zipkin2/collector/kafka/ZipkinKafkaCollectorPropertiesOverrideTest.java
deleted file mode 100644
index 34990ff..0000000
--- a/zipkin-server/src/test/java/zipkin2/collector/kafka/ZipkinKafkaCollectorPropertiesOverrideTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.collector.kafka;
-
-import java.util.Arrays;
-import java.util.function.Function;
-import org.assertj.core.api.Assertions;
-import org.junit.After;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.springframework.boot.test.util.TestPropertyValues;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import zipkin2.server.internal.kafka.Access;
-
-@RunWith(Parameterized.class)
-public class ZipkinKafkaCollectorPropertiesOverrideTest {
-
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
-
- @After
- public void close() {
- if (context != null) context.close();
- }
-
- @Parameterized.Parameter(0)
- public String property;
-
- @Parameterized.Parameter(1)
- public Object value;
-
- @Parameterized.Parameter(2)
- public Function<KafkaCollector.Builder, Object> builderExtractor;
-
- @Parameterized.Parameters(name = "{0}")
- public static Iterable<Object[]> data() {
- return Arrays.asList(
- parameters(
- "bootstrap-servers",
- "127.0.0.1:9092",
- b -> b.properties.getProperty("bootstrap.servers")),
- parameters("group-id", "zapkin", b -> b.properties.getProperty("group.id")),
- parameters("topic", "zapkin", b -> b.topic),
- parameters("streams", 2, b -> b.streams),
- parameters(
- "overrides.auto.offset.reset",
- "latest",
- b -> b.properties.getProperty("auto.offset.reset")));
- }
-
- /** to allow us to define with a lambda */
- static <T> Object[] parameters(
- String propertySuffix, T value, Function<KafkaCollector.Builder, T> builderExtractor) {
- return new Object[] {"zipkin.collector.kafka." + propertySuffix, value, builderExtractor};
- }
-
- @Test
- public void propertyTransferredToCollectorBuilder() {
- TestPropertyValues.of(property + ":" + value).applyTo(context);
- Access.registerKafkaProperties(context);
- context.refresh();
-
- Assertions.assertThat(Access.collectorBuilder(context))
- .extracting(builderExtractor)
- .isEqualTo(value);
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/collector/rabbitmq/ZipkinRabbitMQCollectorPropertiesOverrideTest.java b/zipkin-server/src/test/java/zipkin2/collector/rabbitmq/ZipkinRabbitMQCollectorPropertiesOverrideTest.java
deleted file mode 100644
index 4084ce1..0000000
--- a/zipkin-server/src/test/java/zipkin2/collector/rabbitmq/ZipkinRabbitMQCollectorPropertiesOverrideTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.collector.rabbitmq;
-
-import java.net.URI;
-import java.util.Arrays;
-import java.util.function.Function;
-import org.junit.After;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.springframework.boot.test.util.TestPropertyValues;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import zipkin2.server.internal.rabbitmq.Access;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-@RunWith(Parameterized.class)
-public class ZipkinRabbitMQCollectorPropertiesOverrideTest {
-
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
-
- @After
- public void close() {
- if (context != null) context.close();
- }
-
- @Parameterized.Parameter(0)
- public String property;
-
- @Parameterized.Parameter(1)
- public Object value;
-
- @Parameterized.Parameter(2)
- public Function<RabbitMQCollector.Builder, Object> builderExtractor;
-
- @Parameterized.Parameters(name = "{0}")
- public static Iterable<Object[]> data() {
- return Arrays.asList(
- // intentionally punting on comma-separated form of a list of addresses as it doesn't fit
- // this unit test. Better to make a separate one than force-fit!
- parameters("addresses", "localhost:5671", builder -> builder.addresses[0].toString()),
- parameters("concurrency", 2, builder -> builder.concurrency),
- parameters(
- "connectionTimeout",
- 30_000,
- builder -> builder.connectionFactory.getConnectionTimeout()),
- parameters("password", "admin", builder -> builder.connectionFactory.getPassword()),
- parameters("queue", "zapkin", builder -> builder.queue),
- parameters("username", "admin", builder -> builder.connectionFactory.getUsername()),
- parameters("virtualHost", "/hello", builder -> builder.connectionFactory.getVirtualHost()),
- parameters("useSsl", true, builder -> builder.connectionFactory.isSSL()),
- parameters(
- "uri",
- URI.create("amqp://localhost"),
- builder -> URI.create("amqp://" + builder.connectionFactory.getHost())));
- }
-
- /** to allow us to define with a lambda */
- static <T> Object[] parameters(
- String propertySuffix, T value, Function<RabbitMQCollector.Builder, T> builderExtractor) {
- return new Object[] {"zipkin.collector.rabbitmq." + propertySuffix, value, builderExtractor};
- }
-
- @Test
- public void propertyTransferredToCollectorBuilder() throws Exception {
- TestPropertyValues.of(property + ":" + value).applyTo(context);
- Access.registerRabbitMQProperties(context);
- context.refresh();
-
- assertThat(Access.collectorBuilder(context))
- .extracting(builderExtractor)
- .isEqualTo(value);
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/elasticsearch/ZipkinElasticsearchStorageAutoConfigurationTest.java b/zipkin-server/src/test/java/zipkin2/elasticsearch/ZipkinElasticsearchStorageAutoConfigurationTest.java
deleted file mode 100644
index d9cfa8e..0000000
--- a/zipkin-server/src/test/java/zipkin2/elasticsearch/ZipkinElasticsearchStorageAutoConfigurationTest.java
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.elasticsearch;
-
-import java.util.concurrent.TimeUnit;
-import okhttp3.Interceptor;
-import okhttp3.OkHttpClient;
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.springframework.beans.factory.BeanCreationException;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.boot.test.util.TestPropertyValues;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import zipkin2.server.internal.elasticsearch.Access;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ZipkinElasticsearchStorageAutoConfigurationTest {
-
- @Rule public ExpectedException thrown = ExpectedException.none();
-
- final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
-
- @After
- public void close() {
- context.close();
- }
-
- @Test
- public void doesntProvideStorageComponent_whenStorageTypeNotElasticsearch() {
- TestPropertyValues.of("zipkin.storage.type:cassandra").applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- thrown.expect(NoSuchBeanDefinitionException.class);
- es();
- }
-
- @Test
- public void providesStorageComponent_whenStorageTypeElasticsearchAndHostsAreUrls() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:http://host1:9200")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(es()).isNotNull();
- }
-
- @Test
- public void canOverridesProperty_hostsWithList() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:http://host1:9200,http://host2:9200")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(es().hostsSupplier().get())
- .containsExactly("http://host1:9200", "http://host2:9200");
- }
-
- @Test
- public void configuresPipeline() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:http://host1:9200",
- "zipkin.storage.elasticsearch.pipeline:zipkin")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(es().pipeline()).isEqualTo("zipkin");
- }
-
- @Test
- public void configuresMaxRequests() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:http://host1:9200",
- "zipkin.storage.elasticsearch.max-requests:200")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(es().maxRequests()).isEqualTo(200);
- }
-
- /** This helps ensure old setups don't break (provided they have http port 9200 open) */
- @Test
- public void coersesPort9300To9200() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:host1:9300")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(es().hostsSupplier().get()).containsExactly("http://host1:9200");
- }
-
- @Test
- public void httpPrefixOptional() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:host1:9200")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(es().hostsSupplier().get()).containsExactly("http://host1:9200");
- }
-
- @Test
- public void defaultsToPort9200() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:host1")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(es().hostsSupplier().get()).containsExactly("http://host1:9200");
- }
-
- @Configuration
- static class InterceptorConfiguration {
-
- static Interceptor one = chain -> null;
- static Interceptor two = chain -> null;
-
- @Bean
- @Qualifier("zipkinElasticsearchHttp")
- Interceptor one() {
- return one;
- }
-
- @Bean
- @Qualifier("zipkinElasticsearchHttp")
- Interceptor two() {
- return two;
- }
- }
-
- /** Ensures we can wire up network interceptors, such as for logging or authentication */
- @Test
- public void usesInterceptorsQualifiedWith_zipkinElasticsearchHttp() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:host1:9200")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.register(InterceptorConfiguration.class);
- context.refresh();
-
- assertThat(context.getBean(OkHttpClient.class).networkInterceptors())
- .containsOnlyOnce(InterceptorConfiguration.one, InterceptorConfiguration.two);
- }
-
- @Test
- public void timeout_defaultsTo10Seconds() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:host1:9200")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- OkHttpClient client = context.getBean(OkHttpClient.class);
- assertThat(client.connectTimeoutMillis()).isEqualTo(10_000);
- assertThat(client.readTimeoutMillis()).isEqualTo(10_000);
- assertThat(client.writeTimeoutMillis()).isEqualTo(10_000);
- }
-
- @Test
- public void timeout_override() {
- int timeout = 30_000;
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:http://host1:9200",
- "zipkin.storage.elasticsearch.timeout:" + timeout)
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- OkHttpClient client = context.getBean(OkHttpClient.class);
- assertThat(client.connectTimeoutMillis()).isEqualTo(timeout);
- assertThat(client.readTimeoutMillis()).isEqualTo(timeout);
- assertThat(client.writeTimeoutMillis()).isEqualTo(timeout);
- }
-
- @Test
- public void strictTraceId_defaultsToTrue() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:http://host1:9200")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
- assertThat(es().strictTraceId()).isTrue();
- }
-
- @Test
- public void strictTraceId_canSetToFalse() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:http://host1:9200",
- "zipkin.storage.strict-trace-id:false")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(es().strictTraceId()).isFalse();
- }
-
- @Test
- public void dailyIndexFormat() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:http://host1:9200")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(es().indexNameFormatter().formatTypeAndTimestamp("span", 0))
- .isEqualTo("zipkin*span-1970-01-01");
- }
-
- @Test
- public void dailyIndexFormat_overridingPrefix() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:http://host1:9200",
- "zipkin.storage.elasticsearch.index:zipkin_prod")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(es().indexNameFormatter().formatTypeAndTimestamp("span", 0))
- .isEqualTo("zipkin_prod*span-1970-01-01");
- }
-
- @Test
- public void dailyIndexFormat_overridingDateSeparator() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:http://host1:9200",
- "zipkin.storage.elasticsearch.date-separator:.")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(es().indexNameFormatter().formatTypeAndTimestamp("span", 0))
- .isEqualTo("zipkin*span-1970.01.01");
- }
-
- @Test
- public void dailyIndexFormat_overridingDateSeparator_empty() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:http://host1:9200",
- "zipkin.storage.elasticsearch.date-separator:")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(es().indexNameFormatter().formatTypeAndTimestamp("span", 0))
- .isEqualTo("zipkin*span-19700101");
- }
-
- @Test
- public void dailyIndexFormat_overridingDateSeparator_invalidToBeMultiChar() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:http://host1:9200",
- "zipkin.storage.elasticsearch.date-separator:blagho")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
-
- thrown.expect(BeanCreationException.class);
- context.refresh();
- }
-
- @Test
- public void namesLookbackAssignedFromQueryLookback() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:http://host1:9200",
- "zipkin.query.lookback:" + TimeUnit.DAYS.toMillis(2))
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(es().namesLookback()).isEqualTo((int) TimeUnit.DAYS.toMillis(2));
- }
-
- @Test
- public void doesntProvideBasicAuthInterceptor_whenBasicAuthUserNameandPasswordNotConfigured() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:http://host1:9200")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- thrown.expect(NoSuchBeanDefinitionException.class);
- context.getBean(Interceptor.class);
- }
-
- @Test
- public void providesBasicAuthInterceptor_whenBasicAuthUserNameAndPasswordConfigured() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.elasticsearch.hosts:http://host1:9200",
- "zipkin.storage.elasticsearch.username:somename",
- "zipkin.storage.elasticsearch.password:pass")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(context.getBean(OkHttpClient.class).networkInterceptors())
- .extracting(i -> i.getClass().getName())
- .contains("zipkin2.server.internal.elasticsearch.BasicAuthInterceptor");
- }
-
- @Test
- public void searchEnabled_false() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.search-enabled:false")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(context.getBean(ElasticsearchStorage.class).searchEnabled()).isFalse();
- }
-
- @Test
- public void autocompleteKeys_list() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.autocomplete-keys:environment")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(context.getBean(ElasticsearchStorage.class).autocompleteKeys())
- .containsOnly("environment");
- }
-
- @Test
- public void autocompleteTtl() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.autocomplete-ttl:60000")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(context.getBean(ElasticsearchStorage.class).autocompleteTtl())
- .isEqualTo(60000);
- }
-
- @Test
- public void autocompleteCardinality() {
- TestPropertyValues.of(
- "zipkin.storage.type:elasticsearch",
- "zipkin.storage.autocomplete-cardinality:5000")
- .applyTo(context);
- Access.registerElasticsearchHttp(context);
- context.refresh();
-
- assertThat(context.getBean(ElasticsearchStorage.class).autocompleteCardinality())
- .isEqualTo(5000);
- }
-
- ElasticsearchStorage es() {
- return context.getBean(ElasticsearchStorage.class);
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinMetricsHealth.java b/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinMetricsHealth.java
deleted file mode 100644
index ab92295..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinMetricsHealth.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.jayway.jsonpath.JsonPath;
-import com.linecorp.armeria.server.Server;
-import io.micrometer.prometheus.PrometheusMeterRegistry;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-import zipkin.server.ZipkinServer;
-import zipkin2.Span;
-import zipkin2.codec.SpanBytesEncoder;
-import zipkin2.storage.InMemoryStorage;
-
-import static java.util.Arrays.asList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static zipkin2.TestObjects.LOTS_OF_SPANS;
-import static zipkin2.server.internal.ITZipkinServer.url;
-
-@SpringBootTest(
- classes = ZipkinServer.class,
- webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
- properties = "spring.config.name=zipkin-server"
-)
-@RunWith(SpringRunner.class)
-public class ITZipkinMetricsHealth {
-
- @Autowired InMemoryStorage storage;
- @Autowired PrometheusMeterRegistry registry;
- @Autowired Server server;
-
- OkHttpClient client = new OkHttpClient.Builder().followRedirects(true).build();
-
- @Before public void init() {
- storage.clear();
- }
-
- @Test public void healthIsOK() throws Exception {
- assertThat(get("/health").isSuccessful())
- .isTrue();
-
- // ensure we don't track health in prometheus
- assertThat(scrape())
- .doesNotContain("health");
- }
-
- @Test public void metricsIsOK() throws Exception {
- assertThat(get("/metrics").isSuccessful())
- .isTrue();
-
- // ensure we don't track metrics in prometheus
- assertThat(scrape())
- .doesNotContain("metrics");
- }
-
- @Test public void actuatorIsOK() throws Exception {
- assertThat(get("/actuator").isSuccessful())
- .isTrue();
-
- // ensure we don't track actuator in prometheus
- assertThat(scrape())
- .doesNotContain("actuator");
- }
-
- @Test public void prometheusIsOK() throws Exception {
- assertThat(get("/prometheus").isSuccessful())
- .isTrue();
-
- // ensure we don't track prometheus, UI requests in prometheus
- assertThat(scrape())
- .doesNotContain("prometheus")
- .doesNotContain("uri=\"/zipkin")
- .doesNotContain("uri=\"/\"");
- }
-
- @Test public void notFound_prometheus() throws Exception {
- assertThat(get("/doo-wop").isSuccessful())
- .isFalse();
-
- assertThat(scrape())
- .contains("uri=\"NOT_FOUND\"")
- .doesNotContain("uri=\"/doo-wop");
- }
-
- @Test public void redirected_prometheus() throws Exception {
- assertThat(get("/").isSuccessful())
- .isTrue(); // follows redirects
-
- assertThat(scrape())
- .contains("uri=\"REDIRECTION\"")
- .contains("uri=\"/zipkin/index.html\"")
- .doesNotContain("uri=\"/\"");
- }
-
- @Test public void apiTemplate_prometheus() throws Exception {
- List<Span> spans = asList(LOTS_OF_SPANS[0]);
- byte[] body = SpanBytesEncoder.JSON_V2.encodeList(spans);
- assertThat(post("/api/v2/spans", body).isSuccessful())
- .isTrue();
-
- assertThat(get("/api/v2/trace/" + LOTS_OF_SPANS[0].traceId()).isSuccessful())
- .isTrue();
-
- assertThat(scrape())
- .contains("uri=\"/api/v2/trace/{traceId}\"")
- .doesNotContain(LOTS_OF_SPANS[0].traceId());
- }
-
- @Test public void forwardedRoute_prometheus() throws Exception {
- assertThat(get("/zipkin/api/v2/services").isSuccessful())
- .isTrue();
-
- assertThat(scrape())
- .contains("uri=\"/api/v2/services\"")
- .doesNotContain("uri=\"/zipkin/api/v2/services\"");
- }
-
- String scrape() throws InterruptedException {
- Thread.sleep(100);
- return registry.scrape();
- }
-
- /** Makes sure the prometheus filter doesn't count twice */
- @Test public void writeSpans_updatesPrometheusMetrics() throws Exception {
- List<Span> spans = asList(LOTS_OF_SPANS[0], LOTS_OF_SPANS[1], LOTS_OF_SPANS[2]);
- byte[] body = SpanBytesEncoder.JSON_V2.encodeList(spans);
-
- post("/api/v2/spans", body);
- post("/api/v2/spans", body);
-
- Thread.sleep(100); // sometimes travis flakes getting the "http.server.requests" timer
- double messagesCount = registry.counter("zipkin_collector.spans", "transport", "http").count();
- // Get the http count from the registry and it should match the summation previous count
- // and count of calls below
- long httpCount = registry
- .find("http.server.requests")
- .tag("uri", "/api/v2/spans")
- .timer()
- .count();
-
- // ensure unscoped counter does not exist
- assertThat(scrape())
- .doesNotContain("zipkin_collector_spans_total " + messagesCount)
- .contains("zipkin_collector_spans_total{transport=\"http\",} " + messagesCount)
- .contains(
- "http_server_requests_seconds_count{method=\"POST\",status=\"202\",uri=\"/api/v2/spans\",} "
- + httpCount);
- }
-
- @Test public void readsHealth() throws Exception {
- String json = getAsString("/health");
- assertThat(readString(json, "$.status"))
- .isIn("UP", "DOWN", "UNKNOWN");
- assertThat(readString(json, "$.zipkin.status"))
- .isIn("UP", "DOWN", "UNKNOWN");
- }
-
- @Test public void writesSpans_readMetricsFormat() throws Exception {
- byte[] span = {'z', 'i', 'p', 'k', 'i', 'n'};
- List<Span> spans = asList(LOTS_OF_SPANS[0], LOTS_OF_SPANS[1], LOTS_OF_SPANS[2]);
- byte[] body = SpanBytesEncoder.JSON_V2.encodeList(spans);
- post("/api/v2/spans", body);
- post("/api/v2/spans", body);
- post("/api/v2/spans", span);
- Thread.sleep(1500);
-
- String metrics = getAsString("/metrics");
-
- assertThat(readJson(metrics))
- .containsExactlyInAnyOrder(
- "gauge.zipkin_collector.message_spans.http"
- , "gauge.zipkin_collector.message_bytes.http"
- , "counter.zipkin_collector.messages.http"
- , "counter.zipkin_collector.bytes.http"
- , "counter.zipkin_collector.spans.http"
- , "counter.zipkin_collector.messages_dropped.http"
- , "counter.zipkin_collector.spans_dropped.http"
- );
- }
-
- private String getAsString(String path) throws IOException {
- Response response = get(path);
- assertThat(response.isSuccessful())
- .withFailMessage(response.toString())
- .isTrue();
- return response.body().string();
- }
-
- private Response get(String path) throws IOException {
- return client.newCall(new Request.Builder().url(url(server, path)).build()).execute();
- }
-
- private Response post(String path, byte[] body) throws IOException {
- return client.newCall(new Request.Builder()
- .url(url(server, path))
- .post(RequestBody.create(null, body))
- .build()).execute();
- }
-
- static String readString(String json, String jsonPath) {
- return JsonPath.compile(jsonPath).read(json);
- }
-
- static List readJson(String json) throws Exception {
- ObjectMapper mapper = new ObjectMapper();
- JsonNode jsonNode = mapper.readTree(json);
- List<String> fieldsList = new ArrayList<>();
- jsonNode.fieldNames().forEachRemaining(fieldsList::add);
- return fieldsList;
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinMetricsHealthDirty.java b/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinMetricsHealthDirty.java
deleted file mode 100644
index 3888342..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinMetricsHealthDirty.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal;
-
-import com.jayway.jsonpath.JsonPath;
-import com.linecorp.armeria.server.Server;
-import io.micrometer.prometheus.PrometheusMeterRegistry;
-import java.io.IOException;
-import java.util.List;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit4.SpringRunner;
-import zipkin.server.ZipkinServer;
-import zipkin2.Span;
-import zipkin2.codec.SpanBytesEncoder;
-import zipkin2.storage.InMemoryStorage;
-
-import static java.util.Arrays.asList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.springframework.test.annotation.DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD;
-import static zipkin2.TestObjects.LOTS_OF_SPANS;
-import static zipkin2.server.internal.ITZipkinServer.url;
-
-/**
- * We cannot clear the micrometer registry easily, so we have recreate the spring context. This is
- * extremely slow, so please only add tests that require isolation here.
- */
-@SpringBootTest(
- classes = ZipkinServer.class,
- webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
- properties = "spring.config.name=zipkin-server"
-)
-@RunWith(SpringRunner.class)
-@DirtiesContext(classMode = BEFORE_EACH_TEST_METHOD)
-public class ITZipkinMetricsHealthDirty {
-
- @Autowired InMemoryStorage storage;
- @Autowired PrometheusMeterRegistry registry;
- @Autowired Server server;
-
- OkHttpClient client = new OkHttpClient.Builder().followRedirects(true).build();
-
- @Before public void init() {
- storage.clear();
- }
-
- @Test public void writeSpans_updatesMetrics() throws Exception {
- List<Span> spans = asList(LOTS_OF_SPANS[0], LOTS_OF_SPANS[1], LOTS_OF_SPANS[2]);
- byte[] body = SpanBytesEncoder.JSON_V2.encodeList(spans);
- double messagesCount =
- registry.counter("zipkin_collector.messages", "transport", "http").count();
- double bytesCount = registry.counter("zipkin_collector.bytes", "transport", "http").count();
- double spansCount = registry.counter("zipkin_collector.spans", "transport", "http").count();
- post("/api/v2/spans", body);
- post("/api/v2/spans", body);
-
- String json = getAsString("/metrics");
-
- assertThat(readDouble(json, "$.['counter.zipkin_collector.messages.http']"))
- .isEqualTo(messagesCount + 2.0);
- assertThat(readDouble(json, "$.['counter.zipkin_collector.bytes.http']"))
- .isEqualTo(bytesCount + (body.length * 2));
- assertThat(readDouble(json, "$.['gauge.zipkin_collector.message_bytes.http']"))
- .isEqualTo(body.length);
- assertThat(readDouble(json, "$.['counter.zipkin_collector.spans.http']"))
- .isEqualTo(spansCount + (spans.size() * 2));
- assertThat(readDouble(json, "$.['gauge.zipkin_collector.message_spans.http']"))
- .isEqualTo(spans.size());
- }
-
- @Test public void writeSpans_malformedUpdatesMetrics() throws Exception {
- byte[] body = {'h', 'e', 'l', 'l', 'o'};
- Double messagesCount =
- registry.counter("zipkin_collector.messages", "transport", "http").count();
- Double messagesDroppedCount =
- registry.counter("zipkin_collector.messages_dropped", "transport", "http").count();
- post("/api/v2/spans", body);
-
- String json = getAsString("/metrics");
-
- assertThat(readDouble(json, "$.['counter.zipkin_collector.messages.http']"))
- .isEqualTo(messagesCount + 1);
- assertThat(readDouble(json, "$.['counter.zipkin_collector.messages_dropped.http']"))
- .isEqualTo(messagesDroppedCount + 1);
- }
-
- private String getAsString(String path) throws IOException {
- Response response = get(path);
- assertThat(response.isSuccessful())
- .withFailMessage(response.toString())
- .isTrue();
- return response.body().string();
- }
-
- private Response get(String path) throws IOException {
- return client.newCall(new Request.Builder().url(url(server, path)).build()).execute();
- }
-
- private Response post(String path, byte[] body) throws IOException {
- return client.newCall(new Request.Builder()
- .url(url(server, path))
- .post(RequestBody.create(null, body))
- .build()).execute();
- }
-
- static Double readDouble(String json, String jsonPath) {
- return JsonPath.compile(jsonPath).read(json);
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServer.java b/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServer.java
deleted file mode 100644
index d984fd8..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServer.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal;
-
-import com.linecorp.armeria.server.Server;
-import java.io.IOException;
-import java.util.List;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.Response;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-import zipkin.server.ZipkinServer;
-import zipkin2.Endpoint;
-import zipkin2.Span;
-import zipkin2.TestObjects;
-import zipkin2.codec.SpanBytesEncoder;
-import zipkin2.storage.InMemoryStorage;
-
-import static java.util.Arrays.asList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static zipkin2.TestObjects.TODAY;
-import static zipkin2.TestObjects.UTF_8;
-
-@SpringBootTest(
- classes = ZipkinServer.class,
- webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
- properties = "spring.config.name=zipkin-server"
-)
-@RunWith(SpringRunner.class)
-public class ITZipkinServer {
- static final List<Span> TRACE = asList(TestObjects.CLIENT_SPAN);
-
- @Autowired InMemoryStorage storage;
- @Autowired Server server;
-
- OkHttpClient client = new OkHttpClient.Builder().followRedirects(true).build();
-
- @Before public void init() {
- storage.clear();
- }
-
- @Test public void getTrace() throws Exception {
- storage.accept(TRACE).execute();
-
- Response response = get("/api/v2/trace/" + TRACE.get(0).traceId());
- assertThat(response.isSuccessful()).isTrue();
-
- assertThat(response.body().bytes())
- .containsExactly(SpanBytesEncoder.JSON_V2.encodeList(TRACE));
- }
-
- @Test public void tracesQueryRequiresNoParameters() throws Exception {
- storage.accept(TRACE).execute();
-
- Response response = get("/api/v2/traces");
- assertThat(response.isSuccessful()).isTrue();
- assertThat(response.body().string())
- .isEqualTo("[" + new String(SpanBytesEncoder.JSON_V2.encodeList(TRACE), UTF_8) + "]");
- }
-
- @Test public void v2WiresUp() throws Exception {
- assertThat(get("/api/v2/services").isSuccessful())
- .isTrue();
- }
-
- @Test public void doesntSetCacheControlOnNameEndpointsWhenLessThan4Services() throws Exception {
- storage.accept(TRACE).execute();
-
- assertThat(get("/api/v2/services").header("Cache-Control"))
- .isNull();
-
- assertThat(get("/api/v2/spans?serviceName=web").header("Cache-Control"))
- .isNull();
-
- assertThat(get("/api/v2/remoteServices?serviceName=web").header("Cache-Control"))
- .isNull();
- }
-
- @Test public void spanNameQueryWorksWithNonAsciiServiceName() throws Exception {
- assertThat(get("/api/v2/spans?serviceName=个人信息服务").code())
- .isEqualTo(200);
- }
-
- @Test public void remoteServiceNameQueryWorksWithNonAsciiServiceName() throws Exception {
- assertThat(get("/api/v2/remoteServices?serviceName=个人信息服务").code())
- .isEqualTo(200);
- }
-
- @Test public void setsCacheControlOnNameEndpointsWhenMoreThan3Services() throws Exception {
- List<String> services = asList("foo", "bar", "baz", "quz");
- for (int i = 0; i < services.size(); i++) {
- storage.accept(asList(
- Span.newBuilder().traceId("a").id(i + 1).timestamp(TODAY).name("whopper")
- .localEndpoint(Endpoint.newBuilder().serviceName(services.get(i)).build())
- .remoteEndpoint(Endpoint.newBuilder().serviceName(services.get(i) + 1).build())
- .build()
- )).execute();
- }
-
- assertThat(get("/api/v2/services").header("Cache-Control"))
- .isEqualTo("max-age=300, must-revalidate");
-
- assertThat(get("/api/v2/spans?serviceName=web").header("Cache-Control"))
- .isEqualTo("max-age=300, must-revalidate");
-
- assertThat(get("/api/v2/remoteServices?serviceName=web").header("Cache-Control"))
- .isEqualTo("max-age=300, must-revalidate");
-
- // Check that the response is alphabetically sorted.
- assertThat(get("/api/v2/services").body().string())
- .isEqualTo("[\"bar\",\"baz\",\"foo\",\"quz\"]");
- }
-
- @Test public void shouldAllowAnyOriginByDefault() throws Exception {
- Response response = client.newCall(new Request.Builder()
- .url(url(server, "/api/v2/traces"))
- .header("Origin", "http://foo.example.com")
- .build()).execute();
-
- assertThat(response.isSuccessful()).isTrue();
- assertThat(response.header("vary")).isNull();
- assertThat(response.header("access-control-allow-credentials")).isNull();
- assertThat(response.header("access-control-allow-origin")).contains("*");
- }
-
- @Test public void forwardsApiForUi() throws Exception {
- assertThat(get("/zipkin/api/v2/traces").isSuccessful()).isTrue();
- assertThat(get("/zipkin/api/v2/traces").isSuccessful()).isTrue();
- }
-
- /** Simulate a proxy which forwards / to zipkin as opposed to resolving / -> /zipkin first */
- @Test public void redirectedHeaderUsesOriginalHostAndPort() throws Exception {
- Request forwarded = new Request.Builder()
- .url(url(server, "/"))
- .addHeader("Host", "zipkin.com")
- .addHeader("X-Forwarded-Proto", "https")
- .addHeader("X-Forwarded-Port", "444")
- .build();
-
- Response response = client.newBuilder().followRedirects(false).build()
- .newCall(forwarded).execute();
-
- // Redirect header should be the proxy, not the backed IP/port
- assertThat(response.header("Location"))
- .isEqualTo("/zipkin/");
- }
-
- @Test public void infoEndpointIsAvailable() throws IOException {
- assertThat(get("/info").isSuccessful()).isTrue();
- }
-
- private Response get(String path) throws IOException {
- return client.newCall(new Request.Builder()
- .url(url(server, path))
- .build()).execute();
- }
-
- public static String url(Server server, String path) {
- return "http://localhost:" + server.activePort().get().localAddress().getPort() + path;
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServerAutocomplete.java b/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServerAutocomplete.java
deleted file mode 100644
index 521df81..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServerAutocomplete.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal;
-
-import com.linecorp.armeria.server.Server;
-import java.io.IOException;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-import zipkin.server.ZipkinServer;
-import zipkin2.Span;
-import zipkin2.codec.SpanBytesEncoder;
-
-import static java.util.Arrays.asList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static zipkin2.TestObjects.TODAY;
-import static zipkin2.server.internal.ITZipkinServer.url;
-
-/**
- * Integration test suite for autocomplete tags.
- *
- * Verifies that the whitelist of key can be configured via "zipkin.storage.autocomplete-keys".
- */
-@SpringBootTest(
- classes = ZipkinServer.class,
- webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
- properties = {
- "spring.config.name=zipkin-server",
- "zipkin.storage.autocomplete-keys=environment,clnt/finagle.version"
- }
-)
-@RunWith(SpringRunner.class)
-public class ITZipkinServerAutocomplete {
-
- @Autowired Server server;
- OkHttpClient client = new OkHttpClient.Builder().followRedirects(false).build();
-
- @Test public void setsCacheControlOnAutocompleteKeysEndpoint() throws Exception {
- assertThat(get("/api/v2/autocompleteKeys").header("Cache-Control"))
- .isEqualTo("max-age=300, must-revalidate");
- }
-
- @Test public void setsCacheControlOnAutocompleteEndpointWhenMoreThan3Values() throws Exception {
- assertThat(get("/api/v2/autocompleteValues?key=environment").header("Cache-Control"))
- .isNull();
- assertThat(get("/api/v2/autocompleteValues?key=clnt/finagle.version").header("Cache-Control"))
- .isNull();
-
- for (int i = 0; i < 4; i++) {
- post("/api/v2/spans", SpanBytesEncoder.JSON_V2.encodeList(asList(
- Span.newBuilder().traceId("a").id(i + 1).timestamp(TODAY).name("whopper")
- .putTag("clnt/finagle.version", "6.45." + i).build()
- )));
- }
-
- assertThat(get("/api/v2/autocompleteValues?key=environment").header("Cache-Control"))
- .isNull();
- assertThat(get("/api/v2/autocompleteValues?key=clnt/finagle.version").header("Cache-Control"))
- .isEqualTo("max-age=300, must-revalidate");
- }
-
- private Response get(String path) throws IOException {
- return client.newCall(new Request.Builder()
- .url(url(server, path))
- .build()).execute();
- }
-
- private Response post(String path, byte[] body) throws IOException {
- return client.newCall(new Request.Builder()
- .url(url(server, path))
- .post(RequestBody.create(null, body))
- .build()).execute();
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServerCORS.java b/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServerCORS.java
deleted file mode 100644
index be5bb43..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServerCORS.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal;
-
-import com.linecorp.armeria.server.Server;
-import java.io.IOException;
-import okhttp3.MediaType;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-import zipkin.server.ZipkinServer;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static zipkin2.server.internal.ITZipkinServer.url;
-
-/**
- * Integration test suite for CORS configuration.
- *
- * Verifies that allowed-origins can be configured via properties (zipkin.query.allowed-origins).
- */
-@SpringBootTest(
- classes = ZipkinServer.class,
- webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
- properties = {
- "spring.config.name=zipkin-server",
- "zipkin.query.allowed-origins=" + ITZipkinServerCORS.ALLOWED_ORIGIN
- }
-)
-@RunWith(SpringRunner.class)
-public class ITZipkinServerCORS {
- static final String ALLOWED_ORIGIN = "http://foo.example.com";
- static final String DISALLOWED_ORIGIN = "http://bar.example.com";
-
- @Autowired Server server;
- OkHttpClient client = new OkHttpClient.Builder().followRedirects(false).build();
-
- /** Notably, javascript makes pre-flight requests, and won't POST spans if disallowed! */
- @Test public void shouldAllowConfiguredOrigin_preflight() throws Exception {
- shouldPermitPreflight(optionsForOrigin("GET", "/api/v2/traces", ALLOWED_ORIGIN));
- shouldPermitPreflight(optionsForOrigin("POST", "/api/v2/spans", ALLOWED_ORIGIN));
- }
-
- static void shouldPermitPreflight(Response response) {
- assertThat(response.isSuccessful())
- .withFailMessage(response.toString())
- .isTrue();
- assertThat(response.header("vary")).contains("origin");
- assertThat(response.header("access-control-allow-origin")).contains(ALLOWED_ORIGIN);
- assertThat(response.header("access-control-allow-methods"))
- .contains(response.request().header("access-control-request-method"));
- assertThat(response.header("access-control-allow-credentials")).isNull();
- assertThat(response.header("access-control-allow-headers")).contains("content-type");
- }
-
- @Test public void shouldAllowConfiguredOrigin() throws Exception {
- shouldAllowConfiguredOrigin(getTracesFromOrigin(ALLOWED_ORIGIN));
- shouldAllowConfiguredOrigin(postSpansFromOrigin(ALLOWED_ORIGIN));
- }
-
- static void shouldAllowConfiguredOrigin(Response response) {
- assertThat(response.header("vary")).contains("origin");
- assertThat(response.header("access-control-allow-origin"))
- .contains(response.request().header("origin"));
- assertThat(response.header("access-control-allow-credentials")).isNull();
- assertThat(response.header("access-control-allow-headers")).contains("content-type");
- }
-
- @Test public void shouldDisallowOrigin() throws Exception {
- shouldDisallowOrigin(getTracesFromOrigin(DISALLOWED_ORIGIN));
- shouldDisallowOrigin(postSpansFromOrigin(DISALLOWED_ORIGIN));
- }
-
- static void shouldDisallowOrigin(Response response) {
- assertThat(response.header("vary")).isNull(); // TODO: We used to set vary: origin
- assertThat(response.header("access-control-allow-credentials")).isNull();
- assertThat(response.header("access-control-allow-origin")).isNull();
- assertThat(response.header("access-control-allow-headers")).isNull();
- }
-
- private Response optionsForOrigin(String method, String path, String origin) throws IOException {
- return client.newCall(new Request.Builder()
- .url(url(server, path))
- .header("Origin", origin)
- .header("access-control-request-method", method)
- .header("access-control-request-headers", "content-type")
- .method("OPTIONS", null)
- .build()).execute();
- }
-
- private Response getTracesFromOrigin(String origin) throws IOException {
- return client.newCall(new Request.Builder()
- .url(url(server, "/api/v2/traces"))
- .header("Origin", origin)
- .build()).execute();
- }
-
- private Response postSpansFromOrigin(String origin) throws IOException {
- return client.newCall(new Request.Builder()
- .url(url(server, "/api/v2/spans"))
- .header("Origin", origin)
- .post(RequestBody.create(MediaType.parse("application/json"), "[]"))
- .build()).execute();
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServerHttpCollectorDisabled.java b/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServerHttpCollectorDisabled.java
deleted file mode 100644
index 812f0f1..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServerHttpCollectorDisabled.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal;
-
-import com.linecorp.armeria.server.Server;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-import zipkin.server.ZipkinServer;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static zipkin2.server.internal.ITZipkinServer.url;
-
-/**
- * Query-only builds should be able to disable the HTTP collector, so that associated assets 404
- * instead of allowing creation of spans.
- */
-@SpringBootTest(
- classes = ZipkinServer.class,
- webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
- properties = {
- "zipkin.storage.type=", // cheat and test empty storage type
- "spring.config.name=zipkin-server",
- "zipkin.collector.http.enabled=false"
- })
-@RunWith(SpringRunner.class)
-public class ITZipkinServerHttpCollectorDisabled {
-
- @Autowired Server server;
- OkHttpClient client = new OkHttpClient.Builder().followRedirects(false).build();
-
- @Test public void httpCollectorEndpointReturns404() throws Exception {
- Response response = client.newCall(new Request.Builder()
- .url(url(server, "/api/v2/spans"))
- .post(RequestBody.create(null, "[]"))
- .build()).execute();
-
- assertThat(response.code()).isEqualTo(404);
- }
-
- /** Shows the same http path still works for GET */
- @Test public void getOnSpansEndpointReturnsOK() throws Exception {
- Response response = client.newCall(new Request.Builder()
- .url(url(server, "/api/v2/spans?serviceName=unknown"))
- .build()).execute();
-
- assertThat(response.isSuccessful()).isTrue();
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServerQueryDisabled.java b/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServerQueryDisabled.java
deleted file mode 100644
index 07f288b..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServerQueryDisabled.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal;
-
-import com.linecorp.armeria.server.Server;
-import java.io.IOException;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.Response;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-import zipkin.server.ZipkinServer;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static zipkin2.server.internal.ITZipkinServer.url;
-
-/**
- * Collector-only builds should be able to disable the query (and indirectly the UI), so that
- * associated assets 404 vs throw exceptions.
- */
-@SpringBootTest(
- classes = ZipkinServer.class,
- webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
- properties = {
- "spring.config.name=zipkin-server",
- "zipkin.query.enabled=false",
- "zipkin.ui.enabled=false"
- }
-)
-@RunWith(SpringRunner.class)
-public class ITZipkinServerQueryDisabled {
- @Autowired Server server;
- OkHttpClient client = new OkHttpClient.Builder().followRedirects(false).build();
-
- @Test public void queryRelatedEndpoints404() throws Exception {
- assertThat(get("/api/v2/traces").code()).isEqualTo(404);
- assertThat(get("/index.html").code()).isEqualTo(404);
-
- // but other endpoints are ok
- assertThat(get("/health").isSuccessful()).isTrue();
- }
-
- private Response get(String path) throws IOException {
- return client.newCall(new Request.Builder().url(url(server, path)).build()).execute();
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServerSsl.java b/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServerSsl.java
deleted file mode 100644
index d02ce75..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServerSsl.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal;
-
-import com.linecorp.armeria.client.ClientFactory;
-import com.linecorp.armeria.client.ClientFactoryBuilder;
-import com.linecorp.armeria.client.HttpClient;
-import com.linecorp.armeria.common.AggregatedHttpMessage;
-import com.linecorp.armeria.common.HttpStatus;
-import com.linecorp.armeria.common.SessionProtocol;
-import com.linecorp.armeria.server.Server;
-import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-import zipkin.server.ZipkinServer;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * This code ensures you can setup SSL.
- *
- * <p>This is inspired by com.linecorp.armeria.spring.ArmeriaSslConfigurationTest
- */
-@SpringBootTest(
- classes = ZipkinServer.class,
- webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
- properties = {
- "spring.config.name=zipkin-server",
- "armeria.ssl.enabled=true",
- "armeria.ports[1].port=0",
- "armeria.ports[1].protocols[0]=https",
- // redundant in zipkin-server-shared https://github.com/spring-projects/spring-boot/issues/16394
- "armeria.ports[0].port=${server.port}",
- "armeria.ports[0].protocols[0]=http",
- })
-@RunWith(SpringRunner.class)
-public class ITZipkinServerSsl {
- @Autowired Server server;
-
- // We typically use OkHttp in our tests, but Armeria bundles a handy insecure trust manager
- final ClientFactory clientFactory = new ClientFactoryBuilder()
- .sslContextCustomizer(b -> b.trustManager(InsecureTrustManagerFactory.INSTANCE))
- .build();
-
- @Test public void callHealthEndpoint_HTTP() {
- callHealthEndpoint(SessionProtocol.HTTP);
- }
-
- @Test public void callHealthEndpoint_HTTPS() {
- callHealthEndpoint(SessionProtocol.HTTPS);
- }
-
- void callHealthEndpoint(SessionProtocol http) {
- AggregatedHttpMessage response = HttpClient.of(clientFactory, baseUrl(server, http))
- .get("/health")
- .aggregate().join();
-
- assertThat(response.status()).isEqualTo(HttpStatus.OK);
- }
-
- static String baseUrl(Server server, SessionProtocol protocol) {
- return server.activePorts().values().stream()
- .filter(p -> p.hasProtocol(protocol)).findAny()
- .map(p -> protocol.uriText() + "://127.0.0.1:" + p.localAddress().getPort())
- .orElseThrow(() -> new AssertionError(protocol + " port not open"));
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/ZipkinServerConfigurationTest.java b/zipkin-server/src/test/java/zipkin2/server/internal/ZipkinServerConfigurationTest.java
deleted file mode 100644
index a194a56..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/ZipkinServerConfigurationTest.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal;
-
-import brave.Tracing;
-import com.linecorp.armeria.spring.actuate.ArmeriaSpringActuatorAutoConfiguration;
-import io.micrometer.core.instrument.MeterRegistry;
-import io.micrometer.prometheus.PrometheusConfig;
-import io.micrometer.prometheus.PrometheusMeterRegistry;
-import org.junit.After;
-import org.junit.Test;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
-import org.springframework.boot.actuate.health.HealthAggregator;
-import org.springframework.boot.actuate.health.OrderedHealthAggregator;
-import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
-import org.springframework.boot.test.util.TestPropertyValues;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import zipkin2.server.internal.brave.TracingConfiguration;
-import zipkin2.storage.StorageComponent;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
-
-public class ZipkinServerConfigurationTest {
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
-
- @After public void close() {
- context.close();
- }
-
- @Test public void httpCollector_enabledByDefault() {
- context.register(
- ArmeriaSpringActuatorAutoConfiguration.class,
- EndpointAutoConfiguration.class,
- PropertyPlaceholderAutoConfiguration.class,
- ZipkinServerConfigurationTest.Config.class,
- ZipkinServerConfiguration.class,
- ZipkinHttpCollector.class
- );
- context.refresh();
-
- assertThat(context.getBean(ZipkinHttpCollector.class)).isNotNull();
- }
-
- @Test(expected = NoSuchBeanDefinitionException.class)
- public void httpCollector_canDisable() {
- TestPropertyValues.of("zipkin.collector.http.enabled:false").applyTo(context);
- context.register(
- ArmeriaSpringActuatorAutoConfiguration.class,
- EndpointAutoConfiguration.class,
- PropertyPlaceholderAutoConfiguration.class,
- ZipkinServerConfigurationTest.Config.class,
- ZipkinServerConfiguration.class,
- ZipkinHttpCollector.class
- );
- context.refresh();
-
- context.getBean(ZipkinHttpCollector.class);
- }
-
- @Test public void query_enabledByDefault() {
- context.register(
- ArmeriaSpringActuatorAutoConfiguration.class,
- EndpointAutoConfiguration.class,
- PropertyPlaceholderAutoConfiguration.class,
- ZipkinServerConfigurationTest.Config.class,
- ZipkinServerConfiguration.class,
- ZipkinQueryApiV2.class
- );
- context.refresh();
-
- assertThat(context.getBean(ZipkinQueryApiV2.class)).isNotNull();
- }
-
- @Test public void query_canDisable() {
- TestPropertyValues.of("zipkin.query.enabled:false").applyTo(context);
- context.register(
- ArmeriaSpringActuatorAutoConfiguration.class,
- EndpointAutoConfiguration.class,
- PropertyPlaceholderAutoConfiguration.class,
- ZipkinServerConfigurationTest.Config.class,
- ZipkinServerConfiguration.class,
- ZipkinQueryApiV2.class
- );
- context.refresh();
-
- try {
- context.getBean(ZipkinQueryApiV2.class);
- failBecauseExceptionWasNotThrown(NoSuchBeanDefinitionException.class);
- } catch (NoSuchBeanDefinitionException e) {
- }
- }
-
- @Test public void selfTracing_canEnable() {
- TestPropertyValues.of("zipkin.self-tracing.enabled:true").applyTo(context);
- context.register(
- ArmeriaSpringActuatorAutoConfiguration.class,
- EndpointAutoConfiguration.class,
- PropertyPlaceholderAutoConfiguration.class,
- ZipkinServerConfigurationTest.Config.class,
- ZipkinServerConfiguration.class,
- TracingConfiguration.class
- );
- context.refresh();
-
- context.getBean(Tracing.class).close();
- }
-
- @Test public void search_canDisable() {
- TestPropertyValues.of("zipkin.storage.search-enabled:false").applyTo(context);
- context.register(
- ArmeriaSpringActuatorAutoConfiguration.class,
- EndpointAutoConfiguration.class,
- PropertyPlaceholderAutoConfiguration.class,
- ZipkinServerConfigurationTest.Config.class,
- ZipkinServerConfiguration.class
- );
- context.refresh();
-
- StorageComponent v2Storage = context.getBean(StorageComponent.class);
- assertThat(v2Storage)
- .extracting("searchEnabled")
- .containsExactly(false);
- }
-
- @Configuration
- public static class Config {
- @Bean
- public HealthAggregator healthAggregator() {
- return new OrderedHealthAggregator();
- }
-
- @Bean
- MeterRegistry registry () {
- return new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
- }
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/brave/ITZipkinSelfTracing.java b/zipkin-server/src/test/java/zipkin2/server/internal/brave/ITZipkinSelfTracing.java
deleted file mode 100644
index 597d9c3..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/brave/ITZipkinSelfTracing.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal.brave;
-
-import com.linecorp.armeria.server.Server;
-import java.io.IOException;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
-import zipkin.server.ZipkinServer;
-import zipkin2.storage.InMemoryStorage;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static zipkin2.server.internal.ITZipkinServer.url;
-
-@SpringBootTest(
- classes = ZipkinServer.class,
- webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
- properties = {
- "spring.config.name=zipkin-server",
- "zipkin.self-tracing.enabled=true"
- })
-@RunWith(SpringRunner.class)
-public class ITZipkinSelfTracing {
- @Autowired TracingStorageComponent storageComponent;
- @Autowired Server server;
-
- OkHttpClient client = new OkHttpClient.Builder().followRedirects(false).build();
-
- @Before
- public void clear() {
- ((InMemoryStorage) storageComponent.delegate).clear();
- }
-
- @Test
- public void getIsTraced_v2() throws Exception {
- assertThat(get("v2").body().string()).isEqualTo("[]");
-
- Thread.sleep(1000);
-
- assertThat(get("v2").body().string()).isEqualTo("[\"zipkin-server\"]");
- }
-
- @Test
- public void postIsTraced_v1() throws Exception {
- post("v1");
-
- Thread.sleep(1000);
-
- assertThat(get("v2").body().string()).isEqualTo("[\"zipkin-server\"]");
- }
-
- @Test
- public void postIsTraced_v2() throws Exception {
- post("v2");
-
- Thread.sleep(1000);
-
- assertThat(get("v2").body().string()).isEqualTo("[\"zipkin-server\"]");
- }
-
- private void post(String version) throws IOException {
- client
- .newCall(
- new Request.Builder()
- .url(url(server, "/api/" + version + "/spans"))
- .header("x-b3-sampled", "1") // we don't trace POST by default
- .post(RequestBody.create(null, "[" + "]"))
- .build())
- .execute();
- }
-
- private Response get(String version) throws IOException {
- return client
- .newCall(new Request.Builder()
- .url(url(server, "/api/" + version + "/services"))
- .build())
- .execute();
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/elasticsearch/BasicAuthInterceptorTest.java b/zipkin-server/src/test/java/zipkin2/server/internal/elasticsearch/BasicAuthInterceptorTest.java
deleted file mode 100644
index 443f7cc..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/elasticsearch/BasicAuthInterceptorTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal.elasticsearch;
-
-import java.io.IOException;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.MockWebServer;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-public class BasicAuthInterceptorTest {
-
- @Rule public ExpectedException thrown = ExpectedException.none();
-
- private MockWebServer mockWebServer;
- private OkHttpClient client;
-
- @Before
- public void beforeEach() {
- BasicAuthInterceptor interceptor =
- new BasicAuthInterceptor(new ZipkinElasticsearchStorageProperties());
- client = new OkHttpClient.Builder().addNetworkInterceptor(interceptor).build();
- mockWebServer = new MockWebServer();
- }
-
- @After
- public void afterEach() throws IOException {
- client.dispatcher().executorService().shutdownNow();
- mockWebServer.close();
- }
-
- @Test
- public void intercept_whenESReturns403AndJsonBody_throwsWithResponseBodyMessage()
- throws Exception {
-
- thrown.expect(IllegalStateException.class);
- thrown.expectMessage("Sadness.");
-
- mockWebServer.enqueue(
- new MockResponse().setResponseCode(403).setBody("{\"message\":\"Sadness.\"}"));
-
- client.newCall(new Request.Builder().url(mockWebServer.url("/")).build()).execute();
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/kafka/ZipkinKafkaCollectorConfigurationTest.java b/zipkin-server/src/test/java/zipkin2/server/internal/kafka/ZipkinKafkaCollectorConfigurationTest.java
deleted file mode 100644
index 6be4bad..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/kafka/ZipkinKafkaCollectorConfigurationTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal.kafka;
-
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
-import org.springframework.boot.test.util.TestPropertyValues;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import zipkin2.collector.CollectorMetrics;
-import zipkin2.collector.CollectorSampler;
-import zipkin2.collector.kafka.KafkaCollector;
-import zipkin2.storage.InMemoryStorage;
-import zipkin2.storage.StorageComponent;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ZipkinKafkaCollectorConfigurationTest {
-
- @Rule public ExpectedException thrown = ExpectedException.none();
-
- AnnotationConfigApplicationContext context;
-
- @After
- public void close() {
- if (context != null) {
- context.close();
- }
- }
-
- @Test
- public void doesNotProvideCollectorComponent_whenBootstrapServersUnset() {
- context = new AnnotationConfigApplicationContext();
- context.register(
- PropertyPlaceholderAutoConfiguration.class,
- ZipkinKafkaCollectorConfiguration.class,
- InMemoryConfiguration.class);
- context.refresh();
-
- thrown.expect(NoSuchBeanDefinitionException.class);
- context.getBean(KafkaCollector.class);
- }
-
- @Test
- public void providesCollectorComponent_whenBootstrapServersEmptyString() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of("zipkin.collector.kafka.bootstrap-servers:").applyTo(context);
- context.register(
- PropertyPlaceholderAutoConfiguration.class,
- ZipkinKafkaCollectorConfiguration.class,
- InMemoryConfiguration.class);
- context.refresh();
-
- thrown.expect(NoSuchBeanDefinitionException.class);
- context.getBean(KafkaCollector.class);
- }
-
- @Test
- public void providesCollectorComponent_whenBootstrapServersSet() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of("zipkin.collector.kafka.bootstrap-servers:localhost:9091").applyTo(context);
- context.register(
- PropertyPlaceholderAutoConfiguration.class,
- ZipkinKafkaCollectorConfiguration.class,
- InMemoryConfiguration.class);
- context.refresh();
-
- assertThat(context.getBean(KafkaCollector.class)).isNotNull();
- }
-
- @Configuration
- static class InMemoryConfiguration {
- @Bean
- CollectorSampler sampler() {
- return CollectorSampler.ALWAYS_SAMPLE;
- }
-
- @Bean
- CollectorMetrics metrics() {
- return CollectorMetrics.NOOP_METRICS;
- }
-
- @Bean
- StorageComponent storage() {
- return InMemoryStorage.newBuilder().build();
- }
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/kafka/ZipkinKafkaCollectorPropertiesTest.java b/zipkin-server/src/test/java/zipkin2/server/internal/kafka/ZipkinKafkaCollectorPropertiesTest.java
deleted file mode 100644
index 9afbe6d..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/kafka/ZipkinKafkaCollectorPropertiesTest.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal.kafka;
-
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ZipkinKafkaCollectorPropertiesTest {
- @Test
- public void stringPropertiesConvertEmptyStringsToNull() {
- final ZipkinKafkaCollectorProperties properties = new ZipkinKafkaCollectorProperties();
- properties.setBootstrapServers("");
- properties.setGroupId("");
- properties.setTopic("");
- assertThat(properties.getBootstrapServers()).isNull();
- assertThat(properties.getGroupId()).isNull();
- assertThat(properties.getTopic()).isNull();
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/rabbitmq/ZipkinRabbitMQCollectorConfigurationTest.java b/zipkin-server/src/test/java/zipkin2/server/internal/rabbitmq/ZipkinRabbitMQCollectorConfigurationTest.java
deleted file mode 100644
index 9232137..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/rabbitmq/ZipkinRabbitMQCollectorConfigurationTest.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal.rabbitmq;
-
-import org.junit.After;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
-import org.springframework.boot.test.util.TestPropertyValues;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import zipkin2.collector.CollectorMetrics;
-import zipkin2.collector.CollectorSampler;
-import zipkin2.collector.rabbitmq.RabbitMQCollector;
-import zipkin2.storage.InMemoryStorage;
-import zipkin2.storage.StorageComponent;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ZipkinRabbitMQCollectorConfigurationTest {
-
- @Rule public ExpectedException thrown = ExpectedException.none();
-
- private AnnotationConfigApplicationContext context;
-
- @After
- public void close() {
- if (context != null) {
- context.close();
- }
- }
-
- @Test
- public void doesNotProvideCollectorComponent_whenAddressAndUriNotSet() {
- context = new AnnotationConfigApplicationContext();
- context.register(
- PropertyPlaceholderAutoConfiguration.class,
- ZipkinRabbitMQCollectorConfiguration.class,
- InMemoryConfiguration.class);
- context.refresh();
-
- thrown.expect(NoSuchBeanDefinitionException.class);
- context.getBean(RabbitMQCollector.class);
- }
-
- @Test
- public void doesNotProvideCollectorComponent_whenAddressesAndUriIsEmptyString() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.collector.rabbitmq.addresses:",
- "zipkin.collector.rabbitmq.uri:")
- .applyTo(context);
- context.register(
- PropertyPlaceholderAutoConfiguration.class,
- ZipkinRabbitMQCollectorConfiguration.class,
- InMemoryConfiguration.class);
- context.refresh();
-
- thrown.expect(NoSuchBeanDefinitionException.class);
- context.getBean(RabbitMQCollector.class);
- }
-
- @Test
- @Ignore
- public void providesCollectorComponent_whenAddressesSet() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of("zipkin.collector.rabbitmq.addresses=localhost:5672").applyTo(context);
- context.register(
- PropertyPlaceholderAutoConfiguration.class,
- ZipkinRabbitMQCollectorConfiguration.class,
- InMemoryConfiguration.class);
- context.refresh();
-
- assertThat(context.getBean(RabbitMQCollector.class)).isNotNull();
- }
-
- @Configuration
- static class InMemoryConfiguration {
- @Bean
- CollectorSampler sampler() {
- return CollectorSampler.ALWAYS_SAMPLE;
- }
-
- @Bean
- CollectorMetrics metrics() {
- return CollectorMetrics.NOOP_METRICS;
- }
-
- @Bean
- StorageComponent storage() {
- return InMemoryStorage.newBuilder().build();
- }
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/rabbitmq/ZipkinRabbitMQCollectorPropertiesTest.java b/zipkin-server/src/test/java/zipkin2/server/internal/rabbitmq/ZipkinRabbitMQCollectorPropertiesTest.java
deleted file mode 100644
index e536478..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/rabbitmq/ZipkinRabbitMQCollectorPropertiesTest.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal.rabbitmq;
-
-import com.rabbitmq.client.ConnectionFactory;
-import java.net.URI;
-import java.util.Collections;
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ZipkinRabbitMQCollectorPropertiesTest {
- ZipkinRabbitMQCollectorProperties properties = new ZipkinRabbitMQCollectorProperties();
-
- @Test
- public void uriProperlyParsedAndIgnoresOtherProperties_whenUriSet() throws Exception {
- properties.setUri(URI.create("amqp://admin:admin@localhost:5678/myv"));
- properties.setAddresses(Collections.singletonList("will_not^work!"));
- properties.setUsername("bob");
- properties.setPassword("letmein");
- properties.setVirtualHost("drwho");
-
- assertThat(properties.toBuilder())
- .extracting("connectionFactory")
- .allSatisfy(
- object -> {
- ConnectionFactory connFactory = (ConnectionFactory) object;
- assertThat(connFactory.getHost()).isEqualTo("localhost");
- assertThat(connFactory.getPort()).isEqualTo(5678);
- assertThat(connFactory.getUsername()).isEqualTo("admin");
- assertThat(connFactory.getPassword()).isEqualTo("admin");
- assertThat(connFactory.getVirtualHost()).isEqualTo("myv");
- });
- }
-
- /** This prevents an empty RABBIT_URI variable from being mistaken as a real one */
- @Test
- public void ignoresEmptyURI() {
- properties.setUri(URI.create(""));
-
- assertThat(properties.getUri()).isNull();
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/ui/ITZipkinUiConfiguration.java b/zipkin-server/src/test/java/zipkin2/server/internal/ui/ITZipkinUiConfiguration.java
deleted file mode 100644
index 444eb3a..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/ui/ITZipkinUiConfiguration.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal.ui;
-
-import com.linecorp.armeria.client.HttpClient;
-import com.linecorp.armeria.common.AggregatedHttpMessage;
-import com.linecorp.armeria.common.HttpHeaderNames;
-import com.linecorp.armeria.common.HttpHeaders;
-import com.linecorp.armeria.common.HttpMethod;
-import com.linecorp.armeria.server.Server;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.net.URL;
-import java.util.stream.Stream;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.Response;
-import okio.Okio;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.context.annotation.Import;
-import org.springframework.test.context.junit4.SpringRunner;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-@RunWith(SpringRunner.class)
-@SpringBootTest(
- classes = ITZipkinUiConfiguration.TestServer.class,
- webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
- properties = {
- "zipkin.ui.base-path=/foozipkin",
- "server.compression.enabled=true",
- "server.compression.min-response-size=128"
- }
-)
-public class ITZipkinUiConfiguration {
-
- @Autowired Server server;
- OkHttpClient client = new OkHttpClient.Builder().followRedirects(false).build();
-
- /** The zipkin-ui is a single-page app. This prevents reloading all resources on each click. */
- @Test public void setsMaxAgeOnUiResources() throws Exception {
- assertThat(get("/zipkin/config.json").header("Cache-Control"))
- .isEqualTo("max-age=600");
- assertThat(get("/zipkin/index.html").header("Cache-Control"))
- .isEqualTo("max-age=60");
- assertThat(get("/zipkin/test.txt").header("Cache-Control"))
- .isEqualTo("max-age=31536000");
- }
-
- @Test public void redirectsIndex() throws Exception {
- String index = get("/zipkin/index.html").body().string();
-
- client = new OkHttpClient.Builder().followRedirects(true).build();
-
- Stream.of("/zipkin", "/").forEach(path -> {
- try {
- assertThat(get(path).body().string()).isEqualTo(index);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- });
- }
-
- /** Browsers honor conditional requests such as eTag. Let's make sure the server does */
- @Test public void conditionalRequests() throws Exception {
- Stream.of("/zipkin/config.json", "/zipkin/index.html", "/zipkin/test.txt").forEach(path -> {
- try {
- String etag = get(path).header("etag");
- assertThat(conditionalGet(path, etag).code())
- .isEqualTo(304);
- assertThat(conditionalGet(path, "aargh").code())
- .isEqualTo(200);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- });
- }
-
- /** Some assets are pretty big. ensure they use compression. */
- @Test public void supportsCompression() throws Exception {
- assertThat(getContentEncodingFromRequestThatAcceptsGzip("/zipkin/test.txt"))
- .isNull(); // too small to compress
- assertThat(getContentEncodingFromRequestThatAcceptsGzip("/zipkin/config.json"))
- .isEqualTo("gzip");
- }
-
- /**
- * The test sets the property {@code zipkin.ui.base-path=/foozipkin}, which should reflect in
- * index.html
- */
- @Test public void replacesBaseTag() throws Exception {
- assertThat(get("/zipkin/index.html").body().string())
- .isEqualToIgnoringWhitespace(stringFromClasspath("zipkin-ui/index.html")
- .replace("<base href=\"/\" />", "<base href=\"/foozipkin/\">"));
- }
-
- /** index.html is served separately. This tests other content is also loaded from the classpath. */
- @Test public void servesOtherContentFromClasspath() throws Exception {
- assertThat(get("/zipkin/test.txt").body().string())
- .isEqualToIgnoringWhitespace(stringFromClasspath("zipkin-ui/test.txt"));
- }
-
- @EnableAutoConfiguration
- @Import(ZipkinUiConfiguration.class)
- public static class TestServer {
- }
-
- private String stringFromClasspath(String path) throws IOException {
- URL url = getClass().getClassLoader().getResource(path);
- assertThat(url).isNotNull();
-
- try (InputStream fromClasspath = url.openStream()) {
- return Okio.buffer(Okio.source(fromClasspath)).readUtf8();
- }
- }
-
- private Response get(String path) throws IOException {
- return client.newCall(new Request.Builder()
- .url("http://localhost:" + port() + path)
- .build()).execute();
- }
-
- private Response conditionalGet(String path, String etag) throws IOException {
- return client.newCall(new Request.Builder()
- .url("http://localhost:" + port() + path)
- .header("If-None-Match", etag)
- .build()).execute();
- }
-
- private String getContentEncodingFromRequestThatAcceptsGzip(String path) {
- // We typically use OkHttp in our tests, but that automatically unzips..
- AggregatedHttpMessage response = HttpClient.of("http://localhost:" + port())
- .execute(HttpHeaders.of(HttpMethod.GET, path).set(HttpHeaderNames.ACCEPT_ENCODING, "gzip"))
- .aggregate().join();
- return response.headers().get(HttpHeaderNames.CONTENT_ENCODING);
- }
-
- private int port() {
- return server.activePort().get().localAddress().getPort();
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/ui/ZipkinUiConfigurationTest.java b/zipkin-server/src/test/java/zipkin2/server/internal/ui/ZipkinUiConfigurationTest.java
deleted file mode 100644
index 01d332d..0000000
--- a/zipkin-server/src/test/java/zipkin2/server/internal/ui/ZipkinUiConfigurationTest.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.server.internal.ui;
-
-import com.linecorp.armeria.common.AggregatedHttpMessage;
-import com.linecorp.armeria.common.HttpHeaderNames;
-import com.linecorp.armeria.common.HttpHeaders;
-import com.linecorp.armeria.common.HttpMethod;
-import com.linecorp.armeria.common.HttpRequest;
-import com.linecorp.armeria.common.MediaType;
-import com.linecorp.armeria.server.ServiceRequestContext;
-import io.netty.handler.codec.http.cookie.ClientCookieEncoder;
-import io.netty.handler.codec.http.cookie.Cookie;
-import io.netty.handler.codec.http.cookie.DefaultCookie;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.springframework.beans.factory.BeanCreationException;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
-import org.springframework.boot.test.util.TestPropertyValues;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import org.springframework.core.io.ClassPathResource;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.hamcrest.CoreMatchers.isA;
-import static org.junit.internal.matchers.ThrowableCauseMatcher.hasCause;
-
-public class ZipkinUiConfigurationTest {
-
- AnnotationConfigApplicationContext context;
-
- @After
- public void close() {
- if (context != null) {
- context.close();
- }
- }
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @Test
- public void indexHtmlFromClasspath() {
- context = createContext();
-
- assertThat(context.getBean(ZipkinUiConfiguration.class).indexHtml)
- .isNotNull();
- }
-
- @Test
- public void indexContentType() {
- context = createContext();
- assertThat(
- serveIndex().headers().contentType())
- .isEqualTo(MediaType.HTML_UTF_8);
- }
-
- @Test
- public void invalidIndexHtml() {
- // I failed to make Jsoup barf, even on nonsense like: "<head wait no I changed my mind this HTML is totally invalid <<<<<<<<<<<"
- // So let's just run with a case where the file doesn't exist
- context = createContextWithOverridenProperty("zipkin.ui.basepath:/foo/bar");
- ZipkinUiConfiguration ui = context.getBean(ZipkinUiConfiguration.class);
- ui.indexHtml = new ClassPathResource("does-not-exist.html");
-
- thrown.expect(RuntimeException.class);
- // There's a BeanInstantiationException nested in between BeanCreationException and IOException,
- // so we go one level deeper about causes. There's no `expectRootCause`.
- thrown.expectCause(hasCause(hasCause(isA(BeanCreationException.class))));
- serveIndex();
- }
-
- @Test
- public void canOverridesProperty_defaultLookback() {
- context = createContextWithOverridenProperty("zipkin.ui.defaultLookback:100");
-
- assertThat(context.getBean(ZipkinUiProperties.class).getDefaultLookback())
- .isEqualTo(100);
- }
-
- @Test
- public void canOverrideProperty_logsUrl() {
- final String url = "http://mycompany.com/kibana";
- context = createContextWithOverridenProperty("zipkin.ui.logs-url:" + url);
-
- assertThat(context.getBean(ZipkinUiProperties.class).getLogsUrl()).isEqualTo(url);
- }
-
- @Test
- public void logsUrlIsNullIfOverridenByEmpty() {
- context = createContextWithOverridenProperty("zipkin.ui.logs-url:");
-
- assertThat(context.getBean(ZipkinUiProperties.class).getLogsUrl()).isNull();
- }
-
- @Test
- public void logsUrlIsNullByDefault() {
- context = createContext();
-
- assertThat(context.getBean(ZipkinUiProperties.class).getLogsUrl()).isNull();
- }
-
- @Test(expected = NoSuchBeanDefinitionException.class)
- public void canOverridesProperty_disable() {
- context = createContextWithOverridenProperty("zipkin.ui.enabled:false");
-
- context.getBean(ZipkinUiProperties.class);
- }
-
- @Test
- public void canOverridesProperty_searchEnabled() {
- context = createContextWithOverridenProperty("zipkin.ui.search-enabled:false");
-
- assertThat(context.getBean(ZipkinUiProperties.class).isSearchEnabled()).isFalse();
- }
-
- @Test
- public void canOverrideProperty_dependencyLowErrorRate() {
- context = createContextWithOverridenProperty("zipkin.ui.dependency.low-error-rate:0.1");
-
- assertThat(context.getBean(ZipkinUiProperties.class).getDependency().getLowErrorRate())
- .isEqualTo(0.1f);
- }
-
- @Test
- public void canOverrideProperty_dependencyHighErrorRate() {
- context = createContextWithOverridenProperty("zipkin.ui.dependency.high-error-rate:0.1");
-
- assertThat(context.getBean(ZipkinUiProperties.class).getDependency().getHighErrorRate())
- .isEqualTo(0.1f);
- }
-
- @Test
- public void defaultBaseUrl_doesNotChangeResource() throws IOException {
- context = createContext();
-
- assertThat(new ByteArrayInputStream(serveIndex().content().array()))
- .hasSameContentAs(getClass().getResourceAsStream("/zipkin-ui/index.html"));
- }
-
- @Test
- public void canOverideProperty_basePath() {
- context = createContextWithOverridenProperty("zipkin.ui.basepath:/foo/bar");
-
- assertThat(serveIndex().contentUtf8())
- .contains("<base href=\"/foo/bar/\">");
- }
-
- @Test
- public void lensCookieOverridesIndex() {
- context = createContext();
-
- assertThat(serveIndex(new DefaultCookie("lens", "true")).contentUtf8())
- .contains("zipkin-lens");
- }
-
- @Test
- public void canOverideProperty_specialCaseRoot() {
- context = createContextWithOverridenProperty("zipkin.ui.basepath:/");
-
- assertThat(serveIndex().contentUtf8())
- .contains("<base href=\"/\">");
- }
-
- private AggregatedHttpMessage serveIndex(Cookie... cookies) {
- HttpHeaders headers = HttpHeaders.of(HttpMethod.GET, "/");
- String encodedCookies = ClientCookieEncoder.LAX.encode(cookies);
- if (encodedCookies != null) {
- headers.set(HttpHeaderNames.COOKIE, encodedCookies);
- }
- HttpRequest req = HttpRequest.of(headers);
- try {
- return context.getBean(ZipkinUiConfiguration.class).indexSwitchingService()
- .serve(ServiceRequestContext.of(req), req).aggregate()
- .get();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- private static AnnotationConfigApplicationContext createContext() {
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
- context.register(PropertyPlaceholderAutoConfiguration.class, ZipkinUiConfiguration.class);
- context.refresh();
- return context;
- }
-
- private static AnnotationConfigApplicationContext createContextWithOverridenProperty(
- String pair) {
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(pair).applyTo(context);
- context.register(PropertyPlaceholderAutoConfiguration.class, ZipkinUiConfiguration.class);
- context.refresh();
- return context;
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/storage/cassandra/ZipkinCassandraStorageAutoConfigurationTest.java b/zipkin-server/src/test/java/zipkin2/storage/cassandra/ZipkinCassandraStorageAutoConfigurationTest.java
deleted file mode 100644
index 8c391cb..0000000
--- a/zipkin-server/src/test/java/zipkin2/storage/cassandra/ZipkinCassandraStorageAutoConfigurationTest.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.storage.cassandra;
-
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.boot.test.util.TestPropertyValues;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import zipkin2.server.internal.cassandra3.Access;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ZipkinCassandraStorageAutoConfigurationTest {
-
- @Rule public ExpectedException thrown = ExpectedException.none();
-
- AnnotationConfigApplicationContext context;
-
- @After
- public void close() {
- if (context != null) {
- context.close();
- }
- }
-
- @Test
- public void doesntProvidesStorageComponent_whenStorageTypeNotCassandra() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of("zipkin.storage.type:elasticsearch").applyTo(context);
- Access.registerCassandra3(context);
- context.refresh();
-
- thrown.expect(NoSuchBeanDefinitionException.class);
- context.getBean(CassandraStorage.class);
- }
-
- @Test
- public void providesStorageComponent_whenStorageTypeCassandra() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of("zipkin.storage.type:cassandra3").applyTo(context);
- Access.registerCassandra3(context);
- context.refresh();
-
- assertThat(context.getBean(CassandraStorage.class)).isNotNull();
- }
-
- @Test
- public void canOverridesProperty_contactPoints() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:cassandra3",
- "zipkin.storage.cassandra3.contact-points:host1,host2" // note snake-case supported
- ).applyTo(context);
- Access.registerCassandra3(context);
- context.refresh();
-
- assertThat(context.getBean(CassandraStorage.class).contactPoints()).isEqualTo("host1,host2");
- }
-
- @Test
- public void strictTraceId_defaultsToTrue() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of("zipkin.storage.type:cassandra3").applyTo(context);
- Access.registerCassandra3(context);
- context.refresh();
-
- assertThat(context.getBean(CassandraStorage.class).strictTraceId()).isTrue();
- }
-
- @Test
- public void strictTraceId_canSetToFalse() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:cassandra3",
- "zipkin.storage.strict-trace-id:false")
- .applyTo(context);
- Access.registerCassandra3(context);
- context.refresh();
-
- assertThat(context.getBean(CassandraStorage.class).strictTraceId()).isFalse();
- }
-
- @Test
- public void searchEnabled_canSetToFalse() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:cassandra3",
- "zipkin.storage.search-enabled:false")
- .applyTo(context);
- Access.registerCassandra3(context);
- context.refresh();
-
- assertThat(context.getBean(CassandraStorage.class).searchEnabled()).isFalse();
- }
-
- @Test
- public void autocompleteKeys_list() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:cassandra3",
- "zipkin.storage.autocomplete-keys:environment")
- .applyTo(context);
- Access.registerCassandra3(context);
- context.refresh();
-
- assertThat(context.getBean(CassandraStorage.class).autocompleteKeys())
- .containsOnly("environment");
- }
-
- @Test
- public void autocompleteTtl() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:cassandra3",
- "zipkin.storage.autocomplete-ttl:60000")
- .applyTo(context);
- Access.registerCassandra3(context);
- context.refresh();
-
- assertThat(context.getBean(CassandraStorage.class).autocompleteTtl())
- .isEqualTo(60000);
- }
-
- @Test
- public void autocompleteCardinality() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:cassandra3",
- "zipkin.storage.autocomplete-cardinality:5000")
- .applyTo(context);
- Access.registerCassandra3(context);
- context.refresh();
-
- assertThat(context.getBean(CassandraStorage.class).autocompleteCardinality())
- .isEqualTo(5000);
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/storage/cassandra/v1/ZipkinCassandraStorageConfigurationTest.java b/zipkin-server/src/test/java/zipkin2/storage/cassandra/v1/ZipkinCassandraStorageConfigurationTest.java
deleted file mode 100644
index d281ba4..0000000
--- a/zipkin-server/src/test/java/zipkin2/storage/cassandra/v1/ZipkinCassandraStorageConfigurationTest.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.storage.cassandra.v1;
-
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.boot.test.util.TestPropertyValues;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import zipkin2.server.internal.cassandra.Access;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ZipkinCassandraStorageConfigurationTest {
-
- @Rule public ExpectedException thrown = ExpectedException.none();
-
- AnnotationConfigApplicationContext context;
-
- @After
- public void close() {
- if (context != null) {
- context.close();
- }
- }
-
- @Test
- public void doesntProvidesStorageComponent_whenStorageTypeNotCassandra() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of("zipkin.storage.type:elasticsearch").applyTo(context);
- Access.registerCassandra(context);
- context.refresh();
-
- thrown.expect(NoSuchBeanDefinitionException.class);
- context.getBean(CassandraStorage.class);
- }
-
- @Test
- public void providesStorageComponent_whenStorageTypeCassandra() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of("zipkin.storage.type:cassandra").applyTo(context);
- Access.registerCassandra(context);
- context.refresh();
-
- assertThat(context.getBean(CassandraStorage.class)).isNotNull();
- }
-
- @Test
- public void canOverridesProperty_contactPoints() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:cassandra",
- "zipkin.storage.cassandra.contact-points:host1,host2" // note snake-case supported
- ).applyTo(context);
- Access.registerCassandra(context);
- context.refresh();
-
- assertThat(context.getBean(CassandraStorage.class).contactPoints).isEqualTo("host1,host2");
- }
-
- @Test
- public void strictTraceId_defaultsToTrue() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of("zipkin.storage.type:cassandra").applyTo(context);
- Access.registerCassandra(context);
- context.refresh();
- assertThat(context.getBean(CassandraStorage.class).strictTraceId).isTrue();
- }
-
- @Test
- public void strictTraceId_canSetToFalse() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:cassandra",
- "zipkin.storage.strict-trace-id:false")
- .applyTo(context);
- Access.registerCassandra(context);
- context.refresh();
-
- assertThat(context.getBean(CassandraStorage.class).strictTraceId).isFalse();
- }
-
- @Test
- public void autocompleteKeys_list() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:cassandra",
- "zipkin.storage.autocomplete-keys:environment")
- .applyTo(context);
- Access.registerCassandra(context);
- context.refresh();
-
- assertThat(context.getBean(CassandraStorage.class).autocompleteKeys)
- .containsOnly("environment");
- }
-
- @Test
- public void autocompleteTtl() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:cassandra",
- "zipkin.storage.autocomplete-ttl:60000")
- .applyTo(context);
- Access.registerCassandra(context);
- context.refresh();
-
- assertThat(context.getBean(CassandraStorage.class).autocompleteTtl)
- .isEqualTo(60000);
- }
-
- @Test
- public void autocompleteCardinality() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:cassandra",
- "zipkin.storage.autocomplete-cardinality:5000")
- .applyTo(context);
- Access.registerCassandra(context);
- context.refresh();
-
- assertThat(context.getBean(CassandraStorage.class).autocompleteCardinality)
- .isEqualTo(5000);
- }
-}
diff --git a/zipkin-server/src/test/java/zipkin2/storage/mysql/v1/ZipkinMySQLStorageConfigurationTest.java b/zipkin-server/src/test/java/zipkin2/storage/mysql/v1/ZipkinMySQLStorageConfigurationTest.java
deleted file mode 100644
index 9b90ef6..0000000
--- a/zipkin-server/src/test/java/zipkin2/storage/mysql/v1/ZipkinMySQLStorageConfigurationTest.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package zipkin2.storage.mysql.v1;
-
-import com.zaxxer.hikari.HikariDataSource;
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.boot.test.util.TestPropertyValues;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import zipkin2.server.internal.mysql.Access;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ZipkinMySQLStorageConfigurationTest {
-
- @Rule public ExpectedException thrown = ExpectedException.none();
-
- AnnotationConfigApplicationContext context;
-
- @After
- public void close() {
- if (context != null) {
- context.close();
- }
- }
-
- @Test
- public void doesntProvidesStorageComponent_whenStorageTypeNotMySQL() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of("zipkin.storage.type:cassandra").applyTo(context);
- Access.registerMySQL(context);
- context.refresh();
-
- thrown.expect(NoSuchBeanDefinitionException.class);
- context.getBean(MySQLStorage.class);
- }
-
- @Test
- public void providesStorageComponent_whenStorageTypeMySQL() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of("zipkin.storage.type:mysql").applyTo(context);
- Access.registerMySQL(context);
- context.refresh();
-
- assertThat(context.getBean(MySQLStorage.class)).isNotNull();
- }
-
- @Test
- public void canOverridesProperty_username() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:mysql",
- "zipkin.storage.mysql.username:robot")
- .applyTo(context);
- Access.registerMySQL(context);
- context.refresh();
-
- assertThat(context.getBean(HikariDataSource.class).getUsername()).isEqualTo("robot");
- }
-
- @Test
- public void strictTraceId_defaultsToTrue() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of("zipkin.storage.type:mysql").applyTo(context);
- Access.registerMySQL(context);
- context.refresh();
- assertThat(context.getBean(MySQLStorage.class).strictTraceId).isTrue();
- }
-
- @Test
- public void strictTraceId_canSetToFalse() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:mysql",
- "zipkin.storage.strict-trace-id:false")
- .applyTo(context);
- Access.registerMySQL(context);
- context.refresh();
-
- assertThat(context.getBean(MySQLStorage.class).strictTraceId).isFalse();
- }
-
- @Test
- public void searchEnabled_canSetToFalse() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:mysql",
- "zipkin.storage.search-enabled:false")
- .applyTo(context);
- Access.registerMySQL(context);
- context.refresh();
-
- assertThat(context.getBean(MySQLStorage.class).searchEnabled).isFalse();
- }
-
- @Test
- public void autocompleteKeys_list() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:mysql",
- "zipkin.storage.autocomplete-keys:environment")
- .applyTo(context);
- Access.registerMySQL(context);
- context.refresh();
-
- assertThat(context.getBean(MySQLStorage.class).autocompleteKeys)
- .containsOnly("environment");
- }
-
- @Test
- public void usesJdbcUrl_whenPresent() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:mysql",
- "zipkin.storage.mysql"
- + ".jdbc-url:jdbc:mysql://host1,host2,host3/zipkin")
- .applyTo(context);
- Access.registerMySQL(context);
- context.refresh();
-
- assertThat(context.getBean(HikariDataSource.class).getJdbcUrl()).isEqualTo("jdbc:mysql://host1,host2,host3/zipkin");
- }
-
- @Test
- public void usesRegularConfig_whenBlank() {
- context = new AnnotationConfigApplicationContext();
- TestPropertyValues.of(
- "zipkin.storage.type:mysql",
- "zipkin.storage.mysql.jdbc-url:",
- "zipkin.storage.mysql.host:host",
- "zipkin.storage.mysql.port:3306",
- "zipkin.storage.mysql.username:root",
- "zipkin.storage.mysql.password:secret",
- "zipkin.storage.mysql.db:zipkin")
- .applyTo(context);
- Access.registerMySQL(context);
- context.refresh();
-
- assertThat(context.getBean(HikariDataSource.class).getJdbcUrl()).isEqualTo("jdbc:mysql://host:3306/zipkin?autoReconnect=true&useSSL=false&useUnicode=yes&characterEncoding=UTF-8");
- }
-}
diff --git a/zipkin-server/src/test/kotlin/zipkin/server/ITEnableZipkinServer.kt b/zipkin-server/src/test/kotlin/zipkin/server/ITEnableZipkinServer.kt
new file mode 100644
index 0000000..7a383e0
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin/server/ITEnableZipkinServer.kt
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin.server
+
+import com.linecorp.armeria.server.Server
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.autoconfigure.SpringBootApplication
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.junit4.SpringRunner
+import zipkin2.server.internal.Http
+
+@SpringBootTest(
+ classes = [ITEnableZipkinServer.CustomServer::class],
+ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+ properties = ["spring.config.name=zipkin-server"]
+)
+@RunWith(SpringRunner::class)
+class ITEnableZipkinServer {
+ @SpringBootApplication
+ @EnableZipkinServer
+ open class CustomServer
+
+ @Autowired lateinit var server: Server
+
+ @Test fun writeSpans_noContentTypeIsJson() {
+ assertThat(Http.get(server, "/api/v2/services").code())
+ .isEqualTo(200)
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/collector/kafka/ZipkinKafkaCollectorPropertiesOverrideTest.kt b/zipkin-server/src/test/kotlin/zipkin2/collector/kafka/ZipkinKafkaCollectorPropertiesOverrideTest.kt
new file mode 100644
index 0000000..32d75b9
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/collector/kafka/ZipkinKafkaCollectorPropertiesOverrideTest.kt
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.collector.kafka
+
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.After
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.springframework.boot.test.util.TestPropertyValues
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
+import zipkin2.server.internal.kafka.Access
+
+@RunWith(Parameterized::class)
+class ZipkinKafkaCollectorPropertiesOverrideTest(
+ val property: String,
+ val value: Any,
+ val builderExtractor: (KafkaCollector.Builder) -> Any
+) {
+
+ companion object {
+ @JvmStatic @Parameterized.Parameters fun data(): List<Array<Any?>> {
+ return listOf(
+ parameters("bootstrap-servers", "127.0.0.1:9092",
+ { b -> b.properties.getProperty("bootstrap.servers") }),
+ parameters("group-id", "zapkin",
+ { b -> b.properties.getProperty("group.id") }),
+ parameters("topic", "zapkin",
+ { b -> b.topic }),
+ parameters("streams", 2,
+ { b -> b.streams }),
+ parameters("overrides.auto.offset.reset", "latest",
+ { b -> b.properties.getProperty("auto.offset.reset") })
+ )
+ }
+
+ /** to allow us to define with a lambda */
+ internal fun <T> parameters(
+ propertySuffix: String, value: T, builderExtractor: (KafkaCollector.Builder) -> T
+ ): Array<Any?> = arrayOf(propertySuffix, value, builderExtractor)
+ }
+
+ var context = AnnotationConfigApplicationContext()
+
+ @After fun close() {
+ context.close()
+ }
+
+ @Test fun propertyTransferredToCollectorBuilder() {
+ TestPropertyValues.of("zipkin.collector.kafka.$property:$value").applyTo(context)
+ Access.registerKafkaProperties(context)
+ context.refresh()
+
+ assertThat(Access.collectorBuilder(context))
+ .extracting(builderExtractor)
+ .isEqualTo(value)
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/collector/rabbitmq/ZipkinRabbitMQCollectorPropertiesOverrideTest.kt b/zipkin-server/src/test/kotlin/zipkin2/collector/rabbitmq/ZipkinRabbitMQCollectorPropertiesOverrideTest.kt
new file mode 100644
index 0000000..bce32c2
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/collector/rabbitmq/ZipkinRabbitMQCollectorPropertiesOverrideTest.kt
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.collector.rabbitmq
+
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.After
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.springframework.boot.test.util.TestPropertyValues
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
+import zipkin2.server.internal.rabbitmq.Access
+import java.net.URI
+
+@RunWith(Parameterized::class)
+class ZipkinRabbitMQPropertiesOverrideTest(
+ val property: String,
+ val value: Any,
+ val builderExtractor: (RabbitMQCollector.Builder) -> Any
+) {
+
+ companion object {
+ @JvmStatic @Parameterized.Parameters fun data(): List<Array<Any?>> {
+ return listOf(
+ // intentionally punting on comma-separated form of a list of addresses as it doesn't fit
+ // this unit test. Better to make a separate one than force-fit!
+ parameters("addresses", "localhost:5671",
+ { builder -> builder.addresses[0].toString() }),
+ parameters("concurrency", 2,
+ { builder -> builder.concurrency }),
+ parameters("connectionTimeout", 30000,
+ { builder -> builder.connectionFactory.connectionTimeout }),
+ parameters("password", "admin",
+ { builder -> builder.connectionFactory.password }),
+ parameters("queue", "zapkin",
+ { builder -> builder.queue }),
+ parameters("username", "admin",
+ { builder -> builder.connectionFactory.username }),
+ parameters("virtualHost", "/hello",
+ { builder -> builder.connectionFactory.virtualHost }),
+ parameters("useSsl", true,
+ { builder -> builder.connectionFactory.isSSL }),
+ parameters("uri", URI.create("amqp://localhost"),
+ { builder -> URI.create("amqp://" + builder.connectionFactory.host) })
+ )
+ }
+
+ /** to allow us to define with a lambda */
+ internal fun <T> parameters(
+ propertySuffix: String, value: T, builderExtractor: (RabbitMQCollector.Builder) -> T
+ ): Array<Any?> = arrayOf(propertySuffix, value, builderExtractor)
+ }
+
+ var context = AnnotationConfigApplicationContext()
+
+ @After fun close() {
+ context.close()
+ }
+
+ @Test fun propertyTransferredToCollectorBuilder() {
+ TestPropertyValues.of("zipkin.collector.rabbitmq.$property:$value").applyTo(context)
+ Access.registerRabbitMQProperties(context)
+ context.refresh()
+
+ assertThat(Access.collectorBuilder(context))
+ .extracting(builderExtractor)
+ .isEqualTo(value)
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/elasticsearch/ZipkinElasticsearchStorageAutoConfigurationTest.kt b/zipkin-server/src/test/kotlin/zipkin2/elasticsearch/ZipkinElasticsearchStorageAutoConfigurationTest.kt
new file mode 100644
index 0000000..42f2ea9
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/elasticsearch/ZipkinElasticsearchStorageAutoConfigurationTest.kt
@@ -0,0 +1,360 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.elasticsearch
+
+import okhttp3.Interceptor
+import okhttp3.OkHttpClient
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.After
+import org.junit.Test
+import org.springframework.beans.factory.BeanCreationException
+import org.springframework.beans.factory.NoSuchBeanDefinitionException
+import org.springframework.beans.factory.annotation.Qualifier
+import org.springframework.boot.test.util.TestPropertyValues
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+import zipkin2.server.internal.elasticsearch.Access
+import java.util.concurrent.TimeUnit
+
+class ZipkinElasticsearchStorageAutoConfigurationTest {
+ val context = AnnotationConfigApplicationContext()
+ @After fun closeContext() = context.close()
+ internal fun es() = context.getBean(ElasticsearchStorage::class.java)
+
+ @Test(expected = NoSuchBeanDefinitionException::class)
+ fun doesntProvideStorageComponent_whenStorageTypeNotElasticsearch() {
+ TestPropertyValues.of("zipkin.storage.type:cassandra").applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ es()
+ }
+
+ @Test fun providesStorageComponent_whenStorageTypeElasticsearchAndHostsAreUrls() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:http://host1:9200")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es()).isNotNull
+ }
+
+ @Test fun canOverridesProperty_hostsWithList() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:http://host1:9200,http://host2:9200")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es().hostsSupplier().get())
+ .containsExactly("http://host1:9200", "http://host2:9200")
+ }
+
+ @Test fun configuresPipeline() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:http://host1:9200",
+ "zipkin.storage.elasticsearch.pipeline:zipkin")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es().pipeline()).isEqualTo("zipkin")
+ }
+
+ @Test fun configuresMaxRequests() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:http://host1:9200",
+ "zipkin.storage.elasticsearch.max-requests:200")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es().maxRequests()).isEqualTo(200)
+ }
+
+ /** This helps ensure old setups don't break (provided they have http port 9200 open) */
+ @Test fun coersesPort9300To9200() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:host1:9300")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es().hostsSupplier().get()).containsExactly("http://host1:9200")
+ }
+
+ @Test fun httpPrefixOptional() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:host1:9200")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es().hostsSupplier().get()).containsExactly("http://host1:9200")
+ }
+
+ @Test fun defaultsToPort9200() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:host1")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es().hostsSupplier().get()).containsExactly("http://host1:9200")
+ }
+
+ @Configuration
+ open class InterceptorConfiguration {
+
+ @Bean @Qualifier("zipkinElasticsearchHttp") open fun one(): Interceptor {
+ return one
+ }
+
+ @Bean @Qualifier("zipkinElasticsearchHttp") open fun two(): Interceptor {
+ return two
+ }
+
+ companion object {
+ val one: Interceptor = Interceptor { chain -> chain.proceed(chain.request()) }
+ val two: Interceptor = Interceptor { chain -> chain.proceed(chain.request()) }
+ }
+ }
+
+ /** Ensures we can wire up network interceptors, such as for logging or authentication */
+ @Test fun usesInterceptorsQualifiedWith_zipkinElasticsearchHttp() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:host1:9200")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.register(InterceptorConfiguration::class.java)
+ context.refresh()
+
+ assertThat(context.getBean(OkHttpClient::class.java).networkInterceptors())
+ .containsOnlyOnce(InterceptorConfiguration.one, InterceptorConfiguration.two)
+ }
+
+ @Test fun timeout_defaultsTo10Seconds() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:host1:9200")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ val client = context.getBean(OkHttpClient::class.java)
+ assertThat(client.connectTimeoutMillis()).isEqualTo(10000)
+ assertThat(client.readTimeoutMillis()).isEqualTo(10000)
+ assertThat(client.writeTimeoutMillis()).isEqualTo(10000)
+ }
+
+ @Test fun timeout_override() {
+ val timeout = 30000
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:http://host1:9200",
+ "zipkin.storage.elasticsearch.timeout:$timeout")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ val client = context.getBean(OkHttpClient::class.java)
+ assertThat(client.connectTimeoutMillis()).isEqualTo(timeout)
+ assertThat(client.readTimeoutMillis()).isEqualTo(timeout)
+ assertThat(client.writeTimeoutMillis()).isEqualTo(timeout)
+ }
+
+ @Test fun strictTraceId_defaultsToTrue() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:http://host1:9200")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+ assertThat(es().strictTraceId()).isTrue()
+ }
+
+ @Test fun strictTraceId_canSetToFalse() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:http://host1:9200",
+ "zipkin.storage.strict-trace-id:false")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es().strictTraceId()).isFalse()
+ }
+
+ @Test fun dailyIndexFormat() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:http://host1:9200")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es().indexNameFormatter().formatTypeAndTimestamp("span", 0))
+ .isEqualTo("zipkin*span-1970-01-01")
+ }
+
+ @Test fun dailyIndexFormat_overridingPrefix() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:http://host1:9200",
+ "zipkin.storage.elasticsearch.index:zipkin_prod")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es().indexNameFormatter().formatTypeAndTimestamp("span", 0))
+ .isEqualTo("zipkin_prod*span-1970-01-01")
+ }
+
+ @Test fun dailyIndexFormat_overridingDateSeparator() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:http://host1:9200",
+ "zipkin.storage.elasticsearch.date-separator:.")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es().indexNameFormatter().formatTypeAndTimestamp("span", 0))
+ .isEqualTo("zipkin*span-1970.01.01")
+ }
+
+ @Test fun dailyIndexFormat_overridingDateSeparator_empty() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:http://host1:9200",
+ "zipkin.storage.elasticsearch.date-separator:")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es().indexNameFormatter().formatTypeAndTimestamp("span", 0))
+ .isEqualTo("zipkin*span-19700101")
+ }
+
+ @Test(expected = BeanCreationException::class)
+ fun dailyIndexFormat_overridingDateSeparator_invalidToBeMultiChar() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:http://host1:9200",
+ "zipkin.storage.elasticsearch.date-separator:blagho")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+
+ context.refresh()
+ }
+
+ @Test fun namesLookbackAssignedFromQueryLookback() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:http://host1:9200",
+ "zipkin.query.lookback:" + TimeUnit.DAYS.toMillis(2))
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es().namesLookback()).isEqualTo(TimeUnit.DAYS.toMillis(2).toInt())
+ }
+
+ @Test(expected = NoSuchBeanDefinitionException::class)
+ fun doesntProvideBasicAuthInterceptor_whenBasicAuthUserNameandPasswordNotConfigured() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:http://host1:9200")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ context.getBean(Interceptor::class.java)
+ }
+
+ @Test fun providesBasicAuthInterceptor_whenBasicAuthUserNameAndPasswordConfigured() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.elasticsearch.hosts:http://host1:9200",
+ "zipkin.storage.elasticsearch.username:somename",
+ "zipkin.storage.elasticsearch.password:pass")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(context.getBean(OkHttpClient::class.java).networkInterceptors())
+ .extracting<String, RuntimeException> { i -> i.javaClass.name }
+ .contains("zipkin2.server.internal.elasticsearch.BasicAuthInterceptor")
+ }
+
+ @Test fun searchEnabled_false() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.search-enabled:false")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es().searchEnabled()).isFalse()
+ }
+
+ @Test fun autocompleteKeys_list() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.autocomplete-keys:environment")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es().autocompleteKeys())
+ .containsOnly("environment")
+ }
+
+ @Test fun autocompleteTtl() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.autocomplete-ttl:60000")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es().autocompleteTtl())
+ .isEqualTo(60000)
+ }
+
+ @Test fun autocompleteCardinality() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:elasticsearch",
+ "zipkin.storage.autocomplete-cardinality:5000")
+ .applyTo(context)
+ Access.registerElasticsearchHttp(context)
+ context.refresh()
+
+ assertThat(es().autocompleteCardinality())
+ .isEqualTo(5000)
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/Http.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/Http.kt
new file mode 100644
index 0000000..e4aa395
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/Http.kt
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal
+
+import com.linecorp.armeria.common.SessionProtocol
+import com.linecorp.armeria.server.Server
+import okhttp3.Headers
+import okhttp3.MediaType
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.RequestBody
+import okhttp3.Response
+import zipkin2.TestObjects.UTF_8
+
+object Http {
+ var client: OkHttpClient = OkHttpClient.Builder().followRedirects(false).build()
+
+ fun get(server: Server, path: String, headers: Headers = Headers.of()): Response =
+ client.newCall(Request.Builder().url(url(server, path)).headers(headers).build()).execute()
+
+ fun getAsString(server: Server, path: String, headers: Headers = Headers.of()): String =
+ get(server, path, headers).body()!!.string()
+
+ fun post(
+ server: Server,
+ path: String,
+ contentType: String? = "application/json",
+ body: String,
+ headers: Headers = Headers.of()
+ ) = post(server, path, contentType, body.toByteArray(UTF_8), headers)
+
+ fun post(
+ server: Server,
+ path: String,
+ contentType: String? = "application/json",
+ body: ByteArray,
+ headers: Headers = Headers.of()
+ ): Response {
+ val body =
+ RequestBody.create(if (contentType != null) MediaType.parse(contentType) else null, body)
+ val result = client.newCall(
+ Request.Builder().url(url(server, path)).headers(headers).post(body).build()).execute()
+ return result;
+ }
+
+ fun url(server: Server, path: String, protocol: SessionProtocol = SessionProtocol.HTTP): String {
+ return server.activePorts().values.stream()
+ .filter { p -> p.hasProtocol(protocol) }.findAny()
+ .map { p -> protocol.uriText() + "://127.0.0.1:" + p.localAddress().port + path }
+ .orElseThrow { AssertionError("$protocol port not open") }
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinGrpcCollector.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinGrpcCollector.kt
index 269f982..1f17b67 100644
--- a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinGrpcCollector.kt
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinGrpcCollector.kt
@@ -33,7 +33,7 @@ import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit4.SpringRunner
import zipkin.server.ZipkinServer
import zipkin2.Span
-import zipkin2.TestObjects
+import zipkin2.TestObjects.TRACE
import zipkin2.codec.SpanBytesDecoder
import zipkin2.codec.SpanBytesEncoder
import zipkin2.proto3.ListOfSpans
@@ -41,17 +41,20 @@ import zipkin2.proto3.ReportResponse
import zipkin2.storage.InMemoryStorage
/** This tests that we accept messages constructed by other clients. */
-@SpringBootTest(classes = [ZipkinServer::class],
+@SpringBootTest(
+ classes = [ZipkinServer::class],
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
- properties = ["spring.config.name=zipkin-server", "zipkin.collector.grpc.enabled=true"])
+ properties = ["spring.config.name=zipkin-server", "zipkin.collector.grpc.enabled=true"]
+)
@RunWith(SpringRunner::class)
// Written in Kotlin as Square Wire's grpc client is Kotlin.
// Also, the first author of this test wanted an excuse to write Kotlin.
class ITZipkinGrpcCollector {
- @Autowired lateinit var storage: InMemoryStorage
@Autowired lateinit var server: Server
+ @Autowired lateinit var storage: InMemoryStorage
+ @Before fun clearStorage() = storage.clear()
- var request = ListOfSpans.ADAPTER.decode(SpanBytesEncoder.PROTO3.encodeList(TestObjects.TRACE))
+ val request: ListOfSpans = ListOfSpans.ADAPTER.decode(SpanBytesEncoder.PROTO3.encodeList(TRACE))
lateinit var spanService: SpanService
interface SpanService : Service {
@@ -65,7 +68,7 @@ class ITZipkinGrpcCollector {
@Before fun sanityCheckCodecCompatible() {
assertThat(SpanBytesDecoder.PROTO3.decodeList(request.encode()))
- .containsExactlyElementsOf(TestObjects.TRACE)
+ .containsExactlyElementsOf(TRACE)
}
@Before fun createClient() {
@@ -80,7 +83,7 @@ class ITZipkinGrpcCollector {
spanService.Report(request) // Result is effectively void
}
assertThat<List<Span>>(storage.traces)
- .containsExactly(TestObjects.TRACE)
+ .containsExactly(TRACE)
}
@Test fun report_emptyIsOk() {
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinHttpCollector.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinHttpCollector.kt
index 9a0a215..b8e10b4 100644
--- a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinHttpCollector.kt
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinHttpCollector.kt
@@ -17,10 +17,7 @@
package zipkin2.server.internal
import com.linecorp.armeria.server.Server
-import okhttp3.MediaType
-import okhttp3.OkHttpClient
-import okhttp3.Request
-import okhttp3.RequestBody
+import okhttp3.Headers
import okhttp3.Response
import okio.Buffer
import okio.GzipSink
@@ -33,83 +30,71 @@ import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit4.SpringRunner
import zipkin.server.ZipkinServer
-import zipkin2.Span
import zipkin2.TestObjects.TRACE
import zipkin2.codec.SpanBytesEncoder
import zipkin2.storage.InMemoryStorage
-import java.io.IOException
-import java.util.Arrays.asList
-@SpringBootTest(classes = [ZipkinServer::class],
+@SpringBootTest(
+ classes = [ZipkinServer::class],
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
- properties = ["spring.config.name=zipkin-server"])
+ properties = ["spring.config.name=zipkin-server"]
+)
@RunWith(SpringRunner::class)
class ITZipkinHttpCollector {
- @Autowired lateinit var storage: InMemoryStorage
@Autowired lateinit var server: Server
+ @Autowired lateinit var storage: InMemoryStorage
+ @Before fun clearStorage() = storage.clear()
- var client = OkHttpClient.Builder().followRedirects(true).build()
-
- @Before fun init() {
- storage.clear()
- }
-
- @Test @Throws(IOException::class)
- fun noContentTypeIsJsonV2() {
- val response = post("/api/v2/spans", SpanBytesEncoder.JSON_V2.encodeList(TRACE))
+ @Test fun noContentTypeIsJsonV2() {
+ val response = Http.post(server, "/api/v2/spans", null,
+ SpanBytesEncoder.JSON_V2.encodeList(TRACE)
+ )
assertThat(response.code())
.isEqualTo(202)
- assertThat(storage.traces).containsExactly(TRACE);
+ assertThat(storage.traces).containsExactly(TRACE)
}
- @Test @Throws(IOException::class)
- fun jsonV2() {
- val body = SpanBytesEncoder.JSON_V2.encodeList(TRACE);
- val response = client.newCall(Request.Builder()
- .url(url(server, "/api/v2/spans"))
- .post(RequestBody.create(MediaType.parse("application/json"), body))
- .build()).execute()
+ @Test fun jsonV2() {
+ val response = Http.post(server, "/api/v2/spans", "application/json",
+ SpanBytesEncoder.JSON_V2.encodeList(TRACE)
+ )
assertThat(response.code())
.isEqualTo(202)
- assertThat(storage.traces).containsExactly(TRACE);
+ assertThat(storage.traces).containsExactly(TRACE)
}
- @Test @Throws(IOException::class)
- fun jsonV2_accidentallySentV1Format() {
- val message = SpanBytesEncoder.JSON_V1.encodeList(TRACE)
+ @Test fun jsonV2_accidentallySentV1Format() {
+ val response = Http.post(server, "/api/v2/spans", "application/json",
+ SpanBytesEncoder.JSON_V1.encodeList(TRACE)
+ )
- val response = post("/api/v2/spans", message)
assertThat(response.code()).isEqualTo(400)
assertThat(response.body()!!.string())
.startsWith("Expected a JSON_V2 encoded list, but received: JSON_V1\n")
}
- @Test @Throws(IOException::class)
- fun jsonV1_accidentallySentV2Format() {
- val message = SpanBytesEncoder.JSON_V2.encodeList(TRACE)
+ @Test fun jsonV1_accidentallySentV2Format() {
+ val response = Http.post(server, "/api/v1/spans", "application/json",
+ SpanBytesEncoder.JSON_V2.encodeList(TRACE)
+ )
- val response = post("/api/v1/spans", message)
assertThat(response.code()).isEqualTo(400)
assertThat(response.body()!!.string())
.startsWith("Expected a JSON_V1 encoded list, but received: JSON_V2\n")
}
- @Test @Throws(IOException::class)
- fun ambiguousFormatOk() {
- val message = SpanBytesEncoder.JSON_V2.encodeList(asList(
- Span.newBuilder().traceId("1").id("1").name("test").build()
- ))
+ @Test fun ambiguousFormatOk() {
+ val body = """[{"traceId": "1", "id": "1", "name": "test"}]"""
- assertThat(post("/api/v1/spans", message).code()).isEqualTo(202)
- assertThat(post("/api/v2/spans", message).code()).isEqualTo(202)
+ assertThat(Http.post(server, "/api/v1/spans", null, body).code()).isEqualTo(202)
+ assertThat(Http.post(server, "/api/v2/spans", null, body).code()).isEqualTo(202)
}
- @Test @Throws(IOException::class)
- fun emptyIsOk() {
+ @Test fun emptyIsOk() {
assertOnAllEndpoints(byteArrayOf()) { response: Response,
path: String, contentType: String, encoding: String ->
assertThat(response.isSuccessful)
@@ -118,8 +103,7 @@ class ITZipkinHttpCollector {
}
}
- @Test @Throws(IOException::class)
- fun malformedNotOk() {
+ @Test fun malformedNotOk() {
assertOnAllEndpoints(byteArrayOf(1, 2, 3, 4)) { response: Response,
path: String, contentType: String, encoding: String ->
assertThat(response.code()).isEqualTo(400)
@@ -148,56 +132,40 @@ class ITZipkinHttpCollector {
).forEach {
val (path, contentType) = it
for (encoding in listOf("identity", "gzip")) {
- val response = client.newCall(Request.Builder()
- .url(url(server, path))
- .header("Content-Encoding", encoding)
- .post(RequestBody.create(MediaType.get(contentType), body))
- .build()).execute()
+ val response =
+ Http.post(server, path, contentType, body, Headers.of("Content-Encoding", encoding))
assertion(response, path, contentType, encoding)
}
}
}
- @Test @Throws(IOException::class)
- fun contentTypeXThrift() {
- val message = SpanBytesEncoder.THRIFT.encodeList(TRACE)
-
- val response = client.newCall(Request.Builder()
- .url(url(server, "/api/v1/spans"))
- .post(RequestBody.create(MediaType.parse("application/x-thrift"), message))
- .build()).execute()
+ @Test fun contentTypeXThrift() {
+ val response = Http.post(server, "/api/v1/spans", "application/x-thrift",
+ SpanBytesEncoder.THRIFT.encodeList(TRACE)
+ )
assertThat(response.code())
- .withFailMessage(response.body()!!.string())
.isEqualTo(202)
}
- @Test @Throws(IOException::class)
- fun contentTypeXProtobuf() {
- val message = SpanBytesEncoder.PROTO3.encodeList(TRACE)
-
- val response = client.newCall(Request.Builder()
- .url(url(server, "/api/v2/spans"))
- .post(RequestBody.create(MediaType.parse("application/x-protobuf"), message))
- .build()).execute()
+ @Test fun contentTypeXProtobuf() {
+ val response = Http.post(server, "/api/v2/spans", "application/x-protobuf",
+ SpanBytesEncoder.PROTO3.encodeList(TRACE)
+ )
assertThat(response.code())
.isEqualTo(202)
}
- @Test @Throws(IOException::class)
- fun gzipEncoded() {
- val message = SpanBytesEncoder.JSON_V2.encodeList(TRACE)
- val gzippedBody = gzip(message)
-
- val response = client.newCall(Request.Builder()
- .url(url(server, "/api/v2/spans"))
- .header("Content-Encoding", "gzip")
- .post(RequestBody.create(null, gzippedBody))
- .build()).execute()
+ @Test fun gzipEncoded() {
+ val response = Http.post(server, "/api/v2/spans", null,
+ gzip(SpanBytesEncoder.JSON_V2.encodeList(TRACE)),
+ Headers.of("Content-Encoding", "gzip")
+ )
- assertThat(response.isSuccessful)
+ assertThat(response.code())
+ .isEqualTo(202)
}
fun gzip(message: ByteArray): ByteArray {
@@ -205,26 +173,6 @@ class ITZipkinHttpCollector {
val gzipSink = GzipSink(sink)
gzipSink.write(Buffer().write(message), message.size.toLong())
gzipSink.close()
- val gzippedBody = sink.readByteArray()
- return gzippedBody
- }
-
- @Throws(IOException::class)
- fun get(path: String): Response {
- return client.newCall(Request.Builder()
- .url(url(server, path))
- .build()).execute()
- }
-
- @Throws(IOException::class)
- fun post(path: String, body: ByteArray): Response {
- return client.newCall(Request.Builder()
- .url(url(server, path))
- .post(RequestBody.create(null, body))
- .build()).execute()
- }
-
- fun url(server: Server, path: String): String {
- return "http://localhost:" + server.activePort().get().localAddress().port + path
+ return sink.readByteArray()
}
}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinMetricsHealth.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinMetricsHealth.kt
new file mode 100644
index 0000000..fcd4dc1
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinMetricsHealth.kt
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.jayway.jsonpath.JsonPath
+import com.linecorp.armeria.server.Server
+import io.micrometer.prometheus.PrometheusMeterRegistry
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.junit4.SpringRunner
+import zipkin.server.ZipkinServer
+import zipkin2.TestObjects.LOTS_OF_SPANS
+import zipkin2.TestObjects.UTF_8
+import zipkin2.codec.SpanBytesEncoder
+import java.util.ArrayList
+
+@SpringBootTest(
+ classes = [ZipkinServer::class],
+ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+ properties = ["spring.config.name=zipkin-server"]
+)
+@RunWith(SpringRunner::class)
+class ITZipkinMetricsHealth {
+ @Autowired lateinit var server: Server
+ @Autowired lateinit var registry: PrometheusMeterRegistry
+
+ @Test fun healthIsOK() {
+ assertThat(Http.get(server, "/health").isSuccessful)
+ .isTrue()
+
+ // ensure we don't track health in prometheus
+ assertThat(scrape())
+ .doesNotContain("health")
+ }
+
+ @Test fun metricsIsOK() {
+ assertThat(Http.get(server, "/metrics").isSuccessful)
+ .isTrue()
+
+ // ensure we don't track metrics in prometheus
+ assertThat(scrape())
+ .doesNotContain("metrics")
+ }
+
+ @Test fun actuatorIsOK() {
+ assertThat(Http.get(server, "/actuator").isSuccessful)
+ .isTrue()
+
+ // ensure we don't track actuator in prometheus
+ assertThat(scrape())
+ .doesNotContain("actuator")
+ }
+
+ @Test fun prometheusIsOK() {
+ val response = Http.get(server, "/prometheus")
+ assertThat(response.code()).isEqualTo(307)
+ assertThat(response.header("location")).isEqualTo("/actuator/prometheus")
+
+ assertThat(Http.get(server, "/actuator/prometheus").isSuccessful)
+ .isTrue()
+
+ // ensure we don't track prometheus, UI requests in prometheus
+ assertThat(scrape())
+ .doesNotContain("prometheus")
+ .doesNotContain("uri=\"/zipkin")
+ .doesNotContain("uri=\"/\"")
+ }
+
+ @Test fun notFound_prometheus() {
+ assertThat(Http.get(server, "/doo-wop").isSuccessful)
+ .isFalse()
+
+ assertThat(scrape())
+ .contains("uri=\"NOT_FOUND\"")
+ .doesNotContain("uri=\"/doo-wop")
+ }
+
+ @Test fun redirected_prometheus() {
+ assertThat(Http.get(server, "/").code())
+ .isEqualTo(302) // redirect
+
+ assertThat(scrape())
+ .contains("uri=\"REDIRECTION\"")
+ .doesNotContain("uri=\"/\"")
+ }
+
+ @Test fun apiTemplate_prometheus() {
+ val spans = listOf(LOTS_OF_SPANS[0])
+ val body = SpanBytesEncoder.JSON_V2.encodeList(spans)
+ assertThat(Http.post(server, "/api/v2/spans", body = body).isSuccessful)
+ .isTrue()
+
+ assertThat(Http.get(server, "/api/v2/trace/" + LOTS_OF_SPANS[0].traceId()).isSuccessful)
+ .isTrue()
+
+ assertThat(scrape())
+ .contains("uri=\"/api/v2/trace/{traceId}\"")
+ .doesNotContain(LOTS_OF_SPANS[0].traceId())
+ }
+
+ @Test fun forwardedRoute_prometheus() {
+ assertThat(Http.get(server, "/zipkin/api/v2/services").isSuccessful)
+ .isTrue()
+
+ assertThat(scrape())
+ .contains("uri=\"/api/v2/services\"")
+ .doesNotContain("uri=\"/zipkin/api/v2/services\"")
+ }
+
+ internal fun scrape(): String {
+ Thread.sleep(100)
+ return registry.scrape()
+ }
+
+ /** Makes sure the prometheus filter doesn't count twice */
+ @Test fun writeSpans_updatesPrometheusMetrics() {
+ val spans = listOf(LOTS_OF_SPANS[0], LOTS_OF_SPANS[1], LOTS_OF_SPANS[2])
+ val body = SpanBytesEncoder.JSON_V2.encodeList(spans)
+
+ Http.post(server, "/api/v2/spans", body = body)
+ Http.post(server, "/api/v2/spans", body = body)
+
+ Thread.sleep(100) // sometimes travis flakes getting the "http.server.requests" timer
+ val messagesCount = registry.counter("zipkin_collector.spans", "transport", "http").count()
+ // Get the http count from the registry and it should match the summation previous count
+ // and count of calls below
+ val httpCount = registry
+ .find("http.server.requests")
+ .tag("uri", "/api/v2/spans")
+ .timer()!!
+ .count()
+
+ // ensure unscoped counter does not exist
+ assertThat(scrape())
+ .doesNotContain("zipkin_collector_spans_total $messagesCount")
+ .contains("zipkin_collector_spans_total{transport=\"http\",} $messagesCount")
+ .contains(
+ "http_server_requests_seconds_count{method=\"POST\",status=\"202\",uri=\"/api/v2/spans\",} $httpCount")
+ }
+
+ @Test fun readsHealth() {
+ val json = Http.getAsString(server, "/health")
+ assertThat(readString(json, "$.status"))
+ .isIn("UP", "DOWN", "UNKNOWN")
+ assertThat(readString(json, "$.zipkin.status"))
+ .isIn("UP", "DOWN", "UNKNOWN")
+ }
+
+ @Test fun writesSpans_readMetricsFormat() {
+ val span = "zipkin".toByteArray(UTF_8)
+ val spans = listOf(LOTS_OF_SPANS[0], LOTS_OF_SPANS[1], LOTS_OF_SPANS[2])
+ val body = SpanBytesEncoder.JSON_V2.encodeList(spans)
+ Http.post(server, "/api/v2/spans", body = body)
+ Http.post(server, "/api/v2/spans", body = body)
+ Http.post(server, "/api/v2/spans", body = span)
+ Thread.sleep(1500)
+
+ assertThat(readJson(Http.getAsString(server, "/metrics")))
+ .containsExactlyInAnyOrder(
+ "gauge.zipkin_collector.message_spans.http",
+ "gauge.zipkin_collector.message_bytes.http", "counter.zipkin_collector.messages.http",
+ "counter.zipkin_collector.bytes.http", "counter.zipkin_collector.spans.http",
+ "counter.zipkin_collector.messages_dropped.http",
+ "counter.zipkin_collector.spans_dropped.http"
+ )
+ }
+
+ fun readString(json: String, jsonPath: String): String = JsonPath.compile(jsonPath).read(json)
+
+ fun readJson(json: String): List<*> {
+ val mapper = ObjectMapper()
+ val jsonNode = mapper.readTree(json)
+ val fieldsList = ArrayList<String>()
+ jsonNode.fieldNames().forEachRemaining { fieldsList.add(it) }
+ return fieldsList
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinMetricsHealthDirty.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinMetricsHealthDirty.kt
new file mode 100644
index 0000000..8cbfad9
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinMetricsHealthDirty.kt
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal
+
+import com.jayway.jsonpath.JsonPath
+import com.linecorp.armeria.server.Server
+import io.micrometer.prometheus.PrometheusMeterRegistry
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.annotation.DirtiesContext
+import org.springframework.test.annotation.DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD
+import org.springframework.test.context.junit4.SpringRunner
+import zipkin.server.ZipkinServer
+import zipkin2.TestObjects.LOTS_OF_SPANS
+import zipkin2.codec.SpanBytesEncoder
+
+/**
+ * We cannot clear the micrometer registry easily, so we have recreate the spring context. This is
+ * extremely slow, so please only add tests that require isolation here.
+ */
+@SpringBootTest(
+ classes = [ZipkinServer::class],
+ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+ properties = ["spring.config.name=zipkin-server"]
+)
+@RunWith(SpringRunner::class)
+@DirtiesContext(classMode = BEFORE_EACH_TEST_METHOD)
+class ITZipkinMetricsHealthDirty {
+ @Autowired lateinit var server: Server
+ @Autowired lateinit var registry: PrometheusMeterRegistry
+
+ @Test fun writeSpans_updatesMetrics() {
+ val spans = listOf(LOTS_OF_SPANS[0], LOTS_OF_SPANS[1], LOTS_OF_SPANS[2])
+ val body = SpanBytesEncoder.JSON_V2.encodeList(spans)
+ val messagesCount = registry.counter("zipkin_collector.messages", "transport", "http").count()
+ val bytesCount = registry.counter("zipkin_collector.bytes", "transport", "http").count()
+ val spansCount = registry.counter("zipkin_collector.spans", "transport", "http").count()
+ Http.post(server, "/api/v2/spans", body = body)
+ Http.post(server, "/api/v2/spans", body = body)
+
+ val json = Http.getAsString(server, "/metrics")
+
+ assertThat(readDouble(json, "$.['counter.zipkin_collector.messages.http']"))
+ .isEqualTo(messagesCount + 2.0)
+ assertThat(readDouble(json, "$.['counter.zipkin_collector.bytes.http']"))
+ .isEqualTo(bytesCount + body.size * 2)
+ assertThat(readDouble(json, "$.['gauge.zipkin_collector.message_bytes.http']"))
+ .isEqualTo(body.size.toDouble())
+ assertThat(readDouble(json, "$.['counter.zipkin_collector.spans.http']"))
+ .isEqualTo(spansCount + spans.size * 2)
+ assertThat(readDouble(json, "$.['gauge.zipkin_collector.message_spans.http']"))
+ .isEqualTo(spans.size.toDouble())
+ }
+
+ @Test fun writeSpans_malformedUpdatesMetrics() {
+ val body = byteArrayOf('h'.toByte(), 'e'.toByte(), 'l'.toByte(), 'l'.toByte(), 'o'.toByte())
+ val messagesCount = registry.counter("zipkin_collector.messages", "transport", "http").count()
+ val messagesDroppedCount =
+ registry.counter("zipkin_collector.messages_dropped", "transport", "http").count()
+ Http.post(server, "/api/v2/spans", body = body)
+
+ val json = Http.getAsString(server, "/metrics")
+
+ assertThat(readDouble(json, "$.['counter.zipkin_collector.messages.http']"))
+ .isEqualTo(messagesCount + 1)
+ assertThat(readDouble(json, "$.['counter.zipkin_collector.messages_dropped.http']"))
+ .isEqualTo(messagesDroppedCount + 1)
+ }
+
+ fun readDouble(json: String, jsonPath: String): Double = JsonPath.compile(jsonPath).read(json)
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServer.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServer.kt
new file mode 100644
index 0000000..8612890
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServer.kt
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal
+
+import com.linecorp.armeria.server.Server
+import okhttp3.Headers
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.junit4.SpringRunner
+import zipkin.server.ZipkinServer
+import zipkin2.Endpoint
+import zipkin2.Span
+import zipkin2.TestObjects.TODAY
+import zipkin2.TestObjects.TRACE
+import zipkin2.TestObjects.UTF_8
+import zipkin2.codec.SpanBytesEncoder
+import zipkin2.storage.InMemoryStorage
+
+@SpringBootTest(
+ classes = [ZipkinServer::class],
+ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+ properties = ["spring.config.name=zipkin-server"]
+)
+@RunWith(SpringRunner::class)
+class ITZipkinServer {
+ @Autowired lateinit var server: Server
+ @Autowired lateinit var storage: InMemoryStorage
+ @Before fun clearStorage() = storage.clear()
+
+ @Test fun getTrace() {
+ storage.accept(TRACE).execute()
+
+ val response = Http.get(server, "/api/v2/trace/" + TRACE[0].traceId())
+ assertThat(response.isSuccessful).isTrue()
+
+ assertThat(response.body()!!.bytes())
+ .containsExactly(*SpanBytesEncoder.JSON_V2.encodeList(TRACE))
+ }
+
+ @Test fun tracesQueryRequiresNoParameters() {
+ storage.accept(TRACE).execute()
+
+ val response = Http.get(server, "/api/v2/traces")
+ assertThat(response.isSuccessful).isTrue()
+ assertThat(response.body()!!.string())
+ .isEqualTo("[" + String(SpanBytesEncoder.JSON_V2.encodeList(TRACE), UTF_8) + "]")
+ }
+
+ @Test fun v2WiresUp() {
+ assertThat(Http.get(server, "/api/v2/services").isSuccessful)
+ .isTrue()
+ }
+
+ @Test fun doesntSetCacheControlOnNameEndpointsWhenLessThan4Services() {
+ storage.accept(TRACE).execute()
+
+ assertThat(Http.get(server, "/api/v2/services").header("Cache-Control"))
+ .isNull()
+
+ assertThat(Http.get(server, "/api/v2/spans?serviceName=web").header("Cache-Control"))
+ .isNull()
+
+ assertThat(Http.get(server, "/api/v2/remoteServices?serviceName=web").header("Cache-Control"))
+ .isNull()
+ }
+
+ @Test fun spanNameQueryWorksWithNonAsciiServiceName() {
+ assertThat(Http.get(server, "/api/v2/spans?serviceName=个人信息服务").code())
+ .isEqualTo(200)
+ }
+
+ @Test fun remoteServiceNameQueryWorksWithNonAsciiServiceName() {
+ assertThat(Http.get(server, "/api/v2/remoteServices?serviceName=个人信息服务").code())
+ .isEqualTo(200)
+ }
+
+ @Test fun setsCacheControlOnNameEndpointsWhenMoreThan3Services() {
+ val services = listOf("foo", "bar", "baz", "quz")
+ for (i in services.indices) {
+ storage.accept(listOf(
+ Span.newBuilder().traceId("a").id((i + 1).toLong()).timestamp(TODAY).name("whopper")
+ .localEndpoint(Endpoint.newBuilder().serviceName(services[i]).build())
+ .remoteEndpoint(Endpoint.newBuilder().serviceName(services[i] + 1).build())
+ .build()
+ )).execute()
+ }
+
+ assertThat(Http.get(server, "/api/v2/services").header("Cache-Control"))
+ .isEqualTo("max-age=300, must-revalidate")
+
+ assertThat(Http.get(server, "/api/v2/spans?serviceName=web").header("Cache-Control"))
+ .isEqualTo("max-age=300, must-revalidate")
+
+ assertThat(Http.get(server, "/api/v2/remoteServices?serviceName=web").header("Cache-Control"))
+ .isEqualTo("max-age=300, must-revalidate")
+
+ // Check that the response is alphabetically sorted.
+ assertThat(Http.getAsString(server, "/api/v2/services"))
+ .isEqualTo("[\"bar\",\"baz\",\"foo\",\"quz\"]")
+ }
+
+ @Test fun shouldAllowAnyOriginByDefault() {
+ val response = Http.get(server, "/api/v2/traces", Headers.of(
+ "Origin", "http://foo.example.com"
+ ))
+
+ assertThat(response.isSuccessful).isTrue()
+ assertThat(response.header("vary")).isNull()
+ assertThat(response.header("access-control-allow-credentials")).isNull()
+ assertThat(response.header("access-control-allow-origin")).contains("*")
+ }
+
+ @Test fun forwardsApiForUi() {
+ assertThat(Http.get(server, "/zipkin/api/v2/traces").isSuccessful).isTrue()
+ assertThat(Http.get(server, "/zipkin/api/v2/traces").isSuccessful).isTrue()
+ }
+
+ /** Simulate a proxy which forwards / to zipkin as opposed to resolving / -> /zipkin first */
+ @Test fun redirectedHeaderUsesOriginalHostAndPort() {
+ val response = Http.get(server, "/", Headers.of(
+ "Host", "zipkin.com",
+ "X-Forwarded-Proto", "https",
+ "X-Forwarded-Port", "444"
+ ))
+
+ // Redirect header should be the proxy, not the backed IP/port
+ assertThat(response.header("Location"))
+ .isEqualTo("/zipkin/")
+ }
+
+ @Test fun infoEndpointIsAvailable() {
+ val response = Http.get(server, "/info")
+ assertThat(response.code()).isEqualTo(307)
+ assertThat(response.header("location")).isEqualTo("/actuator/info")
+
+ assertThat(Http.get(server, "/actuator/info").isSuccessful).isTrue()
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServerAutocomplete.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServerAutocomplete.kt
new file mode 100644
index 0000000..4e04983
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServerAutocomplete.kt
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal
+
+import com.linecorp.armeria.server.Server
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.junit4.SpringRunner
+import zipkin.server.ZipkinServer
+import zipkin2.Span
+import zipkin2.TestObjects.TODAY
+import zipkin2.codec.SpanBytesEncoder
+
+/**
+ * Integration test suite for autocomplete tags.
+ *
+ * Verifies that the whitelist of key can be configured via "zipkin.storage.autocomplete-keys".
+ */
+@SpringBootTest(
+ classes = [ZipkinServer::class],
+ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+ properties = [
+ "spring.config.name=zipkin-server",
+ "zipkin.storage.autocomplete-keys=environment,clnt/finagle.version"
+ ]
+)
+@RunWith(SpringRunner::class)
+class ITZipkinServerAutocomplete {
+ @Autowired lateinit var server: Server
+ val values = "/api/v2/autocompleteValues"
+
+ @Test fun setsCacheControlOnAutocompleteKeysEndpoint() {
+ assertThat(Http.get(server, "/api/v2/autocompleteKeys").header("Cache-Control"))
+ .isEqualTo("max-age=300, must-revalidate")
+ }
+
+ @Test fun setsCacheControlOnAutocompleteEndpointWhenMoreThan3Values() {
+ assertThat(Http.get(server, "$values?key=environment").header("Cache-Control"))
+ .isNull()
+ assertThat(Http.get(server, "$values?key=clnt/finagle.version").header("Cache-Control"))
+ .isNull()
+
+ for (i in 0..3) {
+ Http.post(server, "/api/v2/spans", body = SpanBytesEncoder.JSON_V2.encodeList(listOf(
+ Span.newBuilder().traceId("a").id((i + 1).toLong()).timestamp(TODAY).name("whopper")
+ .putTag("clnt/finagle.version", "6.45.$i").build()
+ )))
+ }
+
+ assertThat(Http.get(server, "$values?key=environment").header("Cache-Control"))
+ .isNull()
+ assertThat(Http.get(server, "$values?key=clnt/finagle.version").header("Cache-Control"))
+ .isEqualTo("max-age=300, must-revalidate")
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServerCORS.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServerCORS.kt
new file mode 100644
index 0000000..e2d4485
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServerCORS.kt
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal
+
+import com.linecorp.armeria.server.Server
+import okhttp3.Headers
+import okhttp3.Request
+import okhttp3.Response
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.beans.factory.annotation.Value
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.junit4.SpringRunner
+import zipkin.server.ZipkinServer
+
+/**
+ * Integration test suite for CORS configuration.
+ *
+ * Verifies that allowed-origins can be configured via properties (zipkin.query.allowed-origins).
+ */
+@SpringBootTest(classes = [ZipkinServer::class],
+ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+ properties = [
+ "spring.config.name=zipkin-server",
+ "zipkin.query.allowed-origins=http://foo.example.com"
+ ])
+@RunWith(SpringRunner::class)
+class ITZipkinServerCORS {
+ @Autowired lateinit var server: Server
+ @Autowired @Value("\${zipkin.query.allowed-origins}")
+ lateinit var allowedOrigin: String
+ internal val disallowedOrigin = "http://bar.example.com"
+
+ /** Notably, javascript makes pre-flight requests, and won't POST spans if disallowed! */
+ @Test fun shouldAllowConfiguredOrigin_preflight() {
+ shouldPermitPreflight(optionsForOrigin("GET", "/api/v2/traces", allowedOrigin))
+ shouldPermitPreflight(optionsForOrigin("POST", "/api/v2/spans", allowedOrigin))
+ }
+
+ @Test fun shouldAllowConfiguredOrigin() {
+ shouldAllowConfiguredOrigin(getTracesFromOrigin(allowedOrigin))
+ shouldAllowConfiguredOrigin(postSpansFromOrigin(allowedOrigin))
+ }
+
+ @Test fun shouldDisallowOrigin() {
+ shouldDisallowOrigin(getTracesFromOrigin(disallowedOrigin))
+ shouldDisallowOrigin(postSpansFromOrigin(disallowedOrigin))
+ }
+
+ fun optionsForOrigin(method: String, path: String, origin: String): Response =
+ Http.client.newCall(Request.Builder().url(Http.url(server, path)).headers(Headers.of(
+ "Origin", origin,
+ "access-control-request-method", method,
+ "access-control-request-headers", "content-type"))
+ .method("OPTIONS", null)
+ .build()).execute()
+
+ fun getTracesFromOrigin(origin: String): Response =
+ Http.get(server, "/api/v2/traces", Headers.of("Origin", origin))
+
+ fun postSpansFromOrigin(origin: String): Response =
+ Http.post(server, "/api/v2/traces", null, "[]", Headers.of("Origin", origin))
+
+ fun shouldPermitPreflight(response: Response) {
+ assertThat(response.isSuccessful)
+ .withFailMessage(response.toString())
+ .isTrue()
+ assertThat(response.header("vary")).contains("origin")
+ assertThat(response.header("access-control-allow-origin")).contains(allowedOrigin)
+ assertThat(response.header("access-control-allow-methods"))
+ .contains(response.request().header("access-control-request-method"))
+ assertThat(response.header("access-control-allow-credentials")).isNull()
+ assertThat(response.header("access-control-allow-headers")).contains("content-type")
+ }
+
+ fun shouldAllowConfiguredOrigin(response: Response) {
+ assertThat(response.header("vary")).contains("origin")
+ assertThat(response.header("access-control-allow-origin"))
+ .contains(response.request().header("origin"))
+ assertThat(response.header("access-control-allow-credentials")).isNull()
+ assertThat(response.header("access-control-allow-headers")).contains("content-type")
+ }
+
+ fun shouldDisallowOrigin(response: Response) {
+ assertThat(response.header("vary")).isNull() // TODO: We used to set vary: origin
+ assertThat(response.header("access-control-allow-credentials")).isNull()
+ assertThat(response.header("access-control-allow-origin")).isNull()
+ assertThat(response.header("access-control-allow-headers")).isNull()
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServerHttpCollectorDisabled.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServerHttpCollectorDisabled.kt
new file mode 100644
index 0000000..f355af9
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServerHttpCollectorDisabled.kt
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal
+
+import com.linecorp.armeria.server.Server
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.junit4.SpringRunner
+import zipkin.server.ZipkinServer
+
+/**
+ * Query-only builds should be able to disable the HTTP collector, so that associated assets 404
+ * instead of allowing creation of spans.
+ */
+@SpringBootTest(
+ classes = [ZipkinServer::class],
+ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+ properties = ["spring.config.name=zipkin-server", "zipkin.collector.http.enabled=false"]
+)
+@RunWith(SpringRunner::class)
+class ITZipkinServerHttpCollectorDisabled {
+ @Autowired lateinit var server: Server
+
+ @Test fun httpCollectorEndpointReturns404() {
+ val response = Http.post(server, "/api/v2/spans", body = "[]")
+
+ assertThat(response.code()).isEqualTo(404)
+ }
+
+ /** Shows the same http path still works for GET */
+ @Test fun getOnSpansEndpointReturnsOK() {
+ val response = Http.get(server, "/api/v2/spans?serviceName=unknown")
+
+ assertThat(response.isSuccessful).isTrue()
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServerQueryDisabled.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServerQueryDisabled.kt
new file mode 100644
index 0000000..97a5831
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServerQueryDisabled.kt
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal
+
+import com.linecorp.armeria.server.Server
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.junit4.SpringRunner
+import zipkin.server.ZipkinServer
+
+/**
+ * Collector-only builds should be able to disable the query (and indirectly the UI), so that
+ * associated assets 404 vs throw exceptions.
+ */
+@SpringBootTest(
+ classes = [ZipkinServer::class],
+ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+ properties = [
+ "spring.config.name=zipkin-server",
+ "zipkin.query.enabled=false",
+ "zipkin.ui.enabled=false"
+ ]
+)
+@RunWith(SpringRunner::class)
+class ITZipkinServerQueryDisabled {
+ @Autowired lateinit var server: Server
+
+ @Test fun queryRelatedEndpoints404() {
+ assertThat(Http.get(server, "/api/v2/traces").code()).isEqualTo(404)
+ assertThat(Http.get(server, "/index.html").code()).isEqualTo(404)
+
+ // but other endpoints are ok
+ assertThat(Http.get(server, "/health").isSuccessful).isTrue()
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServerSsl.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServerSsl.kt
new file mode 100644
index 0000000..76cb0f8
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ITZipkinServerSsl.kt
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal
+
+import com.linecorp.armeria.client.ClientFactoryBuilder
+import com.linecorp.armeria.client.HttpClient
+import com.linecorp.armeria.common.HttpStatus
+import com.linecorp.armeria.common.SessionProtocol
+import com.linecorp.armeria.server.Server
+import io.netty.handler.ssl.util.InsecureTrustManagerFactory
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.junit4.SpringRunner
+import zipkin.server.ZipkinServer
+
+/**
+ * This code ensures you can setup SSL.
+ *
+ *
+ * This is inspired by com.linecorp.armeria.spring.ArmeriaSslConfigurationTest
+ */
+@SpringBootTest(
+ classes = [ZipkinServer::class],
+ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+ properties = [
+ "spring.config.name=zipkin-server",
+ "armeria.ssl.enabled=true",
+ "armeria.ports[1].port=0",
+ "armeria.ports[1].protocols[0]=https",
+ // redundant in zipkin-server-shared https://github.com/spring-projects/spring-boot/issues/16394
+ "armeria.ports[0].port=\${server.port}",
+ "armeria.ports[0].protocols[0]=http"
+ ]
+)
+@RunWith(SpringRunner::class)
+class ITZipkinServerSsl {
+ @Autowired lateinit var server: Server
+
+ // We typically use OkHttp in our tests, but Armeria bundles a handy insecure trust manager
+ internal val clientFactory = ClientFactoryBuilder()
+ .sslContextCustomizer { b -> b.trustManager(InsecureTrustManagerFactory.INSTANCE) }
+ .build()
+
+ @Test fun callHealthEndpoint_HTTP() {
+ callHealthEndpoint(SessionProtocol.HTTP)
+ }
+
+ @Test fun callHealthEndpoint_HTTPS() {
+ callHealthEndpoint(SessionProtocol.HTTPS)
+ }
+
+ fun callHealthEndpoint(protocol: SessionProtocol) {
+ val response = HttpClient.of(clientFactory, Http.url(server, "", protocol)).get("/health")
+ .aggregate().join()
+
+ assertThat(response.status()).isEqualTo(HttpStatus.OK)
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/InMemoryCollectorConfiguration.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/InMemoryCollectorConfiguration.kt
new file mode 100644
index 0000000..6afa971
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/InMemoryCollectorConfiguration.kt
@@ -0,0 +1,23 @@
+package zipkin2.server.internal
+
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+import zipkin2.collector.CollectorMetrics
+import zipkin2.collector.CollectorSampler
+import zipkin2.storage.InMemoryStorage
+import zipkin2.storage.StorageComponent
+
+@Configuration
+open class InMemoryCollectorConfiguration {
+ @Bean open fun sampler(): CollectorSampler {
+ return CollectorSampler.ALWAYS_SAMPLE
+ }
+
+ @Bean open fun metrics(): CollectorMetrics {
+ return CollectorMetrics.NOOP_METRICS
+ }
+
+ @Bean open fun storage(): StorageComponent {
+ return InMemoryStorage.newBuilder().build()
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ZipkinServerConfigurationTest.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ZipkinServerConfigurationTest.kt
new file mode 100644
index 0000000..1455a8d
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ZipkinServerConfigurationTest.kt
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal
+
+import brave.Tracing
+import com.linecorp.armeria.spring.actuate.ArmeriaSpringActuatorAutoConfiguration
+import io.micrometer.core.instrument.MeterRegistry
+import io.micrometer.prometheus.PrometheusConfig
+import io.micrometer.prometheus.PrometheusMeterRegistry
+import org.assertj.core.api.Assertions.assertThat
+import org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown
+import org.junit.After
+import org.junit.Test
+import org.springframework.beans.factory.NoSuchBeanDefinitionException
+import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration
+import org.springframework.boot.actuate.health.HealthAggregator
+import org.springframework.boot.actuate.health.OrderedHealthAggregator
+import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
+import org.springframework.boot.test.util.TestPropertyValues
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+import zipkin2.server.internal.brave.TracingConfiguration
+import zipkin2.storage.StorageComponent
+
+class ZipkinServerConfigurationTest {
+ val context = AnnotationConfigApplicationContext()
+ @After fun closeContext() = context.close()
+
+ @Test fun httpCollector_enabledByDefault() {
+ context.register(
+ ArmeriaSpringActuatorAutoConfiguration::class.java,
+ EndpointAutoConfiguration::class.java,
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinServerConfigurationTest.Config::class.java,
+ ZipkinServerConfiguration::class.java,
+ ZipkinHttpCollector::class.java
+ )
+ context.refresh()
+
+ assertThat(context.getBean(ZipkinHttpCollector::class.java)).isNotNull
+ }
+
+ @Test(expected = NoSuchBeanDefinitionException::class)
+ fun httpCollector_canDisable() {
+ TestPropertyValues.of("zipkin.collector.http.enabled:false").applyTo(context)
+ context.register(
+ ArmeriaSpringActuatorAutoConfiguration::class.java,
+ EndpointAutoConfiguration::class.java,
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinServerConfigurationTest.Config::class.java,
+ ZipkinServerConfiguration::class.java,
+ ZipkinHttpCollector::class.java
+ )
+ context.refresh()
+
+ context.getBean(ZipkinHttpCollector::class.java)
+ }
+
+ @Test fun query_enabledByDefault() {
+ context.register(
+ ArmeriaSpringActuatorAutoConfiguration::class.java,
+ EndpointAutoConfiguration::class.java,
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinServerConfigurationTest.Config::class.java,
+ ZipkinServerConfiguration::class.java,
+ ZipkinQueryApiV2::class.java
+ )
+ context.refresh()
+
+ assertThat(context.getBean(ZipkinQueryApiV2::class.java)).isNotNull
+ }
+
+ @Test fun query_canDisable() {
+ TestPropertyValues.of("zipkin.query.enabled:false").applyTo(context)
+ context.register(
+ ArmeriaSpringActuatorAutoConfiguration::class.java,
+ EndpointAutoConfiguration::class.java,
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinServerConfigurationTest.Config::class.java,
+ ZipkinServerConfiguration::class.java,
+ ZipkinQueryApiV2::class.java
+ )
+ context.refresh()
+
+ try {
+ context.getBean(ZipkinQueryApiV2::class.java)
+ failBecauseExceptionWasNotThrown<Any>(NoSuchBeanDefinitionException::class.java)
+ } catch (e: NoSuchBeanDefinitionException) {
+ }
+
+ }
+
+ @Test fun selfTracing_canEnable() {
+ TestPropertyValues.of("zipkin.self-tracing.enabled:true").applyTo(context)
+ context.register(
+ ArmeriaSpringActuatorAutoConfiguration::class.java,
+ EndpointAutoConfiguration::class.java,
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinServerConfigurationTest.Config::class.java,
+ ZipkinServerConfiguration::class.java,
+ TracingConfiguration::class.java
+ )
+ context.refresh()
+
+ context.getBean(Tracing::class.java).close()
+ }
+
+ @Test fun search_canDisable() {
+ TestPropertyValues.of("zipkin.storage.search-enabled:false").applyTo(context)
+ context.register(
+ ArmeriaSpringActuatorAutoConfiguration::class.java,
+ EndpointAutoConfiguration::class.java,
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinServerConfigurationTest.Config::class.java,
+ ZipkinServerConfiguration::class.java
+ )
+ context.refresh()
+
+ val v2Storage = context.getBean(StorageComponent::class.java)
+ assertThat(v2Storage)
+ .extracting("searchEnabled")
+ .containsExactly(false)
+ }
+
+ @Configuration
+ open class Config {
+ @Bean open fun healthAggregator(): HealthAggregator {
+ return OrderedHealthAggregator()
+ }
+
+ @Bean open fun registry(): MeterRegistry {
+ return PrometheusMeterRegistry(PrometheusConfig.DEFAULT)
+ }
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/brave/ITZipkinSelfTracing.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/brave/ITZipkinSelfTracing.kt
new file mode 100644
index 0000000..1258c8b
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/brave/ITZipkinSelfTracing.kt
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal.brave
+
+import com.linecorp.armeria.server.Server
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.junit4.SpringRunner
+import zipkin.server.ZipkinServer
+import zipkin2.server.internal.Http
+import zipkin2.storage.InMemoryStorage
+
+@SpringBootTest(
+ classes = [ZipkinServer::class],
+ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+ properties = ["spring.config.name=zipkin-server", "zipkin.self-tracing.enabled=true"]
+)
+@RunWith(SpringRunner::class)
+class ITZipkinSelfTracing {
+ @Autowired lateinit var server: Server
+ @Autowired lateinit var storage: TracingStorageComponent
+ @Before fun clearStorage() = (storage.delegate as InMemoryStorage).clear()
+
+ @Test fun getIsTraced_v2() {
+ assertThat(Http.getAsString(server, "/api/v2/services"))
+ .isEqualTo("[]")
+
+ assertServerTraced()
+ }
+
+ @Test fun postIsTraced_v1() {
+ assertThat(Http.post(server, "/api/v1/spans", body = "[]").isSuccessful).isTrue()
+
+ assertServerTraced()
+ }
+
+ @Test fun postIsTraced_v2() {
+ assertThat(Http.post(server, "/api/v2/spans", body = "[]").isSuccessful).isTrue()
+
+ assertServerTraced()
+ }
+
+ private fun assertServerTraced() {
+ Thread.sleep(1500) // wait for reporting interval
+
+ assertThat(Http.getAsString(server, "/api/v2/services"))
+ .isEqualTo("[\"zipkin-server\"]")
+ }
+}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/mysql/Access.java b/zipkin-server/src/test/kotlin/zipkin2/server/internal/cassandra/Access.kt
similarity index 72%
copy from zipkin-server/src/test/java/zipkin2/server/internal/mysql/Access.java
copy to zipkin-server/src/test/kotlin/zipkin2/server/internal/cassandra/Access.kt
index 6f01643..a2b818f 100644
--- a/zipkin-server/src/test/java/zipkin2/server/internal/mysql/Access.java
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/cassandra/Access.kt
@@ -14,16 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package zipkin2.server.internal.mysql;
+package zipkin2.server.internal.cassandra
-import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
-/** opens package access for testing */
-public final class Access {
-
- public static void registerMySQL(AnnotationConfigApplicationContext context) {
- context.register(
- PropertyPlaceholderAutoConfiguration.class, ZipkinMySQLStorageConfiguration.class);
- }
+/** opens package access for testing */
+object Access {
+ fun registerCassandra(context: AnnotationConfigApplicationContext) = context.register(
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinCassandraStorageConfiguration::class.java)
}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/cassandra/Access.java b/zipkin-server/src/test/kotlin/zipkin2/server/internal/cassandra3/Access.kt
similarity index 71%
rename from zipkin-server/src/test/java/zipkin2/server/internal/cassandra/Access.java
rename to zipkin-server/src/test/kotlin/zipkin2/server/internal/cassandra3/Access.kt
index ee6ecf1..a82942c 100644
--- a/zipkin-server/src/test/java/zipkin2/server/internal/cassandra/Access.java
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/cassandra3/Access.kt
@@ -14,16 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package zipkin2.server.internal.cassandra;
+package zipkin2.server.internal.cassandra3
-import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
-/** opens package access for testing */
-public final class Access {
-
- public static void registerCassandra(AnnotationConfigApplicationContext context) {
- context.register(
- PropertyPlaceholderAutoConfiguration.class, ZipkinCassandraStorageConfiguration.class);
- }
+/** opens package access for testing */
+object Access {
+ fun registerCassandra3(context: AnnotationConfigApplicationContext) = context.register(
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinCassandra3StorageConfiguration::class.java)
}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/cassandra3/Access.java b/zipkin-server/src/test/kotlin/zipkin2/server/internal/elasticsearch/Access.kt
similarity index 71%
rename from zipkin-server/src/test/java/zipkin2/server/internal/cassandra3/Access.java
rename to zipkin-server/src/test/kotlin/zipkin2/server/internal/elasticsearch/Access.kt
index f6b2e26..49769e6 100644
--- a/zipkin-server/src/test/java/zipkin2/server/internal/cassandra3/Access.java
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/elasticsearch/Access.kt
@@ -14,16 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package zipkin2.server.internal.cassandra3;
+package zipkin2.server.internal.elasticsearch
-import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
-/** opens package access for testing */
-public final class Access {
-
- public static void registerCassandra3(AnnotationConfigApplicationContext context) {
- context.register(
- PropertyPlaceholderAutoConfiguration.class, ZipkinCassandra3StorageConfiguration.class);
- }
+/** opens package access for testing */
+object Access {
+ fun registerElasticsearchHttp(context: AnnotationConfigApplicationContext) = context.register(
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinElasticsearchStorageAutoConfiguration::class.java)
}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/elasticsearch/BasicAuthInterceptorTest.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/elasticsearch/BasicAuthInterceptorTest.kt
new file mode 100644
index 0000000..40ec38c
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/elasticsearch/BasicAuthInterceptorTest.kt
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal.elasticsearch
+
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.mockwebserver.MockResponse
+import okhttp3.mockwebserver.MockWebServer
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.ExpectedException
+
+class BasicAuthInterceptorTest {
+ @Rule @JvmField val mockWebServer = MockWebServer()
+ @Rule @JvmField val thrown: ExpectedException = ExpectedException.none()
+
+ var client: OkHttpClient = OkHttpClient.Builder()
+ .addNetworkInterceptor(BasicAuthInterceptor(ZipkinElasticsearchStorageProperties()))
+ .build()
+
+ @Test fun intercept_whenESReturns403AndJsonBody_throwsWithResponseBodyMessage() {
+ thrown.expect(IllegalStateException::class.java)
+ thrown.expectMessage("Sadness.")
+
+ mockWebServer.enqueue(
+ MockResponse().setResponseCode(403).setBody("{\"message\":\"Sadness.\"}"))
+
+ client.newCall(Request.Builder().url(mockWebServer.url("/")).build()).execute()
+ }
+}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/kafka/Access.java b/zipkin-server/src/test/kotlin/zipkin2/server/internal/kafka/Access.kt
similarity index 56%
rename from zipkin-server/src/test/java/zipkin2/server/internal/kafka/Access.java
rename to zipkin-server/src/test/kotlin/zipkin2/server/internal/kafka/Access.kt
index b439268..cfd1d35 100644
--- a/zipkin-server/src/test/java/zipkin2/server/internal/kafka/Access.java
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/kafka/Access.kt
@@ -14,29 +14,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package zipkin2.server.internal.kafka;
+package zipkin2.server.internal.kafka
-import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import org.springframework.context.annotation.Configuration;
-import zipkin2.collector.kafka.KafkaCollector;
+import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
+import org.springframework.boot.context.properties.EnableConfigurationProperties
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
+import org.springframework.context.annotation.Configuration
+import zipkin2.collector.kafka.KafkaCollector
-/** opens package access for testing */
-public final class Access {
-
- /** Just registering properties to avoid automatically connecting to a Kafka server */
- public static void registerKafkaProperties(AnnotationConfigApplicationContext context) {
- context.register(
- PropertyPlaceholderAutoConfiguration.class, EnableKafkaCollectorProperties.class);
- }
+/** opens package access for testing */
+object Access {
+ /** Just registering properties to avoid automatically connecting to a Kafka server */
+ fun registerKafkaProperties(context: AnnotationConfigApplicationContext) = context.register(
+ PropertyPlaceholderAutoConfiguration::class.java,
+ EnableKafkaCollectorProperties::class.java)
@Configuration
- @EnableConfigurationProperties(ZipkinKafkaCollectorProperties.class)
- static class EnableKafkaCollectorProperties {}
+ @EnableConfigurationProperties(ZipkinKafkaCollectorProperties::class)
+ open class EnableKafkaCollectorProperties
- public static KafkaCollector.Builder collectorBuilder(
- AnnotationConfigApplicationContext context) {
- return context.getBean(ZipkinKafkaCollectorProperties.class).toBuilder();
- }
+ fun collectorBuilder(context: AnnotationConfigApplicationContext): KafkaCollector.Builder =
+ context.getBean(ZipkinKafkaCollectorProperties::class.java).toBuilder()
}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/kafka/ZipkinKafkaCollectorConfigurationTest.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/kafka/ZipkinKafkaCollectorConfigurationTest.kt
new file mode 100644
index 0000000..47de004
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/kafka/ZipkinKafkaCollectorConfigurationTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal.kafka
+
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.After
+import org.junit.Test
+import org.springframework.beans.factory.NoSuchBeanDefinitionException
+import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
+import org.springframework.boot.test.util.TestPropertyValues
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
+import zipkin2.collector.kafka.KafkaCollector
+import zipkin2.server.internal.InMemoryCollectorConfiguration
+
+class ZipkinKafkaCollectorConfigurationTest {
+ val context = AnnotationConfigApplicationContext()
+ @After fun closeContext() = context.close()
+
+ @Test(expected = NoSuchBeanDefinitionException::class)
+ fun doesNotProvideCollectorComponent_whenBootstrapServersUnset() {
+ context.register(
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinKafkaCollectorConfiguration::class.java,
+ InMemoryCollectorConfiguration::class.java)
+ context.refresh()
+
+ context.getBean(KafkaCollector::class.java)
+ }
+
+ @Test(expected = NoSuchBeanDefinitionException::class)
+ fun providesCollectorComponent_whenBootstrapServersEmptyString() {
+ TestPropertyValues.of("zipkin.collector.kafka.bootstrap-servers:").applyTo(context)
+ context.register(
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinKafkaCollectorConfiguration::class.java,
+ InMemoryCollectorConfiguration::class.java)
+ context.refresh()
+
+ context.getBean(KafkaCollector::class.java)
+ }
+
+ @Test fun providesCollectorComponent_whenBootstrapServersSet() {
+ TestPropertyValues.of("zipkin.collector.kafka.bootstrap-servers:localhost:9091")
+ .applyTo(context)
+ context.register(
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinKafkaCollectorConfiguration::class.java,
+ InMemoryCollectorConfiguration::class.java)
+ context.refresh()
+
+ assertThat(context.getBean(KafkaCollector::class.java)).isNotNull
+ }
+}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/mysql/Access.java b/zipkin-server/src/test/kotlin/zipkin2/server/internal/kafka/ZipkinKafkaCollectorPropertiesTest.kt
similarity index 62%
rename from zipkin-server/src/test/java/zipkin2/server/internal/mysql/Access.java
rename to zipkin-server/src/test/kotlin/zipkin2/server/internal/kafka/ZipkinKafkaCollectorPropertiesTest.kt
index 6f01643..eacbacf 100644
--- a/zipkin-server/src/test/java/zipkin2/server/internal/mysql/Access.java
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/kafka/ZipkinKafkaCollectorPropertiesTest.kt
@@ -14,16 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package zipkin2.server.internal.mysql;
+package zipkin2.server.internal.kafka
-import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Test
-/** opens package access for testing */
-public final class Access {
-
- public static void registerMySQL(AnnotationConfigApplicationContext context) {
- context.register(
- PropertyPlaceholderAutoConfiguration.class, ZipkinMySQLStorageConfiguration.class);
+class ZipkinKafkaCollectorPropertiesTest {
+ @Test fun stringPropertiesConvertEmptyStringsToNull() {
+ val properties = ZipkinKafkaCollectorProperties()
+ properties.bootstrapServers = ""
+ properties.groupId = ""
+ properties.topic = ""
+ assertThat(properties.bootstrapServers).isNull()
+ assertThat(properties.groupId).isNull()
+ assertThat(properties.topic).isNull()
}
}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/elasticsearch/Access.java b/zipkin-server/src/test/kotlin/zipkin2/server/internal/mysql/Access.kt
similarity index 70%
rename from zipkin-server/src/test/java/zipkin2/server/internal/elasticsearch/Access.java
rename to zipkin-server/src/test/kotlin/zipkin2/server/internal/mysql/Access.kt
index 25ac0f5..d703733 100644
--- a/zipkin-server/src/test/java/zipkin2/server/internal/elasticsearch/Access.java
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/mysql/Access.kt
@@ -14,17 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package zipkin2.server.internal.elasticsearch;
+package zipkin2.server.internal.mysql
-import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
-/** opens package access for testing */
-public final class Access {
-
- public static void registerElasticsearchHttp(AnnotationConfigApplicationContext context) {
- context.register(
- PropertyPlaceholderAutoConfiguration.class,
- ZipkinElasticsearchStorageAutoConfiguration.class);
- }
+/** opens package access for testing */
+object Access {
+ fun registerMySQL(context: AnnotationConfigApplicationContext) = context.register(
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinMySQLStorageConfiguration::class.java)
}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/prometheus/ZipkinPrometheusMetricsConfigurationTest.java b/zipkin-server/src/test/kotlin/zipkin2/server/internal/prometheus/ZipkinPrometheusMetricsConfigurationTest.kt
similarity index 50%
rename from zipkin-server/src/test/java/zipkin2/server/internal/prometheus/ZipkinPrometheusMetricsConfigurationTest.java
rename to zipkin-server/src/test/kotlin/zipkin2/server/internal/prometheus/ZipkinPrometheusMetricsConfigurationTest.kt
index 08dd021..1081041 100644
--- a/zipkin-server/src/test/java/zipkin2/server/internal/prometheus/ZipkinPrometheusMetricsConfigurationTest.java
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/prometheus/ZipkinPrometheusMetricsConfigurationTest.kt
@@ -14,54 +14,50 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package zipkin2.server.internal.prometheus;
-
-import com.linecorp.armeria.spring.ArmeriaServerConfigurator;
-import org.junit.After;
-import org.junit.Test;
-import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
-import org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusMetricsExportAutoConfiguration;
-import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
-import org.springframework.boot.test.util.TestPropertyValues;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class ZipkinPrometheusMetricsConfigurationTest {
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
-
- public void refresh() {
- context.register(
- PropertyPlaceholderAutoConfiguration.class,
- MetricsAutoConfiguration.class,
- PrometheusMetricsExportAutoConfiguration.class,
- ZipkinPrometheusMetricsConfiguration.class
- );
- context.refresh();
+package zipkin2.server.internal.prometheus
+
+import com.linecorp.armeria.spring.ArmeriaServerConfigurator
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.After
+import org.junit.Test
+import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration
+import org.springframework.boot.actuate.autoconfigure.metrics.export.prometheus.PrometheusMetricsExportAutoConfiguration
+import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
+import org.springframework.boot.test.util.TestPropertyValues
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
+
+class ZipkinPrometheusMetricsConfigurationTest {
+ val context = AnnotationConfigApplicationContext()
+ @After fun closeContext() = context.close()
+
+ @Test fun providesHttpRequestDurationCustomizer() {
+ refresh()
+
+ context.getBeansOfType(ArmeriaServerConfigurator::class.java)
}
- @After public void close() {
- context.close();
- }
-
- @Test public void providesHttpRequestDurationCustomizer() {
- refresh();
+ @Test fun defaultMetricName() {
+ refresh()
- context.getBeansOfType(ArmeriaServerConfigurator.class);
+ assertThat(context.getBean(ZipkinPrometheusMetricsConfiguration::class.java).metricName)
+ .isEqualTo("http.server.requests")
}
- @Test public void defaultMetricName() {
- refresh();
+ @Test fun overrideMetricName() {
+ TestPropertyValues.of("management.metrics.web.server.requests-metric-name:foo").applyTo(context)
+ refresh()
- assertThat(context.getBean(ZipkinPrometheusMetricsConfiguration.class).metricName)
- .isEqualTo("http.server.requests");
+ assertThat(context.getBean(ZipkinPrometheusMetricsConfiguration::class.java).metricName)
+ .isEqualTo("foo")
}
- @Test public void overrideMetricName() {
- TestPropertyValues.of("management.metrics.web.server.requests-metric-name:foo").applyTo(context);
- refresh();
-
- assertThat(context.getBean(ZipkinPrometheusMetricsConfiguration.class).metricName)
- .isEqualTo("foo");
+ fun refresh() {
+ context.register(
+ PropertyPlaceholderAutoConfiguration::class.java,
+ MetricsAutoConfiguration::class.java,
+ PrometheusMetricsExportAutoConfiguration::class.java,
+ ZipkinPrometheusMetricsConfiguration::class.java
+ )
+ context.refresh()
}
}
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/rabbitmq/Access.java b/zipkin-server/src/test/kotlin/zipkin2/server/internal/rabbitmq/Access.kt
similarity index 58%
rename from zipkin-server/src/test/java/zipkin2/server/internal/rabbitmq/Access.java
rename to zipkin-server/src/test/kotlin/zipkin2/server/internal/rabbitmq/Access.kt
index 729dd59..049f550 100644
--- a/zipkin-server/src/test/java/zipkin2/server/internal/rabbitmq/Access.java
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/rabbitmq/Access.kt
@@ -14,29 +14,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package zipkin2.server.internal.rabbitmq;
+package zipkin2.server.internal.rabbitmq
-import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
-import org.springframework.context.annotation.Configuration;
-import zipkin2.collector.rabbitmq.RabbitMQCollector;
+import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
+import org.springframework.boot.context.properties.EnableConfigurationProperties
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
+import org.springframework.context.annotation.Configuration
+import zipkin2.collector.rabbitmq.RabbitMQCollector
-/** opens package access for testing */
-public final class Access {
-
- /** Just registering properties to avoid automatically connecting to a Rabbit MQ server */
- public static void registerRabbitMQProperties(AnnotationConfigApplicationContext context) {
- context.register(
- PropertyPlaceholderAutoConfiguration.class, EnableRabbitMQCollectorProperties.class);
- }
+/** opens package access for testing */
+object Access {
+ /** Just registering properties to avoid automatically connecting to a Rabbit MQ server */
+ fun registerRabbitMQProperties(context: AnnotationConfigApplicationContext) = context.register(
+ PropertyPlaceholderAutoConfiguration::class.java,
+ EnableRabbitMQCollectorProperties::class.java)
@Configuration
- @EnableConfigurationProperties(ZipkinRabbitMQCollectorProperties.class)
- static class EnableRabbitMQCollectorProperties {}
+ @EnableConfigurationProperties(ZipkinRabbitMQCollectorProperties::class)
+ open class EnableRabbitMQCollectorProperties
- public static RabbitMQCollector.Builder collectorBuilder(
- AnnotationConfigApplicationContext context) throws Exception {
- return context.getBean(ZipkinRabbitMQCollectorProperties.class).toBuilder();
- }
+ fun collectorBuilder(context: AnnotationConfigApplicationContext): RabbitMQCollector.Builder =
+ context.getBean(ZipkinRabbitMQCollectorProperties::class.java).toBuilder()
}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/rabbitmq/ZipkinRabbitMQCollectorConfigurationTest.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/rabbitmq/ZipkinRabbitMQCollectorConfigurationTest.kt
new file mode 100644
index 0000000..92b104f
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/rabbitmq/ZipkinRabbitMQCollectorConfigurationTest.kt
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal.rabbitmq
+
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.After
+import org.junit.Ignore
+import org.junit.Test
+import org.springframework.beans.factory.NoSuchBeanDefinitionException
+import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
+import org.springframework.boot.test.util.TestPropertyValues
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
+import zipkin2.collector.rabbitmq.RabbitMQCollector
+import zipkin2.server.internal.InMemoryCollectorConfiguration
+
+class ZipkinRabbitMQCollectorConfigurationTest {
+ val context = AnnotationConfigApplicationContext()
+ @After fun closeContext() = context.close()
+
+ @Test(expected = NoSuchBeanDefinitionException::class)
+ fun doesNotProvideCollectorComponent_whenAddressAndUriNotSet() {
+ context.register(
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinRabbitMQCollectorConfiguration::class.java,
+ InMemoryCollectorConfiguration::class.java)
+ context.refresh()
+
+ context.getBean(RabbitMQCollector::class.java)
+ }
+
+ @Test(expected = NoSuchBeanDefinitionException::class)
+ fun doesNotProvideCollectorComponent_whenAddressesAndUriIsEmptyString() {
+ TestPropertyValues.of(
+ "zipkin.collector.rabbitmq.addresses:",
+ "zipkin.collector.rabbitmq.uri:")
+ .applyTo(context)
+ context.register(
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinRabbitMQCollectorConfiguration::class.java,
+ InMemoryCollectorConfiguration::class.java)
+ context.refresh()
+
+ context.getBean(RabbitMQCollector::class.java)
+ }
+
+ @Test @Ignore fun providesCollectorComponent_whenAddressesSet() {
+ TestPropertyValues.of("zipkin.collector.rabbitmq.addresses=localhost:5672").applyTo(context)
+ context.register(
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinRabbitMQCollectorConfiguration::class.java,
+ InMemoryCollectorConfiguration::class.java)
+ context.refresh()
+
+ assertThat(context.getBean(RabbitMQCollector::class.java)).isNotNull
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/rabbitmq/ZipkinRabbitMQCollectorPropertiesTest.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/rabbitmq/ZipkinRabbitMQCollectorPropertiesTest.kt
new file mode 100644
index 0000000..5ca2760
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/rabbitmq/ZipkinRabbitMQCollectorPropertiesTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal.rabbitmq
+
+import com.rabbitmq.client.ConnectionFactory
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Test
+import java.net.URI
+
+class ZipkinRabbitMQCollectorPropertiesTest {
+
+ @Test fun uriProperlyParsedAndIgnoresOtherProperties_whenUriSet() {
+ val properties = ZipkinRabbitMQCollectorProperties()
+ properties.uri = URI.create("amqp://admin:admin@localhost:5678/myv")
+ properties.addresses = listOf("will_not^work!")
+ properties.username = "bob"
+ properties.password = "letmein"
+ properties.virtualHost = "drwho"
+
+ assertThat(properties.toBuilder())
+ .extracting("connectionFactory")
+ .allSatisfy { `object` ->
+ val connFactory = `object` as ConnectionFactory
+ assertThat(connFactory.host).isEqualTo("localhost")
+ assertThat(connFactory.port).isEqualTo(5678)
+ assertThat(connFactory.username).isEqualTo("admin")
+ assertThat(connFactory.password).isEqualTo("admin")
+ assertThat(connFactory.virtualHost).isEqualTo("myv")
+ }
+ }
+
+ /** This prevents an empty RABBIT_URI variable from being mistaken as a real one */
+ @Test fun ignoresEmptyURI() {
+ val properties = ZipkinRabbitMQCollectorProperties()
+ properties.uri = URI.create("")
+
+ assertThat(properties.uri).isNull()
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ui/ITZipkinUiConfiguration.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ui/ITZipkinUiConfiguration.kt
new file mode 100644
index 0000000..179a233
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ui/ITZipkinUiConfiguration.kt
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal.ui
+
+import com.linecorp.armeria.client.HttpClient
+import com.linecorp.armeria.common.HttpHeaderNames
+import com.linecorp.armeria.common.HttpHeaders
+import com.linecorp.armeria.common.HttpMethod
+import com.linecorp.armeria.server.Server
+import okhttp3.Headers
+import okio.Okio
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.context.annotation.Import
+import org.springframework.test.context.junit4.SpringRunner
+import zipkin2.server.internal.Http
+
+@RunWith(SpringRunner::class)
+@SpringBootTest(
+ classes = [ITZipkinUiConfiguration.TestServer::class],
+ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+ properties = [
+ "zipkin.ui.base-path=/foozipkin",
+ "server.compression.enabled=true",
+ "server.compression.min-response-size=128"
+ ]
+)
+class ITZipkinUiConfiguration {
+ @Autowired lateinit var server: Server
+
+ /** The zipkin-ui is a single-page app. This prevents reloading all resources on each click. */
+ @Test fun setsMaxAgeOnUiResources() {
+ assertThat(Http.get(server, "/zipkin/config.json").header("Cache-Control"))
+ .isEqualTo("max-age=600")
+ assertThat(Http.get(server, "/zipkin/index.html").header("Cache-Control"))
+ .isEqualTo("max-age=60")
+ assertThat(Http.get(server, "/zipkin/test.txt").header("Cache-Control"))
+ .isEqualTo("max-age=31536000")
+ }
+
+ @Test fun redirectsIndex() {
+ val index = Http.getAsString(server, "/zipkin/index.html")
+ assertThat(Http.getAsString(server, "/zipkin/")).isEqualTo(index)
+
+ listOf("/zipkin", "/").forEach { path ->
+ val response = Http.get(server, path)
+ assertThat(response.code()).isEqualTo(302)
+ assertThat(response.header("location")).isEqualTo("/zipkin/")
+ }
+ }
+
+ /** Browsers honor conditional requests such as eTag. Let's make sure the server does */
+ @Test fun conditionalRequests() {
+ listOf("/zipkin/config.json", "/zipkin/index.html", "/zipkin/test.txt").forEach { path ->
+ val etag = Http.get(server, path).header("etag")
+ assertThat(Http.get(server, path, Headers.of("If-None-Match", etag)).code())
+ .isEqualTo(304)
+ assertThat(Http.get(server, path, Headers.of("If-None-Match", "aargh")).code())
+ .isEqualTo(200)
+ }
+ }
+
+ /** Some assets are pretty big. ensure they use compression. */
+ @Test fun supportsCompression() {
+ assertThat(getContentEncodingFromRequestThatAcceptsGzip("/zipkin/test.txt"))
+ .isNull() // too small to compress
+ assertThat(getContentEncodingFromRequestThatAcceptsGzip("/zipkin/config.json"))
+ .isEqualTo("gzip")
+ }
+
+ /**
+ * The test sets the property `zipkin.ui.base-path=/foozipkin`, which should reflect in
+ * index.html
+ */
+ @Test fun replacesBaseTag() {
+ assertThat(Http.getAsString(server, "/zipkin/index.html"))
+ .isEqualToIgnoringWhitespace(stringFromClasspath("zipkin-ui/index.html")
+ .replace("<base href=\"/\" />", "<base href=\"/foozipkin/\">"))
+ }
+
+ /** index.html is served separately. This tests other content is also loaded from the classpath. */
+ @Test fun servesOtherContentFromClasspath() {
+ assertThat(Http.getAsString(server, "/zipkin/test.txt"))
+ .isEqualToIgnoringWhitespace(stringFromClasspath("zipkin-ui/test.txt"))
+ }
+
+ @EnableAutoConfiguration
+ @Import(ZipkinUiConfiguration::class)
+ class TestServer
+
+ private fun stringFromClasspath(path: String): String {
+ val url = javaClass.classLoader.getResource(path)
+ assertThat(url).isNotNull()
+
+ url!!.openStream()
+ .use { fromClasspath -> return Okio.buffer(Okio.source(fromClasspath)).readUtf8() }
+ }
+
+ private fun getContentEncodingFromRequestThatAcceptsGzip(path: String): String? {
+ // We typically use OkHttp in our tests, but that automatically unzips..
+ val response = HttpClient.of(Http.url(server, ""))
+ .execute(HttpHeaders.of(HttpMethod.GET, path).set(HttpHeaderNames.ACCEPT_ENCODING, "gzip"))
+ .aggregate().join()
+ return response.headers().get(HttpHeaderNames.CONTENT_ENCODING)
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/server/internal/ui/ZipkinUiConfigurationTest.kt b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ui/ZipkinUiConfigurationTest.kt
new file mode 100644
index 0000000..3e270ac
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/server/internal/ui/ZipkinUiConfigurationTest.kt
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.server.internal.ui
+
+import com.linecorp.armeria.common.AggregatedHttpMessage
+import com.linecorp.armeria.common.HttpHeaderNames
+import com.linecorp.armeria.common.HttpHeaders
+import com.linecorp.armeria.common.HttpMethod
+import com.linecorp.armeria.common.HttpRequest
+import com.linecorp.armeria.common.MediaType
+import com.linecorp.armeria.server.ServiceRequestContext
+import io.netty.handler.codec.http.cookie.ClientCookieEncoder
+import io.netty.handler.codec.http.cookie.Cookie
+import io.netty.handler.codec.http.cookie.DefaultCookie
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.After
+import org.junit.Test
+import org.springframework.beans.factory.BeanCreationException
+import org.springframework.beans.factory.NoSuchBeanDefinitionException
+import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
+import org.springframework.boot.test.util.TestPropertyValues
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
+import org.springframework.core.io.ClassPathResource
+import java.io.ByteArrayInputStream
+import java.io.FileNotFoundException
+
+class ZipkinUiConfigurationTest {
+ val context = AnnotationConfigApplicationContext()
+ @After fun closeContext() = context.close()
+
+ @Test fun indexHtmlFromClasspath() {
+ refreshContext();
+
+ assertThat(context.getBean(ZipkinUiConfiguration::class.java).indexHtml)
+ .isNotNull
+ }
+
+ @Test fun indexContentType() {
+ refreshContext()
+
+ assertThat(serveIndex().headers().contentType())
+ .isEqualTo(MediaType.HTML_UTF_8)
+ }
+
+ @Test fun invalidIndexHtml() {
+ TestPropertyValues.of("zipkin.ui.basepath:/foo/bar").applyTo(context)
+ refreshContext()
+
+ // I failed to make Jsoup barf, even on nonsense like: "<head wait no I changed my mind this HTML is totally invalid <<<<<<<<<<<"
+ // So let's just run with a case where the file doesn't exist
+ val ui = context.getBean(ZipkinUiConfiguration::class.java)
+ ui.indexHtml = ClassPathResource("does-not-exist.html")
+
+ try {
+ serveIndex()
+
+ assertThat(false).isTrue()
+ } catch (e: RuntimeException) {
+ assertThat(e).hasRootCauseInstanceOf(FileNotFoundException::class.java)
+ }
+ }
+
+ @Test fun canOverridesProperty_defaultLookback() {
+ TestPropertyValues.of("zipkin.ui.defaultLookback:100").applyTo(context)
+ refreshContext()
+
+ assertThat(context.getBean(ZipkinUiProperties::class.java).defaultLookback)
+ .isEqualTo(100)
+ }
+
+ @Test fun canOverrideProperty_logsUrl() {
+ val url = "http://mycompany.com/kibana"
+ TestPropertyValues.of("zipkin.ui.logs-url:$url").applyTo(context)
+ refreshContext()
+
+ assertThat(context.getBean(ZipkinUiProperties::class.java).logsUrl).isEqualTo(url)
+ }
+
+ @Test fun logsUrlIsNullIfOverridenByEmpty() {
+ TestPropertyValues.of("zipkin.ui.logs-url:").applyTo(context)
+ refreshContext()
+
+ assertThat(context.getBean(ZipkinUiProperties::class.java).logsUrl).isNull()
+ }
+
+ @Test fun logsUrlIsNullByDefault() {
+ refreshContext()
+
+ assertThat(context.getBean(ZipkinUiProperties::class.java).logsUrl).isNull()
+ }
+
+ @Test(expected = NoSuchBeanDefinitionException::class)
+ fun canOverridesProperty_disable() {
+ TestPropertyValues.of("zipkin.ui.enabled:false").applyTo(context)
+ refreshContext()
+
+ context.getBean(ZipkinUiProperties::class.java)
+ }
+
+ @Test fun canOverridesProperty_searchEnabled() {
+ TestPropertyValues.of("zipkin.ui.search-enabled:false").applyTo(context)
+ refreshContext()
+
+ assertThat(context.getBean(ZipkinUiProperties::class.java).isSearchEnabled).isFalse()
+ }
+
+ @Test fun canOverrideProperty_dependencyLowErrorRate() {
+ TestPropertyValues.of("zipkin.ui.dependency.low-error-rate:0.1").applyTo(context)
+ refreshContext()
+
+ assertThat(context.getBean(ZipkinUiProperties::class.java).dependency.lowErrorRate)
+ .isEqualTo(0.1f)
+ }
+
+ @Test fun canOverrideProperty_dependencyHighErrorRate() {
+ TestPropertyValues.of("zipkin.ui.dependency.high-error-rate:0.1").applyTo(context)
+ refreshContext()
+
+ assertThat(context.getBean(ZipkinUiProperties::class.java).dependency.highErrorRate)
+ .isEqualTo(0.1f)
+ }
+
+ @Test fun defaultBaseUrl_doesNotChangeResource() {
+ refreshContext()
+
+ assertThat(ByteArrayInputStream(serveIndex().content().array()))
+ .hasSameContentAs(javaClass.getResourceAsStream("/zipkin-ui/index.html"))
+ }
+
+ @Test fun canOverideProperty_basePath() {
+ TestPropertyValues.of("zipkin.ui.basepath:/foo/bar").applyTo(context)
+ refreshContext()
+
+ assertThat(serveIndex().contentUtf8())
+ .contains("<base href=\"/foo/bar/\">")
+ }
+
+ @Test fun lensCookieOverridesIndex() {
+ refreshContext()
+
+ assertThat(serveIndex(DefaultCookie("lens", "true")).contentUtf8())
+ .contains("zipkin-lens")
+ }
+
+ @Test fun canOverideProperty_specialCaseRoot() {
+ TestPropertyValues.of("zipkin.ui.basepath:/").applyTo(context)
+ refreshContext()
+
+ assertThat(serveIndex().contentUtf8())
+ .contains("<base href=\"/\">")
+ }
+
+ private fun serveIndex(vararg cookies: Cookie): AggregatedHttpMessage {
+ val headers = HttpHeaders.of(HttpMethod.GET, "/")
+ val encodedCookies = ClientCookieEncoder.LAX.encode(*cookies)
+ if (encodedCookies != null) {
+ headers.set(HttpHeaderNames.COOKIE, encodedCookies)
+ }
+ val req = HttpRequest.of(headers)
+ return context.getBean(ZipkinUiConfiguration::class.java).indexSwitchingService()
+ .serve(ServiceRequestContext.of(req), req).aggregate()
+ .get()
+ }
+
+ private fun refreshContext() {
+ context.register(
+ PropertyPlaceholderAutoConfiguration::class.java,
+ ZipkinUiConfiguration::class.java)
+ context.refresh()
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/storage/cassandra/ZipkinCassandraStorageAutoConfigurationTest.kt b/zipkin-server/src/test/kotlin/zipkin2/storage/cassandra/ZipkinCassandraStorageAutoConfigurationTest.kt
new file mode 100644
index 0000000..ae0e1fd
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/storage/cassandra/ZipkinCassandraStorageAutoConfigurationTest.kt
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.storage.cassandra
+
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.After
+import org.junit.Test
+import org.springframework.beans.factory.NoSuchBeanDefinitionException
+import org.springframework.boot.test.util.TestPropertyValues
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
+import zipkin2.server.internal.cassandra3.Access
+
+class ZipkinCassandraStorageAutoConfigurationTest {
+ val context = AnnotationConfigApplicationContext()
+ @After fun closeContext() = context.close()
+
+ @Test(expected = NoSuchBeanDefinitionException::class)
+ fun doesntProvidesStorageComponent_whenStorageTypeNotCassandra() {
+ TestPropertyValues.of("zipkin.storage.type:elasticsearch").applyTo(context)
+ Access.registerCassandra3(context)
+ context.refresh()
+
+ context.getBean(CassandraStorage::class.java)
+ }
+
+ @Test fun providesStorageComponent_whenStorageTypeCassandra() {
+ TestPropertyValues.of("zipkin.storage.type:cassandra3").applyTo(context)
+ Access.registerCassandra3(context)
+ context.refresh()
+
+ assertThat(context.getBean(CassandraStorage::class.java)).isNotNull
+ }
+
+ @Test fun canOverridesProperty_contactPoints() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:cassandra3",
+ "zipkin.storage.cassandra3.contact-points:host1,host2" // note snake-case supported
+ ).applyTo(context)
+ Access.registerCassandra3(context)
+ context.refresh()
+
+ assertThat(context.getBean(CassandraStorage::class.java).contactPoints()).isEqualTo(
+ "host1,host2")
+ }
+
+ @Test fun strictTraceId_defaultsToTrue() {
+ TestPropertyValues.of("zipkin.storage.type:cassandra3").applyTo(context)
+ Access.registerCassandra3(context)
+ context.refresh()
+
+ assertThat(context.getBean(CassandraStorage::class.java).strictTraceId()).isTrue()
+ }
+
+ @Test fun strictTraceId_canSetToFalse() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:cassandra3",
+ "zipkin.storage.strict-trace-id:false")
+ .applyTo(context)
+ Access.registerCassandra3(context)
+ context.refresh()
+
+ assertThat(context.getBean(CassandraStorage::class.java).strictTraceId()).isFalse()
+ }
+
+ @Test fun searchEnabled_canSetToFalse() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:cassandra3",
+ "zipkin.storage.search-enabled:false")
+ .applyTo(context)
+ Access.registerCassandra3(context)
+ context.refresh()
+
+ assertThat(context.getBean(CassandraStorage::class.java).searchEnabled()).isFalse()
+ }
+
+ @Test fun autocompleteKeys_list() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:cassandra3",
+ "zipkin.storage.autocomplete-keys:environment")
+ .applyTo(context)
+ Access.registerCassandra3(context)
+ context.refresh()
+
+ assertThat(context.getBean(CassandraStorage::class.java).autocompleteKeys())
+ .containsOnly("environment")
+ }
+
+ @Test fun autocompleteTtl() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:cassandra3",
+ "zipkin.storage.autocomplete-ttl:60000")
+ .applyTo(context)
+ Access.registerCassandra3(context)
+ context.refresh()
+
+ assertThat(context.getBean(CassandraStorage::class.java).autocompleteTtl())
+ .isEqualTo(60000)
+ }
+
+ @Test fun autocompleteCardinality() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:cassandra3",
+ "zipkin.storage.autocomplete-cardinality:5000")
+ .applyTo(context)
+ Access.registerCassandra3(context)
+ context.refresh()
+
+ assertThat(context.getBean(CassandraStorage::class.java).autocompleteCardinality())
+ .isEqualTo(5000)
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/storage/cassandra/v1/ZipkinCassandraStorageConfigurationTest.kt b/zipkin-server/src/test/kotlin/zipkin2/storage/cassandra/v1/ZipkinCassandraStorageConfigurationTest.kt
new file mode 100644
index 0000000..a3ab8d8
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/storage/cassandra/v1/ZipkinCassandraStorageConfigurationTest.kt
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.storage.cassandra.v1
+
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.After
+import org.junit.Test
+import org.springframework.beans.factory.NoSuchBeanDefinitionException
+import org.springframework.boot.test.util.TestPropertyValues
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
+import zipkin2.server.internal.cassandra.Access
+
+class ZipkinCassandraStorageConfigurationTest {
+ val context = AnnotationConfigApplicationContext()
+ @After fun closeContext() = context.close()
+
+ @Test(expected = NoSuchBeanDefinitionException::class)
+ fun doesntProvidesStorageComponent_whenStorageTypeNotCassandra() {
+ TestPropertyValues.of("zipkin.storage.type:elasticsearch").applyTo(context)
+ Access.registerCassandra(context)
+ context.refresh()
+
+ context.getBean(CassandraStorage::class.java)
+ }
+
+ @Test fun providesStorageComponent_whenStorageTypeCassandra() {
+ TestPropertyValues.of("zipkin.storage.type:cassandra").applyTo(context)
+ Access.registerCassandra(context)
+ context.refresh()
+
+ assertThat(context.getBean(CassandraStorage::class.java)).isNotNull
+ }
+
+ @Test fun canOverridesProperty_contactPoints() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:cassandra",
+ "zipkin.storage.cassandra.contact-points:host1,host2" // note snake-case supported
+ ).applyTo(context)
+ Access.registerCassandra(context)
+ context.refresh()
+
+ assertThat(context.getBean(CassandraStorage::class.java).contactPoints).isEqualTo(
+ "host1,host2")
+ }
+
+ @Test fun strictTraceId_defaultsToTrue() {
+ TestPropertyValues.of("zipkin.storage.type:cassandra").applyTo(context)
+ Access.registerCassandra(context)
+ context.refresh()
+
+ assertThat(context.getBean(CassandraStorage::class.java).strictTraceId).isTrue()
+ }
+
+ @Test fun strictTraceId_canSetToFalse() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:cassandra",
+ "zipkin.storage.strict-trace-id:false")
+ .applyTo(context)
+ Access.registerCassandra(context)
+ context.refresh()
+
+ assertThat(context.getBean(CassandraStorage::class.java).strictTraceId).isFalse()
+ }
+
+ @Test fun autocompleteKeys_list() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:cassandra",
+ "zipkin.storage.autocomplete-keys:environment")
+ .applyTo(context)
+ Access.registerCassandra(context)
+ context.refresh()
+
+ assertThat(context.getBean(CassandraStorage::class.java).autocompleteKeys)
+ .containsOnly("environment")
+ }
+
+ @Test fun autocompleteTtl() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:cassandra",
+ "zipkin.storage.autocomplete-ttl:60000")
+ .applyTo(context)
+ Access.registerCassandra(context)
+ context.refresh()
+
+ assertThat(context.getBean(CassandraStorage::class.java).autocompleteTtl)
+ .isEqualTo(60000)
+ }
+
+ @Test fun autocompleteCardinality() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:cassandra",
+ "zipkin.storage.autocomplete-cardinality:5000")
+ .applyTo(context)
+ Access.registerCassandra(context)
+ context.refresh()
+
+ assertThat(context.getBean(CassandraStorage::class.java).autocompleteCardinality)
+ .isEqualTo(5000)
+ }
+}
diff --git a/zipkin-server/src/test/kotlin/zipkin2/storage/mysql/v1/ZipkinMySQLStorageConfigurationTest.kt b/zipkin-server/src/test/kotlin/zipkin2/storage/mysql/v1/ZipkinMySQLStorageConfigurationTest.kt
new file mode 100644
index 0000000..e104011
--- /dev/null
+++ b/zipkin-server/src/test/kotlin/zipkin2/storage/mysql/v1/ZipkinMySQLStorageConfigurationTest.kt
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package zipkin2.storage.mysql.v1
+
+import com.zaxxer.hikari.HikariDataSource
+import org.assertj.core.api.Assertions.assertThat
+import org.junit.After
+import org.junit.Test
+import org.springframework.beans.factory.NoSuchBeanDefinitionException
+import org.springframework.boot.test.util.TestPropertyValues
+import org.springframework.context.annotation.AnnotationConfigApplicationContext
+import zipkin2.server.internal.mysql.Access
+
+class ZipkinMySQLStorageConfigurationTest {
+ val context = AnnotationConfigApplicationContext()
+ @After fun closeContext() = context.close()
+
+ @Test(expected = NoSuchBeanDefinitionException::class)
+ fun doesntProvidesStorageComponent_whenStorageTypeNotMySQL() {
+ TestPropertyValues.of("zipkin.storage.type:cassandra").applyTo(context)
+ Access.registerMySQL(context)
+ context.refresh()
+
+ context.getBean(MySQLStorage::class.java)
+ }
+
+ @Test fun providesStorageComponent_whenStorageTypeMySQL() {
+ TestPropertyValues.of("zipkin.storage.type:mysql").applyTo(context)
+ Access.registerMySQL(context)
+ context.refresh()
+
+ assertThat(context.getBean(MySQLStorage::class.java)).isNotNull
+ }
+
+ @Test fun canOverridesProperty_username() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:mysql",
+ "zipkin.storage.mysql.username:robot")
+ .applyTo(context)
+ Access.registerMySQL(context)
+ context.refresh()
+
+ assertThat(context.getBean(HikariDataSource::class.java).username).isEqualTo("robot")
+ }
+
+ @Test fun strictTraceId_defaultsToTrue() {
+ TestPropertyValues.of("zipkin.storage.type:mysql").applyTo(context)
+ Access.registerMySQL(context)
+ context.refresh()
+
+ assertThat(context.getBean(MySQLStorage::class.java).strictTraceId).isTrue()
+ }
+
+ @Test fun strictTraceId_canSetToFalse() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:mysql",
+ "zipkin.storage.strict-trace-id:false")
+ .applyTo(context)
+ Access.registerMySQL(context)
+ context.refresh()
+
+ assertThat(context.getBean(MySQLStorage::class.java).strictTraceId).isFalse()
+ }
+
+ @Test fun searchEnabled_canSetToFalse() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:mysql",
+ "zipkin.storage.search-enabled:false")
+ .applyTo(context)
+ Access.registerMySQL(context)
+ context.refresh()
+
+ assertThat(context.getBean(MySQLStorage::class.java).searchEnabled).isFalse()
+ }
+
+ @Test fun autocompleteKeys_list() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:mysql",
+ "zipkin.storage.autocomplete-keys:environment")
+ .applyTo(context)
+ Access.registerMySQL(context)
+ context.refresh()
+
+ assertThat(context.getBean(MySQLStorage::class.java).autocompleteKeys)
+ .containsOnly("environment")
+ }
+
+ @Test fun usesJdbcUrl_whenPresent() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:mysql",
+ "zipkin.storage.mysql" + ".jdbc-url:jdbc:mysql://host1,host2,host3/zipkin")
+ .applyTo(context)
+ Access.registerMySQL(context)
+ context.refresh()
+
+ assertThat(context.getBean(HikariDataSource::class.java).jdbcUrl).isEqualTo(
+ "jdbc:mysql://host1,host2,host3/zipkin")
+ }
+
+ @Test fun usesRegularConfig_whenBlank() {
+ TestPropertyValues.of(
+ "zipkin.storage.type:mysql",
+ "zipkin.storage.mysql.jdbc-url:",
+ "zipkin.storage.mysql.host:host",
+ "zipkin.storage.mysql.port:3306",
+ "zipkin.storage.mysql.username:root",
+ "zipkin.storage.mysql.password:secret",
+ "zipkin.storage.mysql.db:zipkin")
+ .applyTo(context)
+ Access.registerMySQL(context)
+ context.refresh()
+
+ assertThat(context.getBean(HikariDataSource::class.java).jdbcUrl).isEqualTo(
+ "jdbc:mysql://host:3306/zipkin?autoReconnect=true&useSSL=false&useUnicode=yes&characterEncoding=UTF-8")
+ }
+}