Skip to content

Commit d65f5ba

Browse files
authored
Add tests for Micronaut (via Netty) (#229)
* Add tests for Micronaut (via Netty) Signed-off-by: Pavol Loffay <[email protected]> * Use old version Signed-off-by: Pavol Loffay <[email protected]> * small changes Signed-off-by: Pavol Loffay <[email protected]> * Fix tests Signed-off-by: Pavol Loffay <[email protected]> * Fix Signed-off-by: Pavol Loffay <[email protected]> * gradle changes Signed-off-by: Pavol Loffay <[email protected]> * Fix Signed-off-by: Pavol Loffay <[email protected]> * cleanup Signed-off-by: Pavol Loffay <[email protected]>
1 parent 61dc21c commit d65f5ba

File tree

9 files changed

+355
-58
lines changed

9 files changed

+355
-58
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ List of supported frameworks with additional capabilities:
1818
| [Apache HttpClient](https://hc.apache.org/index.html) | 4.0+ |
1919
| [gRPC](https://github.com/grpc/grpc-java) | 1.5+ |
2020
| [JAX-RS Client](https://javaee.github.io/javaee-spec/javadocs/javax/ws/rs/client/package-summary.html) | 2.0+ |
21+
| [Micronaut](https://micronaut.io/) (via Netty and only server) | 1.0+ |
2122
| [Netty](https://github.com/netty/netty) (only server) | 4.0+ |
2223
| [OkHttp](https://github.com/square/okhttp/) | 3.0+ |
2324
| [Servlet](https://javaee.github.io/javaee-spec/javadocs/javax/servlet/package-summary.html) | 2.3+ |
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
plugins {
2+
`java-library`
3+
}
4+
5+
val versions: Map<String, String> by extra
6+
7+
val micronautVersion = "1.0.0"
8+
val micronaut2Version = "2.2.3"
9+
val micronautTestVersion = "1.0.0"
10+
11+
dependencies {
12+
implementation(project(":instrumentation:netty:netty-4.1"))
13+
implementation("io.opentelemetry.javaagent.instrumentation:opentelemetry-javaagent-netty-4.1:${versions["opentelemetry_java_agent"]}")
14+
15+
testImplementation(project(":testing-common"))
16+
testImplementation("io.micronaut.test:micronaut-test-junit5:${micronautTestVersion}")
17+
testImplementation("io.micronaut:micronaut-http-server-netty:${micronautVersion}")
18+
testImplementation("io.micronaut:micronaut-runtime:${micronautVersion}")
19+
testImplementation("io.micronaut:micronaut-inject:${micronautVersion}")
20+
testAnnotationProcessor("io.micronaut:micronaut-inject-java:${micronautVersion}")
21+
}
22+
23+
/**
24+
* Todo this does not run tests
25+
*/
26+
for (version in listOf(micronautVersion, micronaut2Version)) {
27+
val versionedConfiguration = configurations.create("test_${version}") {
28+
extendsFrom(configurations.testRuntimeClasspath.get())
29+
}
30+
dependencies {
31+
versionedConfiguration(project(":instrumentation:netty:netty-4.1"))
32+
versionedConfiguration("io.opentelemetry.javaagent.instrumentation:opentelemetry-javaagent-netty-4.1:${versions["opentelemetry_java_agent"]}")
33+
versionedConfiguration(project(":testing-common"))
34+
versionedConfiguration("io.micronaut:micronaut-inject-java:${version}")
35+
versionedConfiguration("io.micronaut.test:micronaut-test-junit5:${micronautTestVersion}")
36+
versionedConfiguration("io.micronaut:micronaut-http-server-netty:${version}")
37+
versionedConfiguration("io.micronaut:micronaut-runtime:${version}")
38+
versionedConfiguration("io.micronaut:micronaut-inject:${version}")
39+
}
40+
val versionedTest = task<Test>("test_${version}") {
41+
group = "verification"
42+
testClassesDirs = sourceSets["test"].output.classesDirs
43+
classpath = versionedConfiguration
44+
shouldRunAfter("test")
45+
}
46+
tasks.check { dependsOn(versionedTest) }
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
/*
2+
* Copyright The Hypertrace Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.opentelemetry.javaagent.instrumentation.hypertrace.micronaut;
18+
19+
import io.micronaut.runtime.server.EmbeddedServer;
20+
import io.micronaut.test.annotation.MicronautTest;
21+
import io.opentelemetry.sdk.trace.data.SpanData;
22+
import java.io.IOException;
23+
import java.util.List;
24+
import java.util.concurrent.TimeoutException;
25+
import javax.inject.Inject;
26+
import okhttp3.Request;
27+
import okhttp3.RequestBody;
28+
import okhttp3.Response;
29+
import okio.Buffer;
30+
import org.hypertrace.agent.core.instrumentation.HypertraceSemanticAttributes;
31+
import org.hypertrace.agent.testing.AbstractInstrumenterTest;
32+
import org.junit.jupiter.api.Assertions;
33+
import org.junit.jupiter.api.Test;
34+
35+
@MicronautTest
36+
public class MicronautInstrumentationTest extends AbstractInstrumenterTest {
37+
38+
public static final String REQUEST_HEADER_NAME = "reqheader";
39+
public static final String REQUEST_HEADER_VALUE = "reqheadervalue";
40+
41+
@Inject EmbeddedServer server;
42+
43+
@Test
44+
public void get() throws IOException, TimeoutException, InterruptedException {
45+
Request request =
46+
new Request.Builder()
47+
.url(String.format("http://localhost:%d/get_no_content", server.getPort()))
48+
.header(REQUEST_HEADER_NAME, REQUEST_HEADER_VALUE)
49+
.get()
50+
.build();
51+
52+
try (Response response = httpClient.newCall(request).execute()) {
53+
Assertions.assertEquals(204, response.code());
54+
}
55+
56+
List<List<SpanData>> traces = TEST_WRITER.getTraces();
57+
TEST_WRITER.waitForTraces(1);
58+
Assertions.assertEquals(1, traces.size());
59+
List<SpanData> trace = traces.get(0);
60+
Assertions.assertEquals(1, trace.size());
61+
SpanData spanData = trace.get(0);
62+
63+
Assertions.assertEquals(
64+
REQUEST_HEADER_VALUE,
65+
spanData
66+
.getAttributes()
67+
.get(HypertraceSemanticAttributes.httpRequestHeader(REQUEST_HEADER_NAME)));
68+
Assertions.assertEquals(
69+
TestController.RESPONSE_HEADER_VALUE,
70+
spanData
71+
.getAttributes()
72+
.get(
73+
HypertraceSemanticAttributes.httpResponseHeader(
74+
TestController.RESPONSE_HEADER_NAME)));
75+
Assertions.assertNull(
76+
spanData.getAttributes().get(HypertraceSemanticAttributes.HTTP_REQUEST_BODY));
77+
Assertions.assertNull(
78+
spanData.getAttributes().get(HypertraceSemanticAttributes.HTTP_RESPONSE_BODY));
79+
}
80+
81+
@Test
82+
public void postJson() throws IOException, TimeoutException, InterruptedException {
83+
RequestBody requestBody = requestBody(true, 3000, 75);
84+
Buffer requestBodyBuffer = new Buffer();
85+
requestBody.writeTo(requestBodyBuffer);
86+
String requestBodyStr = new String(requestBodyBuffer.readByteArray());
87+
88+
Request request =
89+
new Request.Builder()
90+
.url(String.format("http://localhost:%d/post", server.getPort()))
91+
.header(REQUEST_HEADER_NAME, REQUEST_HEADER_VALUE)
92+
.header("Transfer-Encoding", "chunked")
93+
.post(requestBody)
94+
.build();
95+
96+
try (Response response = httpClient.newCall(request).execute()) {
97+
Assertions.assertEquals(200, response.code());
98+
Assertions.assertEquals(TestController.RESPONSE_BODY, response.body().string());
99+
}
100+
101+
List<List<SpanData>> traces = TEST_WRITER.getTraces();
102+
TEST_WRITER.waitForTraces(1);
103+
Assertions.assertEquals(1, traces.size());
104+
List<SpanData> trace = traces.get(0);
105+
Assertions.assertEquals(1, trace.size());
106+
SpanData spanData = trace.get(0);
107+
108+
Assertions.assertEquals(
109+
REQUEST_HEADER_VALUE,
110+
spanData
111+
.getAttributes()
112+
.get(HypertraceSemanticAttributes.httpRequestHeader(REQUEST_HEADER_NAME)));
113+
Assertions.assertEquals(
114+
TestController.RESPONSE_HEADER_VALUE,
115+
spanData
116+
.getAttributes()
117+
.get(
118+
HypertraceSemanticAttributes.httpResponseHeader(
119+
TestController.RESPONSE_HEADER_NAME)));
120+
Assertions.assertEquals(
121+
requestBodyStr,
122+
spanData.getAttributes().get(HypertraceSemanticAttributes.HTTP_REQUEST_BODY));
123+
Assertions.assertEquals(
124+
TestController.RESPONSE_BODY,
125+
spanData.getAttributes().get(HypertraceSemanticAttributes.HTTP_RESPONSE_BODY));
126+
}
127+
128+
@Test
129+
public void stream() throws IOException, TimeoutException, InterruptedException {
130+
Request request =
131+
new Request.Builder()
132+
.url(String.format("http://localhost:%d/stream", server.getPort()))
133+
.header(REQUEST_HEADER_NAME, REQUEST_HEADER_VALUE)
134+
.get()
135+
.build();
136+
137+
StringBuilder responseBody = new StringBuilder();
138+
for (String body : TestController.streamBody()) {
139+
responseBody.append(body);
140+
}
141+
142+
try (Response response = httpClient.newCall(request).execute()) {
143+
Assertions.assertEquals(200, response.code());
144+
Assertions.assertEquals(responseBody.toString(), response.body().string());
145+
}
146+
147+
List<List<SpanData>> traces = TEST_WRITER.getTraces();
148+
TEST_WRITER.waitForTraces(1);
149+
Assertions.assertEquals(1, traces.size());
150+
List<SpanData> trace = traces.get(0);
151+
Assertions.assertEquals(1, trace.size());
152+
SpanData spanData = trace.get(0);
153+
154+
Assertions.assertEquals(
155+
REQUEST_HEADER_VALUE,
156+
spanData
157+
.getAttributes()
158+
.get(HypertraceSemanticAttributes.httpRequestHeader(REQUEST_HEADER_NAME)));
159+
Assertions.assertNull(
160+
spanData.getAttributes().get(HypertraceSemanticAttributes.HTTP_REQUEST_BODY));
161+
Assertions.assertEquals(
162+
responseBody.toString(),
163+
spanData.getAttributes().get(HypertraceSemanticAttributes.HTTP_RESPONSE_BODY));
164+
}
165+
166+
@Test
167+
public void blocking() throws IOException, TimeoutException, InterruptedException {
168+
Request request =
169+
new Request.Builder()
170+
.url(String.format("http://localhost:%d/post", server.getPort()))
171+
.header(REQUEST_HEADER_NAME, REQUEST_HEADER_VALUE)
172+
.header("mockblock", "true")
173+
.get()
174+
.build();
175+
176+
try (Response response = httpClient.newCall(request).execute()) {
177+
Assertions.assertEquals(403, response.code());
178+
Assertions.assertTrue(response.body().string().isEmpty());
179+
}
180+
181+
List<List<SpanData>> traces = TEST_WRITER.getTraces();
182+
TEST_WRITER.waitForTraces(1);
183+
Assertions.assertEquals(1, traces.size());
184+
List<SpanData> trace = traces.get(0);
185+
Assertions.assertEquals(1, trace.size());
186+
SpanData spanData = trace.get(0);
187+
188+
Assertions.assertEquals(
189+
REQUEST_HEADER_VALUE,
190+
spanData
191+
.getAttributes()
192+
.get(HypertraceSemanticAttributes.httpRequestHeader(REQUEST_HEADER_NAME)));
193+
Assertions.assertNull(
194+
spanData
195+
.getAttributes()
196+
.get(
197+
HypertraceSemanticAttributes.httpResponseHeader(
198+
TestController.RESPONSE_HEADER_NAME)));
199+
Assertions.assertNull(
200+
spanData.getAttributes().get(HypertraceSemanticAttributes.HTTP_RESPONSE_BODY));
201+
}
202+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright The Hypertrace Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.opentelemetry.javaagent.instrumentation.hypertrace.micronaut;
18+
19+
import io.micronaut.http.HttpResponse;
20+
import io.micronaut.http.HttpStatus;
21+
import io.micronaut.http.MediaType;
22+
import io.micronaut.http.annotation.Body;
23+
import io.micronaut.http.annotation.Controller;
24+
import io.micronaut.http.annotation.Get;
25+
import io.micronaut.http.annotation.Post;
26+
import io.reactivex.Flowable;
27+
import java.nio.charset.StandardCharsets;
28+
import java.util.ArrayList;
29+
import java.util.List;
30+
31+
@Controller("/")
32+
public class TestController {
33+
34+
static final String RESPONSE_HEADER_NAME = "reqheadername";
35+
static final String RESPONSE_HEADER_VALUE = "reqheadervalue";
36+
static final String RESPONSE_BODY = "{\"key\": \"val\"}";
37+
38+
@Get(uri = "/get_no_content")
39+
public HttpResponse<?> getNoContent() {
40+
return HttpResponse.status(HttpStatus.NO_CONTENT)
41+
.header(RESPONSE_HEADER_NAME, RESPONSE_HEADER_VALUE);
42+
}
43+
44+
@Post(uri = "/post")
45+
public HttpResponse<?> post(@Body String body) {
46+
System.out.printf("Received body: %s", body);
47+
return HttpResponse.status(HttpStatus.OK)
48+
.header(RESPONSE_HEADER_NAME, RESPONSE_HEADER_VALUE)
49+
.characterEncoding(StandardCharsets.US_ASCII)
50+
.contentType(MediaType.APPLICATION_JSON)
51+
.body(RESPONSE_BODY);
52+
}
53+
54+
@Get(value = "/stream", produces = MediaType.APPLICATION_JSON_STREAM)
55+
public Flowable<String> stream() {
56+
return Flowable.fromIterable(streamBody());
57+
}
58+
59+
static List<String> streamBody() {
60+
List<String> entities = new ArrayList<>();
61+
for (int i = 0; i < 1000; i++) {
62+
entities.add(
63+
String.format(
64+
"dog,cats,foo,bar,dog,cats,foo,bar,dog,cats,foo,bar,dog,cats,foo,bar,dog,cats,foo,bar=%d\n",
65+
i));
66+
}
67+
return entities;
68+
}
69+
}

instrumentation/netty/netty-4.0/src/test/java/io/opentelemetry/javaagent/instrumentation/hypertrace/netty/v4_0/AbstractNetty40ServerInstrumentationTest.java

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,13 @@
2222

2323
import io.opentelemetry.sdk.trace.data.SpanData;
2424
import java.io.IOException;
25-
import java.util.Arrays;
2625
import java.util.List;
2726
import java.util.concurrent.ExecutionException;
2827
import java.util.concurrent.TimeoutException;
29-
import okhttp3.MediaType;
3028
import okhttp3.Request;
3129
import okhttp3.RequestBody;
3230
import okhttp3.Response;
3331
import okio.Buffer;
34-
import okio.BufferedSink;
3532
import org.hypertrace.agent.core.instrumentation.HypertraceSemanticAttributes;
3633
import org.hypertrace.agent.testing.AbstractInstrumenterTest;
3734
import org.junit.jupiter.api.AfterEach;
@@ -175,28 +172,4 @@ public void blocking() throws IOException, TimeoutException, InterruptedExceptio
175172
.getAttributes()
176173
.get(HypertraceSemanticAttributes.httpResponseHeader(RESPONSE_BODY)));
177174
}
178-
179-
private RequestBody requestBody(final boolean chunked, final long size, final int writeSize) {
180-
final byte[] buffer = new byte[writeSize];
181-
Arrays.fill(buffer, (byte) 'x');
182-
183-
return new RequestBody() {
184-
@Override
185-
public MediaType contentType() {
186-
return MediaType.get("application/json; charset=utf-8");
187-
}
188-
189-
@Override
190-
public long contentLength() throws IOException {
191-
return chunked ? -1L : size;
192-
}
193-
194-
@Override
195-
public void writeTo(BufferedSink sink) throws IOException {
196-
for (int count = 0; count < size; count += writeSize) {
197-
sink.write(buffer, 0, (int) Math.min(size - count, writeSize));
198-
}
199-
}
200-
};
201-
}
202175
}

0 commit comments

Comments
 (0)