quarkus-operator-sdk
quarkus-operator-sdk copied to clipboard
Example for QuarkusTest
Hello! Do you have an example with quarkus tests such as:
https://github.com/java-operator-sdk/java-operator-sdk/blob/main/sample-operators/tomcat-operator/src/test/java/io/javaoperatorsdk/operator/sample/TomcatOperatorE2E.java
Thanks a lot!
Regards
Hi, I quickly set up a test https://github.com/scrocquesel/quarkus-operator-sdk/commit/6a4ca1a12e657f7fd449e792a2e210f8d6e6a6eb
@metacosm do you want me to make a PR ?
@scrocquesel yes, it might make sense to add such a test indeed. Thank you!
@metacosm do you think it could be possible to only have the reconciler as SUT and unit test the reconcile call ?
Doing integration test with external services could be difficult because mock are not that much dynamic and reaching a stable status for the resource can not be possible all the case. For eg, if the reconcile loop should call a rest client to create an external HTTP resource, it may call a GET to check existence and the POST. Mocking the GET to always return false, is possible but then integration test may loop indefinitely creating something that doesn't exist.
What I would want is to Inject the reconciler in the test class without running the application, like
@WithKubernetesTestServer
@QuarkusTest
public class JokeReconcilerTest {
@InjectMock
@RestClient
JokeService jokeService;
@KubernetesTestServer
KubernetesServer mockServer;
@Inject
JokeReconciler sut;
@Test
void CanReconcile() {
// arange
final JokeModel joke = new JokeModel();
joke.id = 1;
joke.joke = "Hello";
joke.flags = Map.of();
Mockito.when(jokeService.getRandom(eq(Category.Any), anyString(), anyBoolean(), anyString())).thenReturn(joke);
final JokeRequest testRequest = new JokeRequest();
testRequest.setMetadata(new ObjectMetaBuilder()
.withName("myjoke1")
.withNamespace(mockServer.getClient().getNamespace())
.build());
testRequest.setSpec(new JokeRequestSpec());
testRequest.getSpec().setCategory(Category.Any);
// act
var result = sut.reconcile(testRequest, new DefaultContext(null, null, null));
// assert on result
assertThat(result.getResource().getStatus().getState(), equalTo(State.CREATED));
assertFalse(result.getScheduleDelay().isPresent());
}
}
When you write "without running the application", do you mean without starting the operator?
Yes, the code i wrote works but the main is run.
I understand that @QuarkusTest launch the app aside, but if we remove it, we lose all CDI behavior, Mockito integration, ...
What's the issue with running the main method? Not sure I understand what you're trying to achieve…
Testing with PerResourcePollingEventSource for eg could be very difficult and we can't afford having unit tests waiting for time based event to occured. In this case, we can set up the context and call reconcile.
Yes, but you can already call reconcile directly, no?
The only thing would be that we need to provide a TestContext instead of relying on DefaultContext (which probably shouldn't be public). An easily configurable test context could be provided as part of the SDK junit extension.
Yes, but you can already call
reconciledirectly, no?The only thing would be that we need to provide a
TestContextinstead of relying onDefaultContext(which probably shouldn't be public). An easily configurable test context could be provided as part of the SDK junit extension.
Yes, that's true but there is a running instance of the operator and in some circonstances as it use the same kubernetes mock server, it can lead to concurrency issues.
Could you elaborate on how concurrency issues would occur? If nothing else interacts with the mock server during the test, the reconciliation shouldn't be triggered so I'm not sure I'm understanding what the issue is (but then again, I'm starting to get tired so 🤷🏼 😅)
I created a PR with the alternative test style: #198.
Could you elaborate on how concurrency issues would occur? If nothing else interacts with the mock server during the test, the reconciliation shouldn't be triggered so I'm not sure I'm understanding what the issue is (but then again, I'm starting to get tired so 🤷🏼 😅)
I am maybe thinking too much. So, let's try with something else.
Let's say we port the mysql schema operator from JOSDK to QuarkusTest. It has a PerResourcePollingEventSource that needs to connect to a database to get secondary resource state.
For a unit test that only call reconcile, the context is mocked and we don't need the event source to actually run. But the test will fails, because it will tries to run the registered event source and it cannot connect to a non existent database.
If we were doing that with the Tomcat sample, it has an Informer that will trigger the reconcile on the background app when the unit test call reconcile will actually create the secondary ressource on the shared mock kubernetes instance.
I see. I should indeed try to port some more complex example to the extension.
I see. I should indeed try to port some more complex example to the extension.
I was in the middle of something https://github.com/scrocquesel/quarkus-operator-sdk/tree/test/samples
Do you think you can finish that effort?
May be closed, samples are now fully tested, there is ongoing work for a test resource and operator can now be start/stop on demand.