quarkus-operator-sdk icon indicating copy to clipboard operation
quarkus-operator-sdk copied to clipboard

Example for QuarkusTest

Open speedfl opened this issue 3 years ago • 16 comments

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

speedfl avatar Jan 17 '22 10:01 speedfl

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 avatar Jan 18 '22 22:01 scrocquesel

@scrocquesel yes, it might make sense to add such a test indeed. Thank you!

metacosm avatar Jan 19 '22 14:01 metacosm

@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());
    }
}

scrocquesel avatar Jan 19 '22 20:01 scrocquesel

When you write "without running the application", do you mean without starting the operator?

metacosm avatar Jan 19 '22 20:01 metacosm

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, ...

scrocquesel avatar Jan 19 '22 21:01 scrocquesel

What's the issue with running the main method? Not sure I understand what you're trying to achieve…

metacosm avatar Jan 19 '22 21:01 metacosm

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.

scrocquesel avatar Jan 19 '22 21:01 scrocquesel

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.

metacosm avatar Jan 19 '22 21:01 metacosm

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, 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.

scrocquesel avatar Jan 19 '22 21:01 scrocquesel

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 🤷🏼 😅)

metacosm avatar Jan 19 '22 21:01 metacosm

I created a PR with the alternative test style: #198.

metacosm avatar Jan 19 '22 22:01 metacosm

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.

scrocquesel avatar Jan 19 '22 22:01 scrocquesel

I see. I should indeed try to port some more complex example to the extension.

metacosm avatar Jan 19 '22 22:01 metacosm

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

scrocquesel avatar Jan 19 '22 22:01 scrocquesel

Do you think you can finish that effort?

metacosm avatar Jan 20 '22 07:01 metacosm

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.

scrocquesel avatar Aug 12 '22 18:08 scrocquesel