diff --git a/common/pom.xml b/common/pom.xml index 5392bfe4..1cb156e6 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -127,6 +127,18 @@ junit-jupiter + + org.mockito + mockito-core + ${version.org.mockito.mockito-junit-jupiter} + test + + + org.mockito + mockito-junit-jupiter + test + + io.github.resilience4j resilience4j-retry diff --git a/common/src/main/java/org/fiware/tmforum/common/repository/TmForumRepository.java b/common/src/main/java/org/fiware/tmforum/common/repository/TmForumRepository.java index 7bc29a81..620c062e 100644 --- a/common/src/main/java/org/fiware/tmforum/common/repository/TmForumRepository.java +++ b/common/src/main/java/org/fiware/tmforum/common/repository/TmForumRepository.java @@ -104,9 +104,9 @@ public Mono> findEntities(Integer offset, Integer limit, Stri * {@code typeToClass} instead of a single fixed class. */ public Mono> findEntitiesPolymorphic(Integer offset, Integer limit, String types, - String query, String orderBy, Function> typeToClass) { + String query, String ids, String orderBy, Function> typeToClass) { return entitiesApi.queryEntities(generalProperties.getTenant(), - null, + ids, null, types, null, diff --git a/common/src/main/java/org/fiware/tmforum/common/rest/AbstractApiController.java b/common/src/main/java/org/fiware/tmforum/common/rest/AbstractApiController.java index 9497c5a9..853320ee 100644 --- a/common/src/main/java/org/fiware/tmforum/common/rest/AbstractApiController.java +++ b/common/src/main/java/org/fiware/tmforum/common/rest/AbstractApiController.java @@ -182,6 +182,7 @@ protected Mono> listPolymorphic(Integer offset, Integer limit, Str .findEntitiesPolymorphic(offset, limit, Optional.ofNullable(queryParams).map(QueryParams::type).orElse(types), Optional.ofNullable(queryParams).map(QueryParams::query).orElse(null), + Optional.ofNullable(queryParams).map(QueryParams::id).orElse(null), orderBy, typeToClass) .doOnNext(pagedResult -> optionalHttpRequest.ifPresent(theRequest -> { diff --git a/common/src/test/java/org/fiware/tmforum/common/repository/TmForumRepositoryTest.java b/common/src/test/java/org/fiware/tmforum/common/repository/TmForumRepositoryTest.java index 69042c42..07a22431 100644 --- a/common/src/test/java/org/fiware/tmforum/common/repository/TmForumRepositoryTest.java +++ b/common/src/test/java/org/fiware/tmforum/common/repository/TmForumRepositoryTest.java @@ -1,12 +1,20 @@ package org.fiware.tmforum.common.repository; import io.micronaut.http.HttpResponse; +import org.fiware.ngsi.api.EntitiesApiClient; +import org.fiware.ngsi.model.EntityListVO; import org.fiware.tmforum.common.configuration.GeneralProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import reactor.core.publisher.Mono; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; class TmForumRepositoryTest { @@ -19,6 +27,28 @@ public void setUp() { repository = new TmForumRepository(properties, null, null, null, null, null); } + @Test + public void findEntitiesPolymorphicForwardsTheIdFilterToTheBroker() { + // Regression test: findEntitiesPolymorphic used to hard-code the broker's native + // "id" query param to null, silently dropping any ?id= filter on polymorphic list + // endpoints (e.g. resourceSpecification, which spans several NGSI-LD types). + EntitiesApiClient entitiesApi = mock(EntitiesApiClient.class); + TmForumRepository repositoryWithClient = new TmForumRepository(properties, entitiesApi, null, null, null, null); + String requestedId = "urn:ngsi-ld:software-specification:0e2d5c4a-cf51-43cf-a510-dff06f62f4a3"; + + when(entitiesApi.queryEntities(any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), + any(), any(), any(), any(), any(), any())) + .thenReturn(Mono.just(HttpResponse.ok(new EntityListVO()))); + + repositoryWithClient + .findEntitiesPolymorphic(0, 10, "software-specification,resource-specification", null, requestedId, + null, type -> Object.class) + .block(); + + verify(entitiesApi).queryEntities(eq(properties.getTenant()), eq(requestedId), any(), any(), any(), any(), + any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any()); + } + @Test public void extractsTheConfiguredHeader() { properties.setCountHeader("NGSILD-Results-Count"); diff --git a/common/src/test/java/org/fiware/tmforum/common/rest/AbstractApiControllerTest.java b/common/src/test/java/org/fiware/tmforum/common/rest/AbstractApiControllerTest.java new file mode 100644 index 00000000..94c21a4a --- /dev/null +++ b/common/src/test/java/org/fiware/tmforum/common/rest/AbstractApiControllerTest.java @@ -0,0 +1,58 @@ +package org.fiware.tmforum.common.rest; + +import io.micronaut.http.HttpRequest; +import io.micronaut.http.context.ServerRequestContext; +import org.fiware.tmforum.common.configuration.GeneralProperties; +import org.fiware.tmforum.common.querying.MyPojo; +import org.fiware.tmforum.common.querying.QueryParser; +import org.fiware.tmforum.common.repository.PagedResult; +import org.fiware.tmforum.common.repository.TmForumRepository; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Mono; + +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class AbstractApiControllerTest { + + private static class TestController extends AbstractApiController { + TestController(QueryParser queryParser, TmForumRepository repository) { + super(queryParser, null, repository, null); + } + } + + @AfterEach + public void clearRequestContext() { + ServerRequestContext.set(null); + } + + @Test + public void listPolymorphicForwardsTheIdFilterToTheRepository() { + // Regression test: listPolymorphic used to only forward "type" and "query" from the + // parsed request to the repository, silently dropping any ?id= filter - even though it + // was correctly parsed into QueryParams.id(). The non-polymorphic list() already forwarded + // it; listPolymorphic must do the same. + GeneralProperties properties = new GeneralProperties(); + QueryParser queryParser = new QueryParser(properties); + TmForumRepository repository = mock(TmForumRepository.class); + TestController controller = new TestController(queryParser, repository); + + String requestedId = "urn:ngsi-ld:software-specification:0e2d5c4a-cf51-43cf-a510-dff06f62f4a3"; + ServerRequestContext.set( + HttpRequest.GET("/resourceSpecification?id=" + requestedId + "&fields=lifecycleStatus")); + + when(repository.findEntitiesPolymorphic(any(), any(), any(), any(), any(), any(), any())) + .thenReturn(Mono.just(new PagedResult<>(List.of(), 0, 10, null))); + + controller.listPolymorphic(0, 10, "software-specification,resource-specification", MyPojo.class, + type -> MyPojo.class).block(); + + verify(repository).findEntitiesPolymorphic(any(), any(), any(), any(), eq(requestedId), any(), any()); + } +}