Skip to content

Commit 7874861

Browse files
committed
Add cancelled client call metrics test (preview)
1 parent aa286ab commit 7874861

File tree

6 files changed

+153
-13
lines changed

6 files changed

+153
-13
lines changed

tests/src/test/java/net/devh/boot/grpc/test/metric/MetricCollectingClientInterceptorTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
class MetricCollectingClientInterceptorTest {
4040

4141
@Test
42-
public void testClientPreRegistration() {
42+
void testClientPreRegistration() {
4343
log.info("--- Starting tests with client pre-registration ---");
4444
final MeterRegistry meterRegistry = new SimpleMeterRegistry();
4545
assertEquals(0, meterRegistry.getMeters().size());
@@ -52,7 +52,7 @@ public void testClientPreRegistration() {
5252
}
5353

5454
@Test
55-
public void testClientCustomization() {
55+
void testClientCustomization() {
5656
log.info("--- Starting tests with client customization ---");
5757
final MeterRegistry meterRegistry = new SimpleMeterRegistry();
5858
assertEquals(0, meterRegistry.getMeters().size());

tests/src/test/java/net/devh/boot/grpc/test/metric/MetricCollectingInterceptorTest.java

Lines changed: 138 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package net.devh.boot.grpc.test.metric;
1919

20+
import static io.grpc.Status.Code.CANCELLED;
2021
import static io.grpc.Status.Code.UNIMPLEMENTED;
2122
import static net.devh.boot.grpc.common.metric.MetricConstants.METRIC_NAME_CLIENT_PROCESSING_DURATION;
2223
import static net.devh.boot.grpc.common.metric.MetricConstants.METRIC_NAME_CLIENT_REQUESTS_SENT;
@@ -26,14 +27,22 @@
2627
import static net.devh.boot.grpc.common.metric.MetricConstants.METRIC_NAME_SERVER_RESPONSES_SENT;
2728
import static net.devh.boot.grpc.common.metric.MetricConstants.TAG_METHOD_NAME;
2829
import static net.devh.boot.grpc.common.metric.MetricConstants.TAG_STATUS_CODE;
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
2932
import static org.junit.jupiter.api.Assertions.assertEquals;
3033
import static org.junit.jupiter.api.Assertions.assertNotNull;
3134
import static org.junit.jupiter.api.Assertions.assertThrows;
35+
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
3236
import static org.junit.jupiter.api.Assertions.assertTrue;
37+
import static org.junit.jupiter.api.Assertions.fail;
3338

39+
import java.time.Duration;
40+
import java.util.concurrent.CountDownLatch;
3441
import java.util.concurrent.TimeUnit;
42+
import java.util.concurrent.atomic.AtomicReference;
3543

3644
import org.junit.jupiter.api.Test;
45+
import org.junit.jupiter.api.function.Executable;
3746
import org.springframework.beans.factory.annotation.Autowired;
3847
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
3948
import org.springframework.boot.test.context.SpringBootTest;
@@ -43,6 +52,8 @@
4352
import com.google.protobuf.Empty;
4453

4554
import io.grpc.StatusRuntimeException;
55+
import io.grpc.stub.ClientCallStreamObserver;
56+
import io.grpc.stub.StreamObserver;
4657
import io.micrometer.core.instrument.Counter;
4758
import io.micrometer.core.instrument.Meter;
4859
import io.micrometer.core.instrument.MeterRegistry;
@@ -55,7 +66,9 @@
5566
import net.devh.boot.grpc.test.config.BaseAutoConfiguration;
5667
import net.devh.boot.grpc.test.config.MetricConfiguration;
5768
import net.devh.boot.grpc.test.config.ServiceConfiguration;
69+
import net.devh.boot.grpc.test.proto.SomeType;
5870
import net.devh.boot.grpc.test.proto.TestServiceGrpc.TestServiceBlockingStub;
71+
import net.devh.boot.grpc.test.proto.TestServiceGrpc.TestServiceStub;
5972

6073
/**
6174
* A full test with Spring for both the server side and the client side interceptors.
@@ -70,23 +83,28 @@
7083
@SpringJUnitConfig(classes = {MetricConfiguration.class, ServiceConfiguration.class, BaseAutoConfiguration.class})
7184
@ImportAutoConfiguration({GrpcClientMetricAutoConfiguration.class, GrpcServerMetricAutoConfiguration.class})
7285
@DirtiesContext
73-
public class MetricCollectingInterceptorTest {
86+
class MetricCollectingInterceptorTest {
87+
88+
private static final Empty EMPTY = Empty.getDefaultInstance();
7489

7590
@Autowired
7691
private MeterRegistry meterRegistry;
7792

7893
@GrpcClient("test")
7994
private TestServiceBlockingStub testService;
8095

96+
@GrpcClient("test")
97+
private TestServiceStub testStreamService;
98+
8199
/**
82100
* Test successful call.
83101
*/
84102
@Test
85103
@DirtiesContext
86-
public void testMetricsSuccessfulCall() {
104+
void testMetricsSuccessfulCall() {
87105
log.info("--- Starting tests with successful call ---");
88106
// Invoke 1
89-
assertEquals("1.2.3", this.testService.normal(Empty.getDefaultInstance()).getVersion());
107+
assertEquals("1.2.3", this.testService.normal(EMPTY).getVersion());
90108

91109
// Test-Client 1
92110
final Counter requestSentCounter =
@@ -137,7 +155,7 @@ public void testMetricsSuccessfulCall() {
137155
// --------------------------------------------------------------------
138156

139157
// Invoke 2
140-
assertEquals("1.2.3", this.testService.normal(Empty.getDefaultInstance()).getVersion());
158+
assertEquals("1.2.3", this.testService.normal(EMPTY).getVersion());
141159

142160
// Test-Client 2
143161
assertEquals(2, requestSentCounter.count());
@@ -156,16 +174,130 @@ public void testMetricsSuccessfulCall() {
156174
log.info("--- Test completed ---");
157175
}
158176

177+
/**
178+
* Test cancelled call.
179+
*/
180+
@Test
181+
@DirtiesContext
182+
void testMetricsCancelledCall() {
183+
log.info("--- Starting tests with cancelled call ---");
184+
final AtomicReference<Throwable> exception = new AtomicReference<>();
185+
final CountDownLatch counter = new CountDownLatch(1);
186+
187+
// Invoke
188+
final ClientCallStreamObserver<SomeType> observer =
189+
(ClientCallStreamObserver<SomeType>) this.testStreamService.echo(new StreamObserver<SomeType>() {
190+
191+
@Override
192+
public void onNext(final SomeType value) {
193+
try {
194+
fail("Should never be here");
195+
} catch (final RuntimeException t) {
196+
setError(t);
197+
throw t;
198+
}
199+
}
200+
201+
@Override
202+
public void onError(final Throwable t) {
203+
setError(t);
204+
counter.countDown();
205+
}
206+
207+
@Override
208+
public void onCompleted() {
209+
try {
210+
fail("Should never be here");
211+
} catch (final RuntimeException t) {
212+
setError(t);
213+
counter.countDown();
214+
throw t;
215+
}
216+
}
217+
218+
private synchronized void setError(final Throwable t) {
219+
final Throwable previous = exception.get();
220+
if (previous == null) {
221+
exception.set(t);
222+
} else {
223+
previous.addSuppressed(t);
224+
}
225+
}
226+
227+
});
228+
229+
assertDoesNotThrow(() -> counter.await(1, TimeUnit.SECONDS));
230+
231+
observer.cancel("Cancelled", null);
232+
assertTimeoutPreemptively(Duration.ofSeconds(3), (Executable) counter::await);
233+
assertThat(exception.get())
234+
.isNotNull()
235+
.isInstanceOfSatisfying(StatusRuntimeException.class,
236+
t -> assertEquals(CANCELLED, t.getStatus().getCode()));
237+
238+
// Test-Client
239+
final Counter requestSentCounter = this.meterRegistry
240+
.find(METRIC_NAME_CLIENT_REQUESTS_SENT)
241+
.tag(MetricConstants.TAG_METHOD_NAME, "echo")
242+
.counter();
243+
assertNotNull(requestSentCounter);
244+
assertEquals(1, requestSentCounter.count());
245+
246+
final Counter responseReceivedCounter = this.meterRegistry
247+
.find(METRIC_NAME_CLIENT_RESPONSES_RECEIVED)
248+
.tag(MetricConstants.TAG_METHOD_NAME, "echo")
249+
.counter();
250+
assertNotNull(responseReceivedCounter);
251+
assertEquals(0, responseReceivedCounter.count());
252+
253+
final Timer clientTimer = this.meterRegistry
254+
.find(METRIC_NAME_CLIENT_PROCESSING_DURATION)
255+
.tag(MetricConstants.TAG_METHOD_NAME, "echo")
256+
.tag(TAG_STATUS_CODE, CANCELLED.name())
257+
.timer();
258+
assertNotNull(clientTimer);
259+
assertEquals(1, clientTimer.count());
260+
assertTrue(clientTimer.max(TimeUnit.SECONDS) < 1);
261+
262+
// Test-Server
263+
final Counter requestsReceivedCounter = this.meterRegistry
264+
.find(METRIC_NAME_SERVER_REQUESTS_RECEIVED)
265+
.tag(MetricConstants.TAG_METHOD_NAME, "echo")
266+
.counter();
267+
assertNotNull(requestsReceivedCounter);
268+
assertEquals(1, requestsReceivedCounter.count());
269+
270+
final Counter responsesSentCounter = this.meterRegistry
271+
.find(METRIC_NAME_SERVER_RESPONSES_SENT)
272+
.tag(MetricConstants.TAG_METHOD_NAME, "echo")
273+
.counter();
274+
assertNotNull(responsesSentCounter);
275+
assertEquals(0, responsesSentCounter.count());
276+
277+
final Timer serverTimer = this.meterRegistry
278+
.find(METRIC_NAME_SERVER_PROCESSING_DURATION)
279+
.tag(MetricConstants.TAG_METHOD_NAME, "echo")
280+
.tag(TAG_STATUS_CODE, UNIMPLEMENTED.name())
281+
.timer();
282+
assertNotNull(serverTimer);
283+
assertEquals(1, serverTimer.count());
284+
assertTrue(serverTimer.max(TimeUnit.SECONDS) < 1);
285+
286+
// Client has network overhead so it has to be slower
287+
assertTrue(serverTimer.max(TimeUnit.SECONDS) <= clientTimer.max(TimeUnit.SECONDS));
288+
log.info("--- Test completed ---");
289+
}
290+
159291
/**
160292
* Test failing call.
161293
*/
162294
@Test
163295
@DirtiesContext
164-
public void testMetricsFailingCall() {
296+
void testMetricsFailingCall() {
165297
log.info("--- Starting tests with failing call ---");
166298
// Invoke
167299
assertThrows(StatusRuntimeException.class,
168-
() -> this.testService.unimplemented(Empty.getDefaultInstance()).getVersion());
300+
() -> this.testService.unimplemented(EMPTY));
169301

170302
// Test-Client
171303
final Counter requestSentCounter = this.meterRegistry

tests/src/test/java/net/devh/boot/grpc/test/metric/MetricCollectingServerInterceptorTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
class MetricCollectingServerInterceptorTest {
4141

4242
@Test
43-
public void testServerPreRegistration() {
43+
void testServerPreRegistration() {
4444
log.info("--- Starting tests with server pre-registration ---");
4545
final MeterRegistry meterRegistry = new SimpleMeterRegistry();
4646
assertEquals(0, meterRegistry.getMeters().size());
@@ -53,7 +53,7 @@ public void testServerPreRegistration() {
5353
}
5454

5555
@Test
56-
public void testServerCustomization() {
56+
void testServerCustomization() {
5757
log.info("--- Starting tests with server customization ---");
5858
final MeterRegistry meterRegistry = new SimpleMeterRegistry();
5959
assertEquals(0, meterRegistry.getMeters().size());

tests/src/test/java/net/devh/boot/grpc/test/metric/MetricFullAutoConfigurationTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@
4343
@SpringJUnitConfig(classes = ServiceConfiguration.class)
4444
@EnableAutoConfiguration
4545
@DirtiesContext
46-
public class MetricFullAutoConfigurationTest {
46+
class MetricFullAutoConfigurationTest {
4747

4848
@Autowired
4949
private MeterRegistry meterRegistry;
5050

5151
@Test
5252
@DirtiesContext
53-
public void testAutoDiscovery() {
53+
void testAutoDiscovery() {
5454
log.info("--- Starting tests with full auto discovery ---");
5555
assertEquals(METHOD_COUNT * 2, this.meterRegistry.getMeters().stream()
5656
.filter(Counter.class::isInstance)

tests/src/test/java/net/devh/boot/grpc/test/server/TestServiceImpl.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
@GrpcService
4242
public class TestServiceImpl extends TestServiceImplBase {
4343

44-
public static final int METHOD_COUNT = 6;
44+
public static final int METHOD_COUNT = 7;
4545

4646
public TestServiceImpl() {
4747
log.info("Created TestServiceImpl");
@@ -62,6 +62,11 @@ public void unimplemented(final Empty request, final StreamObserver<SomeType> re
6262
super.unimplemented(request, responseObserver);
6363
}
6464

65+
@Override
66+
public StreamObserver<SomeType> echo(StreamObserver<SomeType> responseObserver) {
67+
return responseObserver;
68+
}
69+
6570
@Override
6671
@Secured("ROLE_CLIENT1")
6772
public void secure(final Empty request, final StreamObserver<SomeType> responseObserver) {

tests/src/test/proto/TestService.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ service TestService {
1414
// Unimplemented method
1515
rpc unimplemented(google.protobuf.Empty) returns (SomeType) {}
1616

17+
// Returns the incoming requests as is.
18+
rpc echo(stream SomeType) returns (stream SomeType) {}
19+
1720
// Secured method
1821
rpc secure(google.protobuf.Empty) returns (SomeType) {}
1922

0 commit comments

Comments
 (0)