Skip to content

Commit c363178

Browse files
committed
Use ContextCustomizerFactory to set up inprocess testing
This is the approach we use in 1.0 and it works better for users because they can still use `@AutoConfigureInProcessTransport` even if the test is not a `@SpringBootTest`.
1 parent 1d976a6 commit c363178

File tree

4 files changed

+155
-101
lines changed

4 files changed

+155
-101
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2025-current the original author or 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+
* https://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+
package org.springframework.grpc.sample;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
20+
import org.junit.jupiter.api.Test;
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
23+
import org.springframework.boot.test.context.SpringBootTest;
24+
import org.springframework.boot.test.context.TestConfiguration;
25+
import org.springframework.context.annotation.Import;
26+
import org.springframework.grpc.sample.GrpcServerSideTests.TestConfig;
27+
import org.springframework.grpc.sample.proto.HelloReply;
28+
import org.springframework.grpc.sample.proto.HelloRequest;
29+
import org.springframework.grpc.sample.proto.SimpleGrpc.SimpleBlockingStub;
30+
import org.springframework.grpc.test.AutoConfigureInProcessTransport;
31+
import org.springframework.test.context.TestPropertySource;
32+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
33+
34+
/**
35+
* A test that doesn't use {@link SpringBootTest @SpringBootTest}, but can still use
36+
* {@link AutoConfigureInProcessTransport @AutoConfigureInProcessTransport} to set up an
37+
* in-process gRPC server for testing.
38+
*/
39+
@TestPropertySource(properties = { "spring.grpc.client.default-channel.address=localhost:9090" })
40+
@SpringJUnitConfig(TestConfig.class)
41+
@AutoConfigureInProcessTransport
42+
public class GrpcServerSideTests {
43+
44+
@Autowired
45+
private SimpleBlockingStub stub;
46+
47+
@Test
48+
void contextLoads() {
49+
HelloRequest request = HelloRequest.newBuilder().setName("Test").build();
50+
HelloReply reply = this.stub.sayHello(request);
51+
assertThat(reply.getMessage()).contains(("Test"));
52+
}
53+
54+
@TestConfiguration
55+
@Import(GrpcServerService.class)
56+
@EnableAutoConfiguration
57+
static class TestConfig {
58+
59+
}
60+
61+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright 2024-present the original author or 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+
* https://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+
package org.springframework.grpc.test;
17+
18+
import java.util.List;
19+
import java.util.Objects;
20+
21+
import org.jspecify.annotations.Nullable;
22+
23+
import org.springframework.boot.test.util.TestPropertyValues;
24+
import org.springframework.context.ConfigurableApplicationContext;
25+
import org.springframework.test.context.ContextConfigurationAttributes;
26+
import org.springframework.test.context.ContextCustomizer;
27+
import org.springframework.test.context.ContextCustomizerFactory;
28+
import org.springframework.test.context.MergedContextConfiguration;
29+
import org.springframework.test.context.TestContextAnnotationUtils;
30+
31+
/**
32+
* {@link ContextCustomizerFactory} that starts an in-process gRPC server and replaces the
33+
* regular server and channel factories (e.g. Netty). The customizer can be disabled via
34+
* the {@link AutoConfigureInProcessTransport} annotation or the
35+
* {@value #ENABLED_PROPERTY} property.
36+
*
37+
* @author Chris Bono
38+
*/
39+
class InProcessTransportContextCustomizerFactory implements ContextCustomizerFactory {
40+
41+
static final String ENABLED_PROPERTY = "spring.grpc.test.inprocess.enabled";
42+
43+
@Override
44+
public ContextCustomizer createContextCustomizer(Class<?> testClass,
45+
List<ContextConfigurationAttributes> configAttributes) {
46+
AutoConfigureInProcessTransport annotation = TestContextAnnotationUtils.findMergedAnnotation(testClass,
47+
AutoConfigureInProcessTransport.class);
48+
return new InProcessTransportContextCustomizer(annotation);
49+
}
50+
51+
private static class InProcessTransportContextCustomizer implements ContextCustomizer {
52+
53+
private final @Nullable AutoConfigureInProcessTransport annotation;
54+
55+
InProcessTransportContextCustomizer(@Nullable AutoConfigureInProcessTransport annotation) {
56+
this.annotation = annotation;
57+
}
58+
59+
@Override
60+
public void customizeContext(ConfigurableApplicationContext context,
61+
MergedContextConfiguration mergedContextConfiguration) {
62+
if (this.annotation == null
63+
|| !context.getEnvironment().getProperty(ENABLED_PROPERTY, Boolean.class, true)) {
64+
return;
65+
}
66+
TestPropertyValues
67+
.of("spring.grpc.test.inprocess.enabled=true", "spring.grpc.client.inprocess.exclusive=true",
68+
"spring.grpc.server.inprocess.exclusive=true")
69+
.applyTo(context);
70+
}
71+
72+
@Override
73+
public boolean equals(@Nullable Object o) {
74+
if (this == o) {
75+
return true;
76+
}
77+
if (o == null || getClass() != o.getClass()) {
78+
return false;
79+
}
80+
InProcessTransportContextCustomizer that = (InProcessTransportContextCustomizer) o;
81+
return Objects.equals(this.annotation, that.annotation);
82+
}
83+
84+
@Override
85+
public int hashCode() {
86+
return Objects.hash(this.annotation);
87+
}
88+
89+
}
90+
91+
}

spring-grpc-test/src/main/java/org/springframework/grpc/test/InProcessTransportEnvironmentPostProcessor.java

Lines changed: 0 additions & 98 deletions
This file was deleted.

spring-grpc-test/src/main/resources/META-INF/spring.factories

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
org.springframework.context.ApplicationContextInitializer=\
33
org.springframework.grpc.test.ServerPortInfoApplicationContextInitializer
44

5-
# Environment Post Processors
6-
org.springframework.boot.env.EnvironmentPostProcessor=\
7-
org.springframework.grpc.test.InProcessTransportEnvironmentPostProcessor
5+
# Spring Test Context Customizer Factories
6+
org.springframework.test.context.ContextCustomizerFactory=\
7+
org.springframework.grpc.test.InProcessTransportContextCustomizerFactory

0 commit comments

Comments
 (0)