I'm having an issue testing a controller but I haven't been able to reproduce the problem in a simple application. When I run the app, it works fine.
I have a controller:
public interface HomeOperations {
@Post // Micronaut's Post
HttpResponse<TheResponse> create(@NotNull @Valid @Body TheCommand command);
}
@Controller("/home")
@Secured("user")
@RequiredArgsConstructor // lombok
@Validated
public class HomeController implements HomeOperations {
@Override
@SneakyThrows // lombok
@ExecuteOn(TaskExecutors.IO)
public HttpResponse<TheResponse> create(@NotNull @Valid @Body TheCommand command) {
return HttpResponse.ok(...);
}
}
Notice that the @Post
annotation is in the interface.
The problem with this controller is that the route POST /home
is not being matched. I found that the problem is in AnnotatedMethodRouteBuilder#process(BeanDefinition<?> definition, ExecutableMethod<?, ?> method)
---method
does not have an HTTP mapping (i.e., ultimately @Post
).
This is the output of the failing test:
12:51:39.828 [nioEventLoopGroup-1-4] DEBUG DefaultTokenResolver - Request POST, /home, no token found.
12:51:39.833 [nioEventLoopGroup-1-4] DEBUG Authenticator - com.example.controllers.DummyAuthenticationProvider
12:51:39.835 [nioEventLoopGroup-1-4] INFO DummyAuthenticationProvider - Successful dummy login [user]
12:51:39.904 [nioEventLoopGroup-1-4] DEBUG SecurityFilter - Attributes: roles=>[user], username=>880f1a24-4997-40a6-bbf1-dde1f3871451
12:51:39.905 [nioEventLoopGroup-1-4] DEBUG InterceptUrlMapRule - One or more of the IP patterns matched the host address [127.0.0.1]. Continuing request processing.
12:51:39.908 [nioEventLoopGroup-1-4] DEBUG InterceptUrlMapRule - No url map pattern exact match found for path [/home] and method [POST]. Searching in patterns with no defined method.
12:51:39.909 [nioEventLoopGroup-1-4] DEBUG InterceptUrlMapRule - No url map pattern match found for path [/home]. Returning unknown.
12:51:39.910 [nioEventLoopGroup-1-4] DEBUG SecurityFilter - Authorized request POST /home. No rule provider authorized or rejected the request.
ControllerServerTest > testRegisterEntity() FAILED
io.micronaut.http.client.exceptions.HttpClientResponseException: Forbidden
So, I created this test:
// Receives HomeController.class as parameter
void testController(final Class<?> type) {
final BeanDefinition<?> definition =
this.context.getBeanDefinition(type);
Assertions.assertNotNull(
definition.getAnnotation(Controller.class),
"Controller annotation is null"
);
definition.getExecutableMethods()
.forEach(method -> {
if (!method.hasStereotype(Executable.class)) {
return;
}
// These two are failing:
final Optional<Class<? extends Annotation>> http =
method.getAnnotationTypeByStereotype(HttpMethodMapping.class);
final Optional<Class<? extends Annotation>> uri =
method.getAnnotationTypeByStereotype(UriMapping.class);
Assertions.assertTrue(
http.isPresent(),
String.format("Missing method mapping for method %s", method)
);
Assertions.assertTrue(
uri.isPresent(),
String.format("Missing URI mapping for method %s", method)
);
});
}
The method create
has neither HttpMethodMapping
nor UriMapping
.
If I move the @Post
annotation from the interface to the controller class, this test passes but other tests that send requests to POST /home
fail with the following message:
More than 1 route matched the incoming request. The following routes matched /home: POST - /home, POST - /home
io.micronaut.http.client.exceptions.HttpClientResponseException: More than 1 route matched the incoming request. The following routes matched /home: POST - /home, POST - /home
This is my test config:
micronaut:
server:
port: -1
security:
basic-auth:
enabled: true
token:
basic-auth:
enabled: false
jwt:
enabled: false
...