<commit_before>/*
 * Copyright 2013-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.cloud.sleuth.annotation;

import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;

import brave.Tracer;
import brave.sampler.Sampler;
import org.apache.commons.lang3.StringUtils;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import zipkin2.Span;
import zipkin2.reporter.Reporter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.trace.http.HttpTrace;
import org.springframework.boot.actuate.trace.http.HttpTraceRepository;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.cloud.sleuth.DisableWebFluxSecurity;
import org.springframework.cloud.sleuth.util.ArrayListSpanReporter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;

import static org.assertj.core.api.BDDAssertions.then;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(properties = { "spring.main.web-application-type=reactive" }, classes = {
		SleuthSpanCreatorAspectWebFluxTests.TestEndpoint.class,
		SleuthSpanCreatorAspectWebFluxTests.TestConfiguration.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SleuthSpanCreatorAspectWebFluxTests {

	private static final ConcurrentLinkedQueue<Long> spanIdsInHttpTrace = new ConcurrentLinkedQueue<>();

	private final WebClient webClient = WebClient.create();

	@Autowired
	Tracer tracer;

	@Autowired
	ArrayListSpanReporter reporter;

	@LocalServerPort
	private int port;

	private static String toHexString(long value) {
		return StringUtils.leftPad(Long.toHexString(value), 16, '0');
	}

	@Before
	public void setup() {
		this.reporter.clear();
		spanIdsInHttpTrace.clear();
	}

	@Test
	public void shouldReturnSpanFromWebFluxTraceContext() {

		Mono<Long> mono = webClient.get().uri("http://localhost:" + port + "/test/ping")
				.retrieve().bodyToMono(Long.class);

		then(this.reporter.getSpans()).isEmpty();

		Long newSpanId = mono.block();

		List<zipkin2.Span> spans = this.reporter.getSpans();
		then(spans).hasSize(1);
		then(spans.get(0).kind()).isEqualTo(Span.Kind.SERVER);
		then(spans.get(0).name()).isEqualTo("get /test/ping");
		then(spans.get(0).id()).isEqualTo(toHexString(newSpanId));
		then(this.tracer.currentSpan()).isNull();
	}

	@Test
	public void shouldReturnSpanFromWebFluxSubscriptionContext() {

		Mono<Long> mono = webClient.get()
				.uri("http://localhost:" + port + "/test/pingFromContext").retrieve()
				.bodyToMono(Long.class);

		then(this.reporter.getSpans()).isEmpty();

		Long newSpanId = mono.block();

		List<zipkin2.Span> spans = this.reporter.getSpans();
		then(spans).hasSize(1);
		then(spans.get(0).kind()).isEqualTo(Span.Kind.SERVER);
		then(spans.get(0).name()).isEqualTo("get /test/pingfromcontext");
		then(spans.get(0).id()).isEqualTo(toHexString(newSpanId));
		then(this.tracer.currentSpan()).isNull();
	}

	@Test
	public void shouldContinueSpanInWebFlux() {

		Mono<Long> mono = webClient.get()
				.uri("http://localhost:" + port + "/test/continueSpan").retrieve()
				.bodyToMono(Long.class);

		then(this.reporter.getSpans()).isEmpty();

		Long newSpanId = mono.block();

		List<zipkin2.Span> spans = this.reporter.getSpans();
		then(spans).hasSize(1);
		then(spans.get(0).kind()).isEqualTo(Span.Kind.SERVER);
		then(spans.get(0).name()).isEqualTo("get /test/continuespan");
		then(spans.get(0).id()).isEqualTo(toHexString(newSpanId));
		then(this.tracer.currentSpan()).isNull();
	}

	@Test
	public void shouldCreateNewSpanInWebFlux() {

		Mono<Long> mono = webClient.get()
				.uri("http://localhost:" + port + "/test/newSpan1").retrieve()
				.bodyToMono(Long.class);

		then(this.reporter.getSpans()).isEmpty();

		Long newSpanId = mono.block();

		List<zipkin2.Span> spans = this.reporter.getSpans();
		then(spans).hasSize(2);
		then(spans.get(0).name()).isEqualTo("new-span-in-trace-context");
		then(spans.get(0).id()).isEqualTo(toHexString(newSpanId));
		then(spans.get(1).kind()).isEqualTo(Span.Kind.SERVER);
		then(spans.get(1).name()).isEqualTo("get /test/newspan1");
		then(this.tracer.currentSpan()).isNull();
	}

	@Test
	public void shouldCreateNewSpanInWebFluxInSubscriberContext() {

		Mono<Long> mono = webClient.get()
				.uri("http://localhost:" + port + "/test/newSpan2").retrieve()
				.bodyToMono(Long.class);

		then(this.reporter.getSpans()).isEmpty();

		Long newSpanId = mono.block();

		List<zipkin2.Span> spans = this.reporter.getSpans();
		then(spans).hasSize(2);
		then(spans.get(0).name()).isEqualTo("new-span-in-subscriber-context");
		then(spans.get(0).id()).isEqualTo(toHexString(newSpanId));
		then(spans.get(1).kind()).isEqualTo(Span.Kind.SERVER);
		then(spans.get(1).name()).isEqualTo("get /test/newspan2");
		then(this.tracer.currentSpan()).isNull();
	}

	// TODO: Fix me
	@Test
	@Ignore("The order with HttpTraceWebFilter has changed in Boot")
	public void shouldSetupCorrectSpanInHttpTrace() {

		spanIdsInHttpTrace.clear();

		Mono<Long> mono = webClient.get().uri("http://localhost:" + port + "/test/ping")
				.retrieve().bodyToMono(Long.class);

		then(this.reporter.getSpans()).isEmpty();

		Long newSpanId = mono.block();

		List<zipkin2.Span> spans = this.reporter.getSpans();
		then(spans).hasSize(1);
		then(spans.get(0).kind()).isEqualTo(Span.Kind.SERVER);
		then(spans.get(0).name()).isEqualTo("get /test/ping");
		then(spans.get(0).id()).isEqualTo(toHexString(newSpanId))
				.isEqualTo(toHexString(spanIdsInHttpTrace.poll()));
		then(this.tracer.currentSpan()).isNull();
	}

	@Configuration
	@EnableAutoConfiguration
	@DisableWebFluxSecurity
	protected static class TestConfiguration {

		@Bean
		TestBean testBean(Tracer tracer) {
			return new TestBean(tracer);<commit_msg>Moar logging<commit_after>/*
 * Copyright 2013-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.cloud.sleuth.annotation;

import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;

import brave.Tracer;
import brave.sampler.Sampler;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import zipkin2.Span;
import zipkin2.reporter.Reporter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.trace.http.HttpTrace;
import org.springframework.boot.actuate.trace.http.HttpTraceRepository;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.cloud.sleuth.DisableWebFluxSecurity;
import org.springframework.cloud.sleuth.util.ArrayListSpanReporter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;

import static org.assertj.core.api.BDDAssertions.then;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(properties = { "spring.main.web-application-type=reactive" }, classes = {
		SleuthSpanCreatorAspectWebFluxTests.TestEndpoint.class,
		SleuthSpanCreatorAspectWebFluxTests.TestConfiguration.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SleuthSpanCreatorAspectWebFluxTests {

	private static final Log log = LogFactory.getLog(SleuthSpanCreatorAspectWebFluxTests.class);

	private static final ConcurrentLinkedQueue<Long> spanIdsInHttpTrace = new ConcurrentLinkedQueue<>();

	private final WebClient webClient = WebClient.create();

	@Autowired
	Tracer tracer;

	@Autowired
	ArrayListSpanReporter reporter;

	@LocalServerPort
	private int port;

	private static String toHexString(long value) {
		return StringUtils.leftPad(Long.toHexString(value), 16, '0');
	}

	@Before
	public void setup() {
		this.reporter.clear();
		spanIdsInHttpTrace.clear();
	}

	@Test
	public void shouldReturnSpanFromWebFluxTraceContext() {
		Mono<Long> mono = webClient.get().uri("http://localhost:" + port + "/test/ping")
				.retrieve().bodyToMono(Long.class);

		then(this.reporter.getSpans()).isEmpty();

		Long newSpanId = mono.block();

		List<zipkin2.Span> spans = getSpans();
		then(spans).hasSize(1);
		then(spans.get(0).kind()).isEqualTo(Span.Kind.SERVER);
		then(spans.get(0).name()).isEqualTo("get /test/ping");
		then(spans.get(0).id()).isEqualTo(toHexString(newSpanId));
		then(this.tracer.currentSpan()).isNull();
	}

	private List<zipkin2.Span> getSpans() {
		List<zipkin2.Span> spans = this.reporter.getSpans();
		log.info("Reported the following spans: \n\n" + spans);
		return spans;
	}

	@Test
	public void shouldReturnSpanFromWebFluxSubscriptionContext() {

		Mono<Long> mono = webClient.get()
				.uri("http://localhost:" + port + "/test/pingFromContext").retrieve()
				.bodyToMono(Long.class);

		then(this.reporter.getSpans()).isEmpty();

		Long newSpanId = mono.block();

		List<zipkin2.Span> spans = getSpans();
		then(spans).hasSize(1);
		then(spans.get(0).kind()).isEqualTo(Span.Kind.SERVER);
		then(spans.get(0).name()).isEqualTo("get /test/pingfromcontext");
		then(spans.get(0).id()).isEqualTo(toHexString(newSpanId));
		then(this.tracer.currentSpan()).isNull();
	}

	@Test
	public void shouldContinueSpanInWebFlux() {

		Mono<Long> mono = webClient.get()
				.uri("http://localhost:" + port + "/test/continueSpan").retrieve()
				.bodyToMono(Long.class);

		then(this.reporter.getSpans()).isEmpty();

		Long newSpanId = mono.block();

		List<zipkin2.Span> spans = getSpans();
		then(spans).hasSize(1);
		then(spans.get(0).kind()).isEqualTo(Span.Kind.SERVER);
		then(spans.get(0).name()).isEqualTo("get /test/continuespan");
		then(spans.get(0).id()).isEqualTo(toHexString(newSpanId));
		then(this.tracer.currentSpan()).isNull();
	}

	@Test
	public void shouldCreateNewSpanInWebFlux() {

		Mono<Long> mono = webClient.get()
				.uri("http://localhost:" + port + "/test/newSpan1").retrieve()
				.bodyToMono(Long.class);

		then(this.reporter.getSpans()).isEmpty();

		Long newSpanId = mono.block();

		List<zipkin2.Span> spans = getSpans();
		then(spans).hasSize(2);
		then(spans.get(0).name()).isEqualTo("new-span-in-trace-context");
		then(spans.get(0).id()).isEqualTo(toHexString(newSpanId));
		then(spans.get(1).kind()).isEqualTo(Span.Kind.SERVER);
		then(spans.get(1).name()).isEqualTo("get /test/newspan1");
		then(this.tracer.currentSpan()).isNull();
	}

	@Test
	public void shouldCreateNewSpanInWebFluxInSubscriberContext() {

		Mono<Long> mono = webClient.get()
				.uri("http://localhost:" + port + "/test/newSpan2").retrieve()
				.bodyToMono(Long.class);

		then(this.reporter.getSpans()).isEmpty();

		Long newSpanId = mono.block();

		List<zipkin2.Span> spans = getSpans();
		then(spans).hasSize(2);
		then(spans.get(0).name()).isEqualTo("new-span-in-subscriber-context");
		then(spans.get(0).id()).isEqualTo(toHexString(newSpanId));
		then(spans.get(1).kind()).isEqualTo(Span.Kind.SERVER);
		then(spans.get(1).name()).isEqualTo("get /test/newspan2");
		then(this.tracer.currentSpan()).isNull();
	}

	// TODO: Fix me
	@Test
	@Ignore("The order with HttpTraceWebFilter has changed in Boot")
	public void shouldSetupCorrectSpanInHttpTrace() {

		spanIdsInHttpTrace.clear();

		Mono<Long> mono = webClient.get().uri("http://localhost:" + port + "/test/ping")
				.retrieve().bodyToMono(Long.class);

		then(this.reporter.getSpans()).isEmpty();

		Long newSpanId = mono.block();

		List<zipkin2.Span> spans = getSpans();
		then(spans).hasSize(1);
		then(spans.get(0).kind()).isEqualTo(Span.Kind.SERVER);
		then(spans.get(0).name()).isEqualTo("get /test/ping");
		then(spans.get(0).id()).isEqualTo(toHexString(newSpanId))
				.isEqualTo(toHexString(spanIdsInHttpTrace.poll()));
		then(this.tracer.currentSpan()).isNull();
	}

	@Configuration
	@EnableAutoConfiguration
	@DisableWebFluxSecurity
	protected static class TestConfiguration {

		@Bean
		TestBean testBean(Tracer tracer) {
			return new TestBean(tracer);
{'fraction_non_alphanumeric': 0.14905130007027406, 'fraction_numerical': 0.008432888264230498, 'mean_word_length': 5.445199275362318, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '686359', 'n_tokens_mistral': 4958, 'n_tokens_neox': 4661, 'n_words': 760}