Skip to content

Conversation

@andreilisa
Copy link
Contributor

This pull request introduces support for in-process transport for gRPC, facilitating efficient testing of gRPC services within the same process.

@andreilisa andreilisa force-pushed the 7-in-proccess-transport-testing branch from 855d267 to 296653e Compare November 1, 2024 15:42
Comment on lines 70 to 75
public static void shutdown() {
if (grpcChannel != null)
grpcChannel.shutdownNow();
if (grpcServer != null)
grpcServer.shutdownNow();
}
Copy link

@vuhp vuhp Nov 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe users should not have to call to startup or should down from their test classes.
Instead, we can leverage a post-processor to handle the shutdown process.

I think this TestcontainersLifecycleApplicationContextInitializer is a good reference

Copy link
Contributor Author

@andreilisa andreilisa Nov 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I am agree with you about this point, and also I think that an ApplicationListener on ContextClosedEvent achieves the purpose of not requiring users to manually handle the lifecycle, specifically shutdown.

@andreilisa andreilisa force-pushed the 7-in-proccess-transport-testing branch from ced3c2d to 296653e Compare November 9, 2024 10:18
@dsyer
Copy link
Member

dsyer commented Nov 9, 2024

Thanks for the fixes. I'm still waiting for spring.grpc.inprocess to be spring.grpc.inprocess.enabled. And if it's in the json metadata, it should really be an Environment property, not just a System property? Is that a problem (it might be that the Environment is not initialized in time)?

I think we should have a sample test as well. The existing samples should now be enabling this by default? So we could slip one in there.

@andreilisa
Copy link
Contributor Author

@dsyer I changed the property to spring.grpc.inprocess.enabled and for the metadata, I wasn’t entirely sure it was the best fit for this case, so I created a custom class that reads the property value directly from application.properties. If it’s not set, it defaults to true. This approach avoids potential issues with system properties and ensures that the environment is properly initialized before accessing the value. The tests I've written validate that these changes work as expected.

@andreilisa andreilisa requested a review from vuhp November 9, 2024 15:42
@andreilisa andreilisa force-pushed the 7-in-proccess-transport-testing branch from a107df3 to cfb847c Compare November 9, 2024 15:43

@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
GrpcProperties grpcProperties = new GrpcProperties(applicationContext.getEnvironment());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I don't think class GrpcProperties is necessary

@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
GrpcProperties grpcProperties = new GrpcProperties(applicationContext.getEnvironment());
if (grpcProperties.isInProcessEnabled() && isJarOnClasspath()) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could check the reversed conditions and return early

}
}

private boolean isJarOnClasspath() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider re-use existing method ClassUtils.isPresent

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;

class InProcessApplicationContextInitializerTests {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this test class be in spring-grpc-test module instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It depends if the test jar depends on Spring Boot or not. I'm happy for it to be here for now anyway -it could also be a nested class inside the existing GrpcServerIntegrationTests (which I see below you already have, so maybe we don't need this one at all?).

@dsyer
Copy link
Member

dsyer commented Nov 9, 2024

@dsyer I changed the property to spring.grpc.inprocess.enabled and for the metadata, I wasn’t entirely sure it was the best fit for this case, so I created a custom class that reads the property value directly from application.properties.

I’m not sure I like the sound of that. There’s nothing like it in the whole Spring Boot ecosystem as far as I know. Did you try it in a sample and it wasn’t available in a test?

@andreilisa
Copy link
Contributor Author

@dsyer I changed the property to spring.grpc.inprocess.enabled and for the metadata, I wasn’t entirely sure it was the best fit for this case, so I created a custom class that reads the property value directly from application.properties.

I’m not sure I like the sound of that. There’s nothing like it in the whole Spring Boot ecosystem as far as I know. Did you try it in a sample and it wasn’t available in a test?

I haven't tried it in a sample yet, let me try it and I will do the changes(using metadata file for this property) to match the ecosystem pattern as well.

@andreilisa andreilisa force-pushed the 7-in-proccess-transport-testing branch from cfb847c to 4493635 Compare November 11, 2024 15:58
@andreilisa
Copy link
Contributor Author

andreilisa commented Nov 11, 2024

Hello, @dsyer can you please check one more time the changes ? Now the PR should look better.
About this point: "The existing samples should now be enabling this by default. So we could slip one in there."
I'm not sure how the test class should be structured because I have the property configured individually for each test.

@dsyer
Copy link
Member

dsyer commented Nov 11, 2024

I added a couple more comments. If you could squash and rebase that will help as well, please.

@andreilisa
Copy link
Contributor Author

I added a couple more comments. If you could squash and rebase that will help as well, please.

I cannot see your comments

/*
* @author Andrei Lisa
*/
public class InProcessApplicationContextInitializer
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a special reason this is an ApplicationContextInitializer? What is the expected usage? I was sort of hoping that a user would be able to easily write an integration test that uses the in-process channel instead of the tcp one. Doesn't that mean we should make it look as much like the existing GrpcServerLifecycle pattern?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe ApplicationContextInitializer is a better fit here, as it allows us to set up a simple in-process channel builder directly at application startup and ensures that it’s automatically shut down when the process ends. This approach keeps things lightweight and aligns well with the purpose of the in-process channel, as we don’t need the full lifecycle management that GrpcServerLifecycle provides.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree, and I'm not really sure I want to merge this yet. It works up to a point, but it doesn't stop the tcp server starting, which feels odd to me (I was hoping for a drop in replacement). It's also an unusual way to implement this kind of feature, and I'm not convinced it won't create problems down the road. Looking at the test containers support was a good suggestion, so I'd like to understand what we are missing there before we do anything else here.

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;

class InProcessApplicationContextInitializerTests {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It depends if the test jar depends on Spring Boot or not. I'm happy for it to be here for now anyway -it could also be a nested class inside the existing GrpcServerIntegrationTests (which I see below you already have, so maybe we don't need this one at all?).


@Nested
@SpringBootTest(properties = { "spring.grpc.server.host=0.0.0.0", "spring.grpc.server.port=0",
"spring.grpc.inprocess.enabled=true" })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same test as WithInProcessEnabled? Probably we can just have one (and not set the property - just use the default).

try {
String serverName = InProcessServerBuilder.generateName();

Server grpcServer = InProcessServerBuilder.forName(serverName).directExecutor().build().start();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are starting this server without registering any services. This is a bug, and it should have had a test. Feels like maybe a sign that we would be better sticking more closely to the GrpcServerFactory pattern. I'm still open to not doing that, but there has to be a test, and the services have to get registered, at a minimum. What about interceptors? They probably need to get registered as well (maybe with exceptions for testing).

Copy link
Contributor Author

@andreilisa andreilisa Nov 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are right and also I’m aware of the missing service registration and encountered the same issue in testing. I agree that this indicates a need to align more closely with the GrpcServerFactory pattern, especially for consistency in managing service and interceptor registration. At a minimum, I’ll ensure that services are properly registered and that we have a test to validate this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dsyer Can you please check the changes again ? II implemented a factory for the in-process channel that now ensures the correct registration of services, which resolves the bugs we encountered earlier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dsyer Hello, what do think about this PR ?

@andreilisa andreilisa requested review from dsyer and vuhp November 13, 2024 16:38
@dsyer
Copy link
Member

dsyer commented Nov 19, 2024

Closing in favour of 2df6c37.

@dsyer dsyer closed this Nov 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants