micronaut-projects / micronaut-maven-plugin

Maven plugin to execute Micronaut applications
https://micronaut-projects.github.io/micronaut-maven-plugin/latest/
Apache License 2.0
21 stars 22 forks source link

A new Micronaut project with Maven skips tests #375

Closed mraible closed 2 years ago

mraible commented 2 years ago

For some reason mvn test skips the unit test in a new Micronaut project.

[INFO] --- maven-compiler-plugin:3.10.1:testCompile (default-testCompile) @ app ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/mraible/Downloads/micronaut/target/test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ app ---
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.okta.rest.AppTest
10:03:40.710 [main] INFO  i.m.context.env.DefaultEnvironment - Established active environments: [test]
[WARNING] Tests run: 1, Failures: 0, Errors: 0, Skipped: 1, Time elapsed: 0.517 s - in com.okta.rest.AppTest
[INFO]
[INFO] Results:
[INFO]
[WARNING] Tests run: 1, Failures: 0, Errors: 0, Skipped: 1
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  4.714 s
[INFO] Finished at: 2022-05-11T10:03:41-06:00
[INFO] ------------------------------------------------------------------------

I created the project with:

mn create-app com.okta.rest.app --build maven -f security-jwt -f micronaut-aot
mv app micronaut

Then, I replaced the application.yml with the following contents:

micronaut:
  application:
    name: app
  security:
    enabled: true
    token:
      jwt:
        enabled: true
        claims-validators:
          issuer: https://dev-17700857.okta.com/oauth2/default
        signatures:
          jwks:
            okta:
              url: https://dev-17700857.okta.com/oauth2/default/v1/keys
netty:
  default:
    allocator:
      max-order: 3

The test is as follows:

package com.okta.rest;

import io.micronaut.runtime.EmbeddedApplication;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;

import jakarta.inject.Inject;

@MicronautTest
class AppTest {

    @Inject
    EmbeddedApplication<?> application;

    @Test
    void testItWorks() {
        Assertions.assertTrue(application.isRunning());
    }

}
alvarosanchez commented 2 years ago

I can confirm that this is reproducible when using AOT, but not when not using it.

When it doesn't work, the message in Surefire report is this:

Test is not bean. Either the test does not satisfy requirements defined by @Requires or annotation processing is not enabled. If the latter ensure annotation processing is enabled in your IDE

Surely the reason is something else. Annotation processors are configured. The target/test-classes directory is the same in both cases:

target/test-classes
├── META-INF
│   └── services
│       └── io.micronaut.inject.BeanDefinitionReference
└── com
    └── okta
        └── rest
            ├── $App2Test$Definition$Exec.class
            ├── $App2Test$Definition$Reference.class
            ├── $App2Test$Definition.class
            └── App2Test.class

In both cases, the content of target/test-classes/META-INF/services/io.micronaut.inject.BeanDefinitionReference is the same:

com.okta.rest.$App2Test$Definition$Reference

@melix do you think that the AOT configuration that we provide by default could be causing this? For reference, it's this:

# AOT configuration properties for jar packaging
# Please review carefully the optimizations enabled below
# Check https://micronaut-projects.github.io/micronaut-aot/latest/guide/ for more details

# Caches environment property values: environment properties will be deemed immutable after application startup.
cached.environment.enabled=true

# Precomputes Micronaut configuration property keys from the current environment variables
precompute.environment.properties.enabled=true

# Converts YAML configuration files to Java configuration
yaml.to.java.config.enabled=true

# Scans for service types ahead-of-time, avoiding classpath scanning at startup
serviceloading.jit.enabled = true

# Scans reactive types at build time instead of runtime
scan.reactive.types.enabled=true

# Deduces the environment at build time instead of runtime
deduce.environment.enabled=true

# Checks of existence of some types at build time instead of runtime
known.missing.types.enabled=true

# Precomputes property sources at build time
sealed.property.source.enabled=true

# The list of service types to be scanned (comma separated)
service.types=io.micronaut.context.env.PropertySourceLoader,io.micronaut.inject.BeanConfiguration,io.micronaut.inject.BeanDefinitionReference,io.micronaut.http.HttpRequestFactory,io.micronaut.http.HttpResponseFactory,io.micronaut.core.beans.BeanIntrospectionReference

# A list of types that the AOT analyzer needs to check for existence (comma separated)
known.missing.types.list=io.reactivex.Observable,reactor.core.publisher.Flux,kotlinx.coroutines.flow.Flow,io.reactivex.rxjava3.core.Flowable,io.reactivex.rxjava3.core.Observable,io.reactivex.Single,reactor.core.publisher.Mono,io.reactivex.Maybe,io.reactivex.rxjava3.core.Single,io.reactivex.rxjava3.core.Maybe,io.reactivex.Completable,io.reactivex.rxjava3.core.Completable,io.methvin.watchservice.MacOSXListeningWatchService,io.micronaut.core.async.publisher.CompletableFuturePublisher,io.micronaut.core.async.publisher.Publishers.JustPublisher,io.micronaut.core.async.subscriber.Completable
alvarosanchez commented 2 years ago

Ok, disabling serviceloading.jit.enabled makes it work again.

Is it because the service.types list is wrong?

melix commented 2 years ago

The service type list is correct. I think the problem is different: if AOT is used, then the list of services is hardcoded. Because it happens at compile time after the main source sets are processed, then we only find the production beans. Therefore the test beans are not loaded. Note that it's a difference between Gradle and Maven here: with Gradle the tests are not executed with AOT optimizations, there are always executed without. I'm not sure what we can do here :/

melix commented 2 years ago

I guess one way to fix this would be to run AOT with the production and test classes, but the problem is that you certainly don't want to have the test classes referenced in your production code :thinking:

alvarosanchez commented 2 years ago

Ok, I see.

I'll see if I can skip the AOT analysis if the test phase is being run.