From 644e3e0282df6ac39b18a00f8fd50787f5131497 Mon Sep 17 00:00:00 2001 From: Jedrzej Janasiak Date: Fri, 15 Mar 2024 14:15:31 +0100 Subject: [PATCH] feat: create integration and list integrations --- .../management/api/IntegrationRepository.java | 29 +++ .../management/model/Integration.java | 47 ++++ .../MongoIntegrationRepository.java | 113 +++++++++ .../IntegrationMongoRepository.java | 27 ++ .../IntegrationMongoRepositoryCustom.java | 24 ++ .../IntegrationMongoRepositoryImpl.java | 52 ++++ .../internal/model/IntegrationMongo.java | 44 ++++ .../management/mapper/GraviteeMapper.java | 7 + .../v2/rest/mapper/IntegrationMapper.java | 41 +++ .../integration/IntegrationsResource.java | 62 +++-- .../main/resources/openapi/openapi-apis.yaml | 2 + .../integration/IntegrationsResourceTest.java | 237 ++++++++++++++++++ .../permissions/EnvironmentPermission.java | 3 +- .../api/model/permissions/RolePermission.java | 1 + .../crud_service/IntegrationCrudService.java | 26 ++ .../core/integration/model/Integration.java | 41 +++ .../IntegrationQueryService.java | 24 ++ .../use_case/CreateIntegrationUseCase.java | 61 +++++ .../use_case/GetIntegrationsUseCase.java | 62 +++++ .../infra/adapter/IntegrationAdapter.java | 33 +++ .../IntegrationCrudServiceImpl.java | 53 ++++ .../IntegrationQueryServiceImpl.java | 66 +++++ .../core/model/IntegrationFixture.java | 47 ++++ .../IntegrationCrudServiceInMemory.java | 49 ++++ .../IntegrationQueryServiceInMemory.java | 76 ++++++ .../spring/InMemoryConfiguration.java | 51 +--- .../CreateIntegrationUseCaseTest.java | 96 +++++++ .../use_case/GetIntegrationsUseCaseTest.java | 94 +++++++ .../IntegrationCrudServiceImplTest.java | 73 ++++++ .../IntegrationQueryServiceImplTest.java | 94 +++++++ 30 files changed, 1571 insertions(+), 64 deletions(-) create mode 100644 gravitee-apim-repository/gravitee-apim-repository-api/src/main/java/io/gravitee/repository/management/api/IntegrationRepository.java create mode 100644 gravitee-apim-repository/gravitee-apim-repository-api/src/main/java/io/gravitee/repository/management/model/Integration.java create mode 100644 gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/MongoIntegrationRepository.java create mode 100644 gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/internal/integration/IntegrationMongoRepository.java create mode 100644 gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/internal/integration/IntegrationMongoRepositoryCustom.java create mode 100644 gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/internal/integration/IntegrationMongoRepositoryImpl.java create mode 100644 gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/internal/model/IntegrationMongo.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/mapper/IntegrationMapper.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/test/java/io/gravitee/rest/api/management/v2/rest/resource/integration/IntegrationsResourceTest.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/crud_service/IntegrationCrudService.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/model/Integration.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/query_service/IntegrationQueryService.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/use_case/CreateIntegrationUseCase.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/use_case/GetIntegrationsUseCase.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/adapter/IntegrationAdapter.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/crud_service/integration/IntegrationCrudServiceImpl.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/query_service/integration/IntegrationQueryServiceImpl.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/fixtures/core/model/IntegrationFixture.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/IntegrationCrudServiceInMemory.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/IntegrationQueryServiceInMemory.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/integration/use_case/CreateIntegrationUseCaseTest.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/integration/use_case/GetIntegrationsUseCaseTest.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/crud_service/integration/IntegrationCrudServiceImplTest.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/query_service/integration/IntegrationQueryServiceImplTest.java diff --git a/gravitee-apim-repository/gravitee-apim-repository-api/src/main/java/io/gravitee/repository/management/api/IntegrationRepository.java b/gravitee-apim-repository/gravitee-apim-repository-api/src/main/java/io/gravitee/repository/management/api/IntegrationRepository.java new file mode 100644 index 00000000000..31679a0ae94 --- /dev/null +++ b/gravitee-apim-repository/gravitee-apim-repository-api/src/main/java/io/gravitee/repository/management/api/IntegrationRepository.java @@ -0,0 +1,29 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.repository.management.api; + +import io.gravitee.common.data.domain.Page; +import io.gravitee.repository.exceptions.TechnicalException; +import io.gravitee.repository.management.api.search.Pageable; +import io.gravitee.repository.management.model.Integration; + +/** + * @author Remi Baptiste (remi.baptiste at graviteesource.com) + * @author GraviteeSource Team + */ +public interface IntegrationRepository extends CrudRepository { + Page findAllByEnvironment(String environmentId, Pageable pageable) throws TechnicalException; +} diff --git a/gravitee-apim-repository/gravitee-apim-repository-api/src/main/java/io/gravitee/repository/management/model/Integration.java b/gravitee-apim-repository/gravitee-apim-repository-api/src/main/java/io/gravitee/repository/management/model/Integration.java new file mode 100644 index 00000000000..e69b1f30efe --- /dev/null +++ b/gravitee-apim-repository/gravitee-apim-repository-api/src/main/java/io/gravitee/repository/management/model/Integration.java @@ -0,0 +1,47 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.repository.management.model; + +import java.util.Date; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author Remi Baptiste (remi.baptiste at graviteesource.com) + * @author GraviteeSource Team + */ +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Data +public class Integration { + + private String id; + + private String name; + + private String description; + + private String provider; + + private String environmentId; + + private Date createdAt; + + private Date updatedAt; +} diff --git a/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/MongoIntegrationRepository.java b/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/MongoIntegrationRepository.java new file mode 100644 index 00000000000..bb006ad1046 --- /dev/null +++ b/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/MongoIntegrationRepository.java @@ -0,0 +1,113 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.repository.mongodb.management; + +import io.gravitee.common.data.domain.Page; +import io.gravitee.repository.exceptions.TechnicalException; +import io.gravitee.repository.management.api.IntegrationRepository; +import io.gravitee.repository.management.api.search.Pageable; +import io.gravitee.repository.management.model.Integration; +import io.gravitee.repository.mongodb.management.internal.integration.IntegrationMongoRepository; +import io.gravitee.repository.mongodb.management.internal.model.IntegrationMongo; +import io.gravitee.repository.mongodb.management.mapper.GraviteeMapper; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Remi Baptiste (remi.baptiste at graviteesource.com) + * @author GraviteeSource Team + */ +@Component +public class MongoIntegrationRepository implements IntegrationRepository { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private IntegrationMongoRepository internalRepository; + + @Autowired + private GraviteeMapper mapper; + + @Override + public Optional findById(String s) throws TechnicalException { + logger.debug("Find integration by id [{}]", s); + Optional result = internalRepository.findById(s).map(this::map); + logger.debug("Find integration by id [{}] - DONE", s); + return result; + } + + @Override + public Integration create(Integration integration) throws TechnicalException { + logger.debug("Create integration [{}]", integration.getId()); + Integration createdIntegration = map(internalRepository.insert(map(integration))); + logger.debug("Create integration [{}] - Done", createdIntegration.getId()); + return createdIntegration; + } + + @Override + public Integration update(Integration integration) throws TechnicalException { + if (integration == null) { + throw new IllegalStateException("Integration must not be null"); + } + + return internalRepository + .findById(integration.getId()) + .map(found -> { + logger.debug("Update integration [{}]", integration.getId()); + Integration updatedIntegration = map(internalRepository.save(map(integration))); + logger.debug("Update integration [{}] - Done", updatedIntegration.getId()); + return updatedIntegration; + }) + .orElseThrow(() -> new IllegalStateException(String.format("No integration found with id [%s]", integration.getId()))); + } + + @Override + public void delete(String id) throws TechnicalException { + logger.debug("Delete integration [{}]", id); + internalRepository.deleteById(id); + logger.debug("Delete integration [{}] - Done", id); + } + + @Override + public Set findAll() throws TechnicalException { + return internalRepository.findAll().stream().map(this::map).collect(Collectors.toSet()); + } + + @Override + public Page findAllByEnvironment(String environmentId, Pageable pageable) throws TechnicalException { + logger.debug("Search by environment ID [{}]", environmentId); + + Page integrations = internalRepository.findAllByEnvironmentId(environmentId, pageable); + List content = mapper.mapIntegrationsList(integrations.getContent()); + + logger.debug("Search by environment ID [{}] - Done", environmentId); + return new Page<>(content, integrations.getPageNumber(), (int) integrations.getPageElements(), integrations.getTotalElements()); + } + + private Integration map(IntegrationMongo integrationMongo) { + return mapper.map(integrationMongo); + } + + private IntegrationMongo map(Integration integration) { + return mapper.map(integration); + } +} diff --git a/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/internal/integration/IntegrationMongoRepository.java b/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/internal/integration/IntegrationMongoRepository.java new file mode 100644 index 00000000000..40c405ecdb8 --- /dev/null +++ b/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/internal/integration/IntegrationMongoRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.repository.mongodb.management.internal.integration; + +import io.gravitee.repository.mongodb.management.internal.model.IntegrationMongo; +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.stereotype.Repository; + +/** + * @author Remi Baptiste (remi.baptiste at graviteesource.com) + * @author GraviteeSource Team + */ +@Repository +public interface IntegrationMongoRepository extends MongoRepository, IntegrationMongoRepositoryCustom {} diff --git a/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/internal/integration/IntegrationMongoRepositoryCustom.java b/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/internal/integration/IntegrationMongoRepositoryCustom.java new file mode 100644 index 00000000000..e1408bba27e --- /dev/null +++ b/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/internal/integration/IntegrationMongoRepositoryCustom.java @@ -0,0 +1,24 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.repository.mongodb.management.internal.integration; + +import io.gravitee.common.data.domain.Page; +import io.gravitee.repository.management.api.search.Pageable; +import io.gravitee.repository.mongodb.management.internal.model.IntegrationMongo; + +public interface IntegrationMongoRepositoryCustom { + Page findAllByEnvironmentId(String environmentId, Pageable pageable); +} diff --git a/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/internal/integration/IntegrationMongoRepositoryImpl.java b/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/internal/integration/IntegrationMongoRepositoryImpl.java new file mode 100644 index 00000000000..b864cb813d3 --- /dev/null +++ b/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/internal/integration/IntegrationMongoRepositoryImpl.java @@ -0,0 +1,52 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.repository.mongodb.management.internal.integration; + +import io.gravitee.common.data.domain.Page; +import io.gravitee.repository.management.api.search.Pageable; +import io.gravitee.repository.mongodb.management.internal.model.IntegrationMongo; +import java.util.List; +import lombok.AllArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Component; + +@Component +@AllArgsConstructor +public class IntegrationMongoRepositoryImpl implements IntegrationMongoRepositoryCustom { + + private final MongoTemplate mongoTemplate; + + @Override + public Page findAllByEnvironmentId(String environmentId, Pageable pageable) { + Query query = new Query(); + query.addCriteria(Criteria.where("environmentId").is(environmentId)); + query.with(Sort.by(Sort.Direction.DESC, "updatedAt")); + + long total = mongoTemplate.count(query, IntegrationMongo.class); + + if (pageable != null) { + query.with(PageRequest.of(pageable.pageNumber(), pageable.pageSize())); + } + + List integrations = mongoTemplate.find(query, IntegrationMongo.class); + + return new Page<>(integrations, (pageable != null) ? pageable.pageNumber() : 0, integrations.size(), total); + } +} diff --git a/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/internal/model/IntegrationMongo.java b/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/internal/model/IntegrationMongo.java new file mode 100644 index 00000000000..f164792915f --- /dev/null +++ b/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/internal/model/IntegrationMongo.java @@ -0,0 +1,44 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.repository.mongodb.management.internal.model; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +/** + * @author Remi Baptiste (remi.baptiste at graviteesource.com) + * @author GraviteeSource Team + */ +@Getter +@Setter +@Document(collection = "#{@environment.getProperty('management.mongodb.prefix')}integration") +public class IntegrationMongo extends Auditable { + + @Id + private String id; + + private String name; + + private String description; + + private String provider; + + private String environmentId; + + public IntegrationMongo() {} +} diff --git a/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/mapper/GraviteeMapper.java b/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/mapper/GraviteeMapper.java index fc5783da990..004ffa6227b 100644 --- a/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/mapper/GraviteeMapper.java +++ b/gravitee-apim-repository/gravitee-apim-repository-mongodb/src/main/java/io/gravitee/repository/mongodb/management/mapper/GraviteeMapper.java @@ -168,6 +168,11 @@ public interface GraviteeMapper { InstallationMongo map(Installation toMap); + // Integration mapping + Integration map(IntegrationMongo integrationMongo); + + IntegrationMongo map(Integration toMap); + // Invitation mapping Invitation map(InvitationMongo toMap); @@ -297,4 +302,6 @@ public interface GraviteeMapper { Workflow map(WorkflowMongo toMap); WorkflowMongo map(Workflow toMap); + + List mapIntegrationsList(Collection toMap); } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/mapper/IntegrationMapper.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/mapper/IntegrationMapper.java new file mode 100644 index 00000000000..ba12618c2b7 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/mapper/IntegrationMapper.java @@ -0,0 +1,41 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.rest.api.management.v2.rest.mapper; + +import io.gravitee.apim.core.integration.model.Integration; +import io.gravitee.rest.api.management.v2.rest.model.CreateIntegration; +import java.util.List; +import java.util.Set; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Remi Baptiste (remi.baptiste at graviteesource.com) + * @author GraviteeSource Team + */ +@Mapper(uses = { ConfigurationSerializationMapper.class, DateMapper.class }) +public interface IntegrationMapper { + Logger logger = LoggerFactory.getLogger(IntegrationMapper.class); + IntegrationMapper INSTANCE = Mappers.getMapper(IntegrationMapper.class); + + Integration map(CreateIntegration createIntegration); + + io.gravitee.rest.api.management.v2.rest.model.Integration map(Integration createdIntegration); + + List map(Set createdIntegration); +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/resource/integration/IntegrationsResource.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/resource/integration/IntegrationsResource.java index 0f9fdfe007e..83d720145af 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/resource/integration/IntegrationsResource.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/resource/integration/IntegrationsResource.java @@ -15,20 +15,23 @@ */ package io.gravitee.rest.api.management.v2.rest.resource.integration; +import io.gravitee.apim.core.integration.model.Integration; +import io.gravitee.apim.core.integration.use_case.CreateIntegrationUseCase; +import io.gravitee.apim.core.integration.use_case.GetIntegrationsUseCase; import io.gravitee.common.data.domain.Page; import io.gravitee.common.http.MediaType; -import io.gravitee.rest.api.management.v2.rest.model.*; +import io.gravitee.rest.api.management.v2.rest.mapper.IntegrationMapper; +import io.gravitee.rest.api.management.v2.rest.model.CreateIntegration; +import io.gravitee.rest.api.management.v2.rest.model.IntegrationsResponse; import io.gravitee.rest.api.management.v2.rest.pagination.PaginationInfo; import io.gravitee.rest.api.management.v2.rest.resource.AbstractResource; import io.gravitee.rest.api.management.v2.rest.resource.param.PaginationParam; +import io.gravitee.rest.api.model.common.PageableImpl; +import jakarta.inject.Inject; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import jakarta.ws.rs.*; -import jakarta.ws.rs.Path; import jakarta.ws.rs.core.Response; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import lombok.extern.slf4j.Slf4j; /** @@ -39,37 +42,50 @@ @Slf4j public class IntegrationsResource extends AbstractResource { - private static final List integrationsMock = new ArrayList<>(); + @Inject + private CreateIntegrationUseCase createIntegrationUsecase; + + @Inject + private GetIntegrationsUseCase getIntegrationsUsecase; @POST @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) - public Response createIntegration(@Valid @NotNull final CreateIntegration integration) { - Integration mockIntegration = Integration - .builder() - .id(UUID.randomUUID().toString()) - .name(integration.getName()) - .description(integration.getDescription()) - .provider(integration.getProvider()) + // TODO enable permission when front will be ready + // @Permissions({ @Permission(value = RolePermission.ENVIRONMENT_INTEGRATION, acls = { RolePermissionAction.CREATE }) }) + public Response createIntegration(@PathParam("envId") String environmentId, @Valid @NotNull final CreateIntegration integration) { + var newIntegrationEntity = IntegrationMapper.INSTANCE.map(integration); + newIntegrationEntity.setEnvironmentId(environmentId); + + var createdIntegration = createIntegrationUsecase + .execute(CreateIntegrationUseCase.Input.builder().integration(newIntegrationEntity).build()) + .createdIntegration(); + + return Response + .created(this.getLocationHeader(createdIntegration.getId())) + .entity(IntegrationMapper.INSTANCE.map(createdIntegration)) .build(); - integrationsMock.add(mockIntegration); - return Response.created(this.getLocationHeader(mockIntegration.getId())).entity(mockIntegration).build(); } @GET @Produces(MediaType.APPLICATION_JSON) + // TODO enable permission when front will be ready + // @Permissions({ @Permission(value = RolePermission.ENVIRONMENT_INTEGRATION, acls = { RolePermissionAction.CREATE }) }) public IntegrationsResponse listIntegrations( @PathParam("envId") String environmentId, @BeanParam @Valid PaginationParam paginationParam ) { - Page integrationPage = new Page<>(integrationsMock, 0, integrationsMock.size(), integrationsMock.size()); - - long totalCount = integrationPage.getTotalElements(); - Integer pageItemsCount = Math.toIntExact(integrationPage.getPageElements()); - + Page integrations = getIntegrationsUsecase + .execute( + new GetIntegrationsUseCase.Input(environmentId, new PageableImpl(paginationParam.getPage(), paginationParam.getPerPage())) + ) + .integrations(); + var totalElements = integrations.getTotalElements(); return new IntegrationsResponse() - .data(integrationsMock) - .pagination(PaginationInfo.computePaginationInfo(totalCount, pageItemsCount, paginationParam)) - .links(computePaginationLinks(totalCount, paginationParam)); + .data(integrations.getContent().stream().map(IntegrationMapper.INSTANCE::map).toList()) + .pagination( + PaginationInfo.computePaginationInfo(totalElements, Math.toIntExact(integrations.getPageElements()), paginationParam) + ) + .links(computePaginationLinks(totalElements, paginationParam)); } } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/resources/openapi/openapi-apis.yaml b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/resources/openapi/openapi-apis.yaml index e9f6fd85ba7..6f2c0a1d975 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/resources/openapi/openapi-apis.yaml +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/resources/openapi/openapi-apis.yaml @@ -5856,6 +5856,8 @@ components: provider: type: string description: Provider of this integration + required: + - name parameters: ############# diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/test/java/io/gravitee/rest/api/management/v2/rest/resource/integration/IntegrationsResourceTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/test/java/io/gravitee/rest/api/management/v2/rest/resource/integration/IntegrationsResourceTest.java new file mode 100644 index 00000000000..074c2449864 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/test/java/io/gravitee/rest/api/management/v2/rest/resource/integration/IntegrationsResourceTest.java @@ -0,0 +1,237 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.rest.api.management.v2.rest.resource.integration; + +import static assertions.MAPIAssertions.assertThat; +import static io.gravitee.common.http.HttpStatusCode.OK_200; +import static org.mockito.Mockito.doReturn; + +import fixtures.core.model.IntegrationFixture; +import inmemory.IntegrationCrudServiceInMemory; +import io.gravitee.common.http.HttpStatusCode; +import io.gravitee.repository.exceptions.TechnicalException; +import io.gravitee.rest.api.management.v2.rest.model.*; +import io.gravitee.rest.api.management.v2.rest.resource.AbstractResourceTest; +import io.gravitee.rest.api.model.EnvironmentEntity; +import io.gravitee.rest.api.service.common.GraviteeContext; +import io.gravitee.rest.api.service.common.UuidString; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Response; +import java.time.ZonedDateTime; +import java.util.stream.IntStream; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class IntegrationsResourceTest extends AbstractResourceTest { + + @Autowired + IntegrationCrudServiceInMemory integrationCrudServiceInMemory; + + private static final String ENVIRONMENT = "my-env"; + private static final String INTEGRATION_NAME = "test-name"; + private static final String INTEGRATION_DESCRIPTION = "integration-description"; + private static final String INTEGRATION_PROVIDER = "test-provider"; + private static final String INTEGRATION_ID = "generated-id"; + + WebTarget target; + + @Override + protected String contextPath() { + return "/environments/" + ENVIRONMENT + "/integrations"; + } + + @BeforeEach + public void init() throws TechnicalException { + target = rootTarget(); + + EnvironmentEntity environmentEntity = EnvironmentEntity.builder().id(ENVIRONMENT).organizationId(ORGANIZATION).build(); + doReturn(environmentEntity).when(environmentService).findById(ENVIRONMENT); + doReturn(environmentEntity).when(environmentService).findByOrgAndIdOrHrid(ORGANIZATION, ENVIRONMENT); + + GraviteeContext.setCurrentEnvironment(ENVIRONMENT); + GraviteeContext.setCurrentOrganization(ORGANIZATION); + + UuidString.overrideGenerator(() -> INTEGRATION_ID); + } + + @AfterEach + public void tearDown() { + integrationCrudServiceInMemory.reset(); + } + + @Nested + class CreateIntegrations { + + @Test + public void should_create_integration() { + //Given + var createIntegration = CreateIntegration + .builder() + .name(INTEGRATION_NAME) + .description(INTEGRATION_DESCRIPTION) + .provider(INTEGRATION_PROVIDER) + .build(); + + //When + Response response = target.request().post(Entity.json(createIntegration)); + + //Then + + assertThat(response) + .hasStatus(HttpStatusCode.CREATED_201) + .asEntity(Integration.class) + .isEqualTo( + Integration + .builder() + .id(INTEGRATION_ID) + .name(INTEGRATION_NAME) + .description(INTEGRATION_DESCRIPTION) + .provider(INTEGRATION_PROVIDER) + .build() + ); + } + + @Test + public void should_throw_bad_request_when_name_is_missing() { + //Given + CreateIntegration createIntegration = CreateIntegration + .builder() + .description(INTEGRATION_DESCRIPTION) + .provider(INTEGRATION_PROVIDER) + .build(); + + //When + Response response = target.request().post(Entity.json(createIntegration)); + + //Then + assertThat(response).hasStatus(HttpStatusCode.BAD_REQUEST_400); + } + + @Test + public void should_throw_bad_request_when_payload_is_empty() { + //When + Response response = target.request().post(Entity.json(null)); + + //Then + assertThat(response).hasStatus(HttpStatusCode.BAD_REQUEST_400); + } + } + + @Nested + class ListIntegrations { + + @BeforeEach + void setup() { + var integration = IntStream.range(0, 15).mapToObj(i -> IntegrationFixture.anIntegration()).toList(); + integrationCrudServiceInMemory.initWith(integration); + } + + @Test + public void get_first_page_of_integrations_for_specific_env_id() { + var integrationOtherEnv = IntegrationFixture.anIntegration("other-env"); + integrationCrudServiceInMemory.create(integrationOtherEnv); + + //When + Response response = target.queryParam("page", 1).queryParam("perPage", 5).request().get(); + + //Then + assertThat(response) + .hasStatus(HttpStatusCode.OK_200) + .asEntity(IntegrationsResponse.class) + .extracting(IntegrationsResponse::getPagination) + .isEqualTo(Pagination.builder().page(1).perPage(5).pageItemsCount(5).pageCount(3).totalCount(15L).build()); + } + + @Test + public void get_second_page_of_integrations() { + //When + Response response = target.queryParam("page", 2).queryParam("perPage", 2).request().get(); + + //Then + assertThat(response) + .hasStatus(HttpStatusCode.OK_200) + .asEntity(IntegrationsResponse.class) + .extracting(IntegrationsResponse::getPagination) + .isEqualTo(Pagination.builder().page(2).perPage(2).pageItemsCount(2).pageCount(8).totalCount(15L).build()); + } + + @Test + public void get_first_page_with_page_size_10_when_pagination_param_missing() { + //When + Response response = target.request().get(); + + //Then + assertThat(response) + .hasStatus(HttpStatusCode.OK_200) + .asEntity(IntegrationsResponse.class) + .extracting(IntegrationsResponse::getPagination) + .isEqualTo(Pagination.builder().page(1).perPage(10).pageItemsCount(10).pageCount(2).totalCount(15L).build()); + } + + @Test + public void get_sorted_list_of_integrations() { + //Given + var name = "most-recent-integration"; + var description = "should-be-returned-first"; + var provider = "test-provider"; + var recentDate = ZonedDateTime.parse("2024-02-03T20:22:02.00Z"); + var integration = IntegrationFixture.BASE + .get() + .name(name) + .description(description) + .provider(provider) + .createdAt(recentDate) + .updatedAt(recentDate) + .build(); + integrationCrudServiceInMemory.create(integration); + + //When + Response response = target.request().get(); + + //Then + assertThat(response) + .hasStatus(HttpStatusCode.OK_200) + .asEntity(IntegrationsResponse.class) + .extracting(IntegrationsResponse::getData) + .extracting(integrations -> integrations.get(0)) + .isEqualTo(Integration.builder().id(INTEGRATION_ID).name(name).description(description).provider(provider).build()); + } + + @Test + void should_compute_links() { + Response response = target.queryParam("page", 2).queryParam("perPage", 5).request().get(); + + assertThat(response) + .hasStatus(OK_200) + .asEntity(ApiLogsResponse.class) + .extracting(ApiLogsResponse::getLinks) + .isEqualTo( + Links + .builder() + .self(target.queryParam("page", 2).queryParam("perPage", 5).getUri().toString()) + .first(target.queryParam("page", 1).queryParam("perPage", 5).getUri().toString()) + .last(target.queryParam("page", 3).queryParam("perPage", 5).getUri().toString()) + .previous(target.queryParam("page", 1).queryParam("perPage", 5).getUri().toString()) + .next(target.queryParam("page", 3).queryParam("perPage", 5).getUri().toString()) + .build() + ); + } + } +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-model/src/main/java/io/gravitee/rest/api/model/permissions/EnvironmentPermission.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-model/src/main/java/io/gravitee/rest/api/model/permissions/EnvironmentPermission.java index 78157340014..4a76f238e5d 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-model/src/main/java/io/gravitee/rest/api/model/permissions/EnvironmentPermission.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-model/src/main/java/io/gravitee/rest/api/model/permissions/EnvironmentPermission.java @@ -46,7 +46,8 @@ public enum EnvironmentPermission implements Permission { API_HEADER("API_HEADER", 3300), CLIENT_REGISTRATION_PROVIDER("CLIENT_REGISTRATION_PROVIDER", 3500), THEME("THEME", 3600), - IDENTITY_PROVIDER_ACTIVATION("IDENTITY_PROVIDER_ACTIVATION", 3700); + IDENTITY_PROVIDER_ACTIVATION("IDENTITY_PROVIDER_ACTIVATION", 3700), + INTEGRATION("INTEGRATION", 3800); String name; int mask; diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-model/src/main/java/io/gravitee/rest/api/model/permissions/RolePermission.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-model/src/main/java/io/gravitee/rest/api/model/permissions/RolePermission.java index 10fd0a695df..2837f437d22 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-model/src/main/java/io/gravitee/rest/api/model/permissions/RolePermission.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-model/src/main/java/io/gravitee/rest/api/model/permissions/RolePermission.java @@ -80,6 +80,7 @@ public enum RolePermission { ENVIRONMENT_CLIENT_REGISTRATION_PROVIDER(RoleScope.ENVIRONMENT, EnvironmentPermission.CLIENT_REGISTRATION_PROVIDER), ENVIRONMENT_THEME(RoleScope.ENVIRONMENT, EnvironmentPermission.THEME), ENVIRONMENT_IDENTITY_PROVIDER_ACTIVATION(RoleScope.ENVIRONMENT, EnvironmentPermission.IDENTITY_PROVIDER_ACTIVATION), + ENVIRONMENT_INTEGRATION(RoleScope.ENVIRONMENT, EnvironmentPermission.INTEGRATION), ORGANIZATION_USERS(RoleScope.ORGANIZATION, OrganizationPermission.USER), ORGANIZATION_ROLE(RoleScope.ORGANIZATION, OrganizationPermission.ROLE), diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/crud_service/IntegrationCrudService.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/crud_service/IntegrationCrudService.java new file mode 100644 index 00000000000..04070feb702 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/crud_service/IntegrationCrudService.java @@ -0,0 +1,26 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.apim.core.integration.crud_service; + +import io.gravitee.apim.core.integration.model.Integration; + +/** + * @author Remi Baptiste (remi.baptiste at graviteesource.com) + * @author GraviteeSource Team + */ +public interface IntegrationCrudService { + Integration create(Integration integration); +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/model/Integration.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/model/Integration.java new file mode 100644 index 00000000000..938f4e2c192 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/model/Integration.java @@ -0,0 +1,41 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.apim.core.integration.model; + +import java.time.ZonedDateTime; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author Remi Baptiste (remi.baptiste at graviteesource.com) + * @author GraviteeSource Team + */ +@Data +@Builder(toBuilder = true) +@NoArgsConstructor +@AllArgsConstructor +public class Integration { + + String id; + String name; + String description; + String provider; + String environmentId; + ZonedDateTime createdAt; + ZonedDateTime updatedAt; +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/query_service/IntegrationQueryService.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/query_service/IntegrationQueryService.java new file mode 100644 index 00000000000..3adeeba3ac6 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/query_service/IntegrationQueryService.java @@ -0,0 +1,24 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.apim.core.integration.query_service; + +import io.gravitee.apim.core.integration.model.Integration; +import io.gravitee.common.data.domain.Page; +import io.gravitee.rest.api.model.common.Pageable; + +public interface IntegrationQueryService { + Page findByEnvironment(String environmentId, Pageable pageable); +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/use_case/CreateIntegrationUseCase.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/use_case/CreateIntegrationUseCase.java new file mode 100644 index 00000000000..b60c6e19365 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/use_case/CreateIntegrationUseCase.java @@ -0,0 +1,61 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.apim.core.integration.use_case; + +import io.gravitee.apim.core.UseCase; +import io.gravitee.apim.core.integration.crud_service.IntegrationCrudService; +import io.gravitee.apim.core.integration.model.Integration; +import io.gravitee.common.utils.TimeProvider; +import io.gravitee.rest.api.service.common.UuidString; +import lombok.Builder; + +/** + * @author Remi Baptiste (remi.baptiste at graviteesource.com) + * @author GraviteeSource Team + */ +@UseCase +public class CreateIntegrationUseCase { + + private final IntegrationCrudService integrationCrudService; + + public CreateIntegrationUseCase(IntegrationCrudService integrationCrudService) { + this.integrationCrudService = integrationCrudService; + } + + public Output execute(Input input) { + var now = TimeProvider.now(); + + var integrationToCreate = Integration + .builder() + .id(UuidString.generateRandom()) + .name(input.integration.getName()) + .description(input.integration.getDescription()) + .provider(input.integration.getProvider()) + .environmentId(input.integration.getEnvironmentId()) + .createdAt(now) + .updatedAt(now) + .build(); + + Integration integrationCreated = integrationCrudService.create(integrationToCreate); + + return new Output(integrationCreated); + } + + @Builder + public record Input(Integration integration) {} + + public record Output(Integration createdIntegration) {} +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/use_case/GetIntegrationsUseCase.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/use_case/GetIntegrationsUseCase.java new file mode 100644 index 00000000000..91dbdf1b840 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/integration/use_case/GetIntegrationsUseCase.java @@ -0,0 +1,62 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.gravitee.apim.core.integration.use_case; + +import io.gravitee.apim.core.UseCase; +import io.gravitee.apim.core.integration.model.Integration; +import io.gravitee.apim.core.integration.query_service.IntegrationQueryService; +import io.gravitee.common.data.domain.Page; +import io.gravitee.rest.api.model.common.Pageable; +import io.gravitee.rest.api.model.common.PageableImpl; +import java.util.Optional; +import lombok.Builder; + +/** + * @author Remi Baptiste (remi.baptiste at graviteesource.com) + * @author GraviteeSource Team + */ +@UseCase +public class GetIntegrationsUseCase { + + private final IntegrationQueryService integrationQueryService; + + public GetIntegrationsUseCase(IntegrationQueryService integrationQueryService) { + this.integrationQueryService = integrationQueryService; + } + + public GetIntegrationsUseCase.Output execute(GetIntegrationsUseCase.Input input) { + var environmentId = input.environmentId(); + var pageable = input.pageable.orElse(new PageableImpl(1, 10)); + + Page integrations = integrationQueryService.findByEnvironment(environmentId, pageable); + + return new GetIntegrationsUseCase.Output(integrations); + } + + @Builder + public record Input(String environmentId, Optional pageable) { + public Input(String environmentId) { + this(environmentId, Optional.empty()); + } + + public Input(String environmentId, Pageable pageable) { + this(environmentId, Optional.of(pageable)); + } + } + + public record Output(Page integrations) {} +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/adapter/IntegrationAdapter.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/adapter/IntegrationAdapter.java new file mode 100644 index 00000000000..adaf19f84a3 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/adapter/IntegrationAdapter.java @@ -0,0 +1,33 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.apim.infra.adapter; + +import io.gravitee.apim.core.integration.model.Integration; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * @author Remi Baptiste (remi.baptiste at graviteesource.com) + * @author GraviteeSource Team + */ +@Mapper +public interface IntegrationAdapter { + IntegrationAdapter INSTANCE = Mappers.getMapper(IntegrationAdapter.class); + + Integration toEntity(io.gravitee.repository.management.model.Integration integration); + + io.gravitee.repository.management.model.Integration toRepository(Integration integration); +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/crud_service/integration/IntegrationCrudServiceImpl.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/crud_service/integration/IntegrationCrudServiceImpl.java new file mode 100644 index 00000000000..7e3d26e8214 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/crud_service/integration/IntegrationCrudServiceImpl.java @@ -0,0 +1,53 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.apim.infra.crud_service.integration; + +import io.gravitee.apim.core.exception.TechnicalDomainException; +import io.gravitee.apim.core.integration.crud_service.IntegrationCrudService; +import io.gravitee.apim.core.integration.model.Integration; +import io.gravitee.apim.infra.adapter.IntegrationAdapter; +import io.gravitee.repository.exceptions.TechnicalException; +import io.gravitee.repository.management.api.IntegrationRepository; +import io.gravitee.rest.api.service.exceptions.TechnicalManagementException; +import io.gravitee.rest.api.service.impl.AbstractService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; + +/** + * @author Remi Baptiste (remi.baptiste at graviteesource.com) + * @author GraviteeSource Team + */ +@Slf4j +@Service +public class IntegrationCrudServiceImpl extends AbstractService implements IntegrationCrudService { + + private final IntegrationRepository integrationRepository; + + public IntegrationCrudServiceImpl(@Lazy IntegrationRepository integrationRepository) { + this.integrationRepository = integrationRepository; + } + + @Override + public Integration create(Integration integration) { + try { + var createdIntegration = integrationRepository.create(IntegrationAdapter.INSTANCE.toRepository(integration)); + return IntegrationAdapter.INSTANCE.toEntity(createdIntegration); + } catch (TechnicalException e) { + throw new TechnicalManagementException("Error when creating Integration: " + integration.getName(), e); + } + } +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/query_service/integration/IntegrationQueryServiceImpl.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/query_service/integration/IntegrationQueryServiceImpl.java new file mode 100644 index 00000000000..f4b15cbfe12 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/query_service/integration/IntegrationQueryServiceImpl.java @@ -0,0 +1,66 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.apim.infra.query_service.integration; + +import io.gravitee.apim.core.integration.model.Integration; +import io.gravitee.apim.core.integration.query_service.IntegrationQueryService; +import io.gravitee.apim.infra.adapter.IntegrationAdapter; +import io.gravitee.common.data.domain.Page; +import io.gravitee.repository.exceptions.TechnicalException; +import io.gravitee.repository.management.api.IntegrationRepository; +import io.gravitee.rest.api.model.common.Pageable; +import io.gravitee.rest.api.service.exceptions.TechnicalManagementException; +import io.gravitee.rest.api.service.impl.AbstractService; +import java.util.List; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class IntegrationQueryServiceImpl extends AbstractService implements IntegrationQueryService { + + private final IntegrationRepository integrationRepository; + + public IntegrationQueryServiceImpl(@Lazy IntegrationRepository integrationRepository) { + this.integrationRepository = integrationRepository; + } + + @Override + public Page findByEnvironment(String environmentId, Pageable pageable) { + try { + Page integrationsPage = integrationRepository.findAllByEnvironment( + environmentId, + convert(pageable) + ); + List integrationList = integrationsPage + .getContent() + .stream() + .map(IntegrationAdapter.INSTANCE::toEntity) + .collect(Collectors.toList()); + return new Page<>( + integrationList, + integrationsPage.getPageNumber(), + (int) integrationsPage.getPageElements(), + integrationsPage.getTotalElements() + ); + } catch (TechnicalException e) { + log.error("An error occurred while finding Integrations by environment", e); + throw new TechnicalManagementException("An error occurred while finding Integrations by environment id: " + environmentId, e); + } + } +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/fixtures/core/model/IntegrationFixture.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/fixtures/core/model/IntegrationFixture.java new file mode 100644 index 00000000000..3c626f42553 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/fixtures/core/model/IntegrationFixture.java @@ -0,0 +1,47 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package fixtures.core.model; + +import io.gravitee.apim.core.integration.model.Integration; +import io.gravitee.rest.api.service.common.UuidString; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.UUID; +import java.util.function.Supplier; + +public class IntegrationFixture { + + private IntegrationFixture() {} + + public static final Supplier BASE = () -> + Integration + .builder() + .id(UuidString.generateRandom()) + .name("Test integration") + .description("Test description") + .provider("ForTestPurpose") + .environmentId("my-env") + .createdAt(ZonedDateTime.parse("2020-02-03T20:22:02.00Z").withZoneSameLocal(ZoneId.systemDefault())) + .updatedAt(ZonedDateTime.parse("2020-02-03T20:22:02.00Z").withZoneSameLocal(ZoneId.systemDefault())); + + public static Integration anIntegration() { + return BASE.get().build(); + } + + public static Integration anIntegration(String envId) { + return BASE.get().environmentId(envId).build(); + } +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/IntegrationCrudServiceInMemory.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/IntegrationCrudServiceInMemory.java new file mode 100644 index 00000000000..ff6d77b6423 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/IntegrationCrudServiceInMemory.java @@ -0,0 +1,49 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package inmemory; + +import io.gravitee.apim.core.integration.crud_service.IntegrationCrudService; +import io.gravitee.apim.core.integration.model.Integration; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class IntegrationCrudServiceInMemory implements IntegrationCrudService, InMemoryAlternative { + + final ArrayList storage = new ArrayList<>(); + + @Override + public Integration create(Integration integration) { + storage.add(integration); + return integration; + } + + @Override + public void initWith(List items) { + storage.clear(); + storage.addAll(items); + } + + @Override + public void reset() { + storage.clear(); + } + + @Override + public List storage() { + return Collections.unmodifiableList(storage); + } +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/IntegrationQueryServiceInMemory.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/IntegrationQueryServiceInMemory.java new file mode 100644 index 00000000000..bd5fba0748b --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/IntegrationQueryServiceInMemory.java @@ -0,0 +1,76 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package inmemory; + +import io.gravitee.apim.core.integration.model.Integration; +import io.gravitee.apim.core.integration.query_service.IntegrationQueryService; +import io.gravitee.common.data.domain.Page; +import io.gravitee.rest.api.model.common.Pageable; +import io.gravitee.rest.api.service.common.UuidString; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class IntegrationQueryServiceInMemory implements IntegrationQueryService, InMemoryAlternative { + + private List storage; + + public IntegrationQueryServiceInMemory() { + storage = new ArrayList<>(); + } + + public IntegrationQueryServiceInMemory(IntegrationCrudServiceInMemory integrationCrudServiceInMemory) { + storage = integrationCrudServiceInMemory.storage; + } + + @Override + public Page findByEnvironment(String environmentId, Pageable pageable) { + var pageNumber = pageable.getPageNumber(); + var pageSize = pageable.getPageSize(); + + var matches = storage + .stream() + .filter(integration -> integration.getEnvironmentId().equals(environmentId)) + .sorted(Comparator.comparing(Integration::getUpdatedAt).reversed()) + .toList(); + + var page = matches.size() <= pageSize + ? matches + : matches.subList((pageNumber - 1) * pageSize, Math.min(pageNumber * pageSize, matches.size())); + + return new Page<>(page, pageNumber, pageSize, matches.size()); + } + + @Override + public void initWith(List items) { + storage.clear(); + storage = items; + } + + @Override + public void reset() { + storage.clear(); + } + + @Override + public List storage() { + return Collections.unmodifiableList(storage); + } +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/spring/InMemoryConfiguration.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/spring/InMemoryConfiguration.java index b657e761b6b..8cdaee96b74 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/spring/InMemoryConfiguration.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/spring/InMemoryConfiguration.java @@ -15,46 +15,7 @@ */ package inmemory.spring; -import inmemory.AccessPointQueryServiceInMemory; -import inmemory.ApiCrudServiceInMemory; -import inmemory.ApiKeyCrudServiceInMemory; -import inmemory.ApiKeyQueryServiceInMemory; -import inmemory.ApiMetadataQueryServiceInMemory; -import inmemory.ApiQueryServiceInMemory; -import inmemory.ApplicationCrudServiceInMemory; -import inmemory.AuditCrudServiceInMemory; -import inmemory.AuditMetadataQueryServiceInMemory; -import inmemory.AuditQueryServiceInMemory; -import inmemory.ConnectionLogsCrudServiceInMemory; -import inmemory.EndpointPluginQueryServiceInMemory; -import inmemory.EntrypointPluginQueryServiceInMemory; -import inmemory.EnvironmentCrudServiceInMemory; -import inmemory.EventCrudInMemory; -import inmemory.EventQueryServiceInMemory; -import inmemory.FlowCrudServiceInMemory; -import inmemory.GroupQueryServiceInMemory; -import inmemory.IndexerInMemory; -import inmemory.InstallationAccessQueryServiceInMemory; -import inmemory.InstanceQueryServiceInMemory; -import inmemory.LicenseCrudServiceInMemory; -import inmemory.MembershipCrudServiceInMemory; -import inmemory.MembershipQueryServiceInMemory; -import inmemory.MessageLogCrudServiceInMemory; -import inmemory.NoopSwaggerOpenApiResolver; -import inmemory.NoopTemplateResolverDomainService; -import inmemory.PageCrudServiceInMemory; -import inmemory.PageQueryServiceInMemory; -import inmemory.PageRevisionCrudServiceInMemory; -import inmemory.ParametersDomainServiceInMemory; -import inmemory.ParametersQueryServiceInMemory; -import inmemory.PlanCrudServiceInMemory; -import inmemory.PlanQueryServiceInMemory; -import inmemory.PolicyPluginQueryServiceInMemory; -import inmemory.RoleQueryServiceInMemory; -import inmemory.SubscriptionCrudServiceInMemory; -import inmemory.SubscriptionQueryServiceInMemory; -import inmemory.TriggerNotificationDomainServiceInMemory; -import inmemory.UserCrudServiceInMemory; +import inmemory.*; import io.gravitee.apim.infra.query_service.audit.AuditEventQueryServiceImpl; import org.mockito.Mockito; import org.springframework.context.annotation.Bean; @@ -267,4 +228,14 @@ public NoopTemplateResolverDomainService noopTemplateResolverDomainService() { public NoopSwaggerOpenApiResolver noopSwaggerOpenApiResolver() { return new NoopSwaggerOpenApiResolver(); } + + @Bean + public IntegrationCrudServiceInMemory integrationCrudService() { + return new IntegrationCrudServiceInMemory(); + } + + @Bean + public IntegrationQueryServiceInMemory integrationQueryService(IntegrationCrudServiceInMemory integrationCrudServiceInMemory) { + return new IntegrationQueryServiceInMemory(integrationCrudServiceInMemory); + } } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/integration/use_case/CreateIntegrationUseCaseTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/integration/use_case/CreateIntegrationUseCaseTest.java new file mode 100644 index 00000000000..f960fba5b3b --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/integration/use_case/CreateIntegrationUseCaseTest.java @@ -0,0 +1,96 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.apim.core.integration.use_case; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import fixtures.core.model.IntegrationFixture; +import inmemory.IntegrationCrudServiceInMemory; +import io.gravitee.apim.core.integration.crud_service.IntegrationCrudService; +import io.gravitee.apim.core.integration.model.Integration; +import io.gravitee.common.utils.TimeProvider; +import io.gravitee.rest.api.service.common.UuidString; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Date; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class CreateIntegrationUseCaseTest { + + private static final String INTEGRATION_ID = "generated-id"; + private static final String NAME = "Test integration"; + private static final String DESCRIPTION = "Test description"; + private static final String PROVIDER = "ForTestPurpose"; + private static final Instant INSTANT_NOW = Instant.parse("2023-10-22T10:15:30Z"); + private static final String ENV_ID = "my-env"; + + IntegrationCrudServiceInMemory integrationCrudServiceInMemory = new IntegrationCrudServiceInMemory(); + + CreateIntegrationUseCase usecase; + + @BeforeAll + static void beforeAll() { + UuidString.overrideGenerator(() -> INTEGRATION_ID); + TimeProvider.overrideClock(Clock.fixed(INSTANT_NOW, ZoneId.systemDefault())); + } + + @BeforeEach + void setUp() { + IntegrationCrudService integrationCrudService = integrationCrudServiceInMemory; + usecase = new CreateIntegrationUseCase(integrationCrudService); + } + + @AfterEach + void tearDown() { + integrationCrudServiceInMemory.reset(); + } + + @Test + void should_create_new_integration() { + //Given + var integration = IntegrationFixture.anIntegration(); + var input = CreateIntegrationUseCase.Input.builder().integration(integration).build(); + + //When + CreateIntegrationUseCase.Output output = usecase.execute(input); + + //Then + assertThat(output).isNotNull(); + assertThat(output.createdIntegration().getId()).isEqualTo(INTEGRATION_ID); + assertThat(output.createdIntegration()) + .extracting( + Integration::getName, + Integration::getDescription, + Integration::getProvider, + Integration::getEnvironmentId, + Integration::getCreatedAt, + Integration::getUpdatedAt + ) + .containsExactly( + NAME, + DESCRIPTION, + PROVIDER, + ENV_ID, + ZonedDateTime.ofInstant(INSTANT_NOW, ZoneId.systemDefault()), + ZonedDateTime.ofInstant(INSTANT_NOW, ZoneId.systemDefault()) + ); + } +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/integration/use_case/GetIntegrationsUseCaseTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/integration/use_case/GetIntegrationsUseCaseTest.java new file mode 100644 index 00000000000..9e2d4ad0648 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/integration/use_case/GetIntegrationsUseCaseTest.java @@ -0,0 +1,94 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.apim.core.integration.use_case; + +import static java.util.Optional.of; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import fixtures.core.model.IntegrationFixture; +import inmemory.IntegrationQueryServiceInMemory; +import io.gravitee.apim.core.integration.query_service.IntegrationQueryService; +import io.gravitee.common.data.domain.Page; +import io.gravitee.rest.api.model.common.Pageable; +import io.gravitee.rest.api.model.common.PageableImpl; +import java.util.List; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class GetIntegrationsUseCaseTest { + + private static final String ENV_ID = "my-env"; + private static final int PAGE_NUMBER = 1; + private static final int PAGE_SIZE = 5; + private static final Pageable pageable = new PageableImpl(PAGE_NUMBER, PAGE_SIZE); + + IntegrationQueryServiceInMemory integrationQueryServiceInMemory = new IntegrationQueryServiceInMemory(); + + GetIntegrationsUseCase usecase; + + @BeforeEach + void setUp() { + IntegrationQueryService integrationQueryService = integrationQueryServiceInMemory; + usecase = new GetIntegrationsUseCase(integrationQueryService); + } + + @Test + void should_return_integrations_with_specific_env_id() { + //Given + var expected = IntegrationFixture.anIntegration(); + integrationQueryServiceInMemory.initWith( + List.of(expected, IntegrationFixture.anIntegration("falseEnvID"), IntegrationFixture.anIntegration("anotherFalseEnvID")) + ); + var input = GetIntegrationsUseCase.Input.builder().environmentId(ENV_ID).pageable(of(pageable)).build(); + + //When + var output = usecase.execute(input); + + //Then + assertThat(output).isNotNull(); + assertThat(output.integrations()) + .extracting(Page::getContent, Page::getPageNumber, Page::getPageElements, Page::getTotalElements) + .containsExactly( + List.of(expected), + PAGE_NUMBER, + output.integrations().getPageElements(), + (long) output.integrations().getContent().size() + ); + } + + @Test + void should_return_integrations_with_default_pageable() { + //Given + var expected = IntegrationFixture.anIntegration(); + integrationQueryServiceInMemory.initWith(List.of(expected)); + var input = new GetIntegrationsUseCase.Input(ENV_ID); + + //When + var output = usecase.execute(input); + + //Then + assertThat(output).isNotNull(); + assertThat(output.integrations()) + .extracting(Page::getContent, Page::getPageNumber, Page::getPageElements, Page::getTotalElements) + .containsExactly( + List.of(expected), + PAGE_NUMBER, + output.integrations().getPageElements(), + (long) output.integrations().getContent().size() + ); + } +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/crud_service/integration/IntegrationCrudServiceImplTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/crud_service/integration/IntegrationCrudServiceImplTest.java new file mode 100644 index 00000000000..4f7abcc4c52 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/crud_service/integration/IntegrationCrudServiceImplTest.java @@ -0,0 +1,73 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.apim.infra.crud_service.integration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import fixtures.core.model.IntegrationFixture; +import io.gravitee.apim.core.integration.model.Integration; +import io.gravitee.repository.exceptions.TechnicalException; +import io.gravitee.repository.management.api.IntegrationRepository; +import io.gravitee.rest.api.service.exceptions.TechnicalManagementException; +import lombok.SneakyThrows; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class IntegrationCrudServiceImplTest { + + IntegrationRepository integrationRepository; + + IntegrationCrudServiceImpl service; + + @BeforeEach + void setUp() { + integrationRepository = mock(IntegrationRepository.class); + service = new IntegrationCrudServiceImpl(integrationRepository); + } + + @Test + @SneakyThrows + void should_create_integration() { + //Given + Integration integration = IntegrationFixture.anIntegration(); + when(integrationRepository.create(any())).thenAnswer(invocation -> invocation.getArgument(0)); + + //When + Integration createdIntegration = service.create(integration); + + //Then + assertThat(createdIntegration).isEqualTo(integration); + } + + @Test + void should_throw_when_technical_exception_occurs() throws TechnicalException { + // Given + var integration = IntegrationFixture.anIntegration(); + when(integrationRepository.create(any())).thenThrow(TechnicalException.class); + + // When + Throwable throwable = catchThrowable(() -> service.create(integration)); + + // Then + assertThat(throwable) + .isInstanceOf(TechnicalManagementException.class) + .hasMessage("Error when creating Integration: Test integration"); + } +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/query_service/integration/IntegrationQueryServiceImplTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/query_service/integration/IntegrationQueryServiceImplTest.java new file mode 100644 index 00000000000..fe9a88e76e9 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/query_service/integration/IntegrationQueryServiceImplTest.java @@ -0,0 +1,94 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.apim.infra.query_service.integration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import fixtures.core.model.IntegrationFixture; +import io.gravitee.apim.core.integration.model.Integration; +import io.gravitee.apim.infra.adapter.IntegrationAdapter; +import io.gravitee.common.data.domain.Page; +import io.gravitee.repository.exceptions.TechnicalException; +import io.gravitee.repository.management.api.IntegrationRepository; +import io.gravitee.rest.api.model.common.Pageable; +import io.gravitee.rest.api.model.common.PageableImpl; +import io.gravitee.rest.api.service.exceptions.TechnicalManagementException; +import java.util.List; +import java.util.Optional; +import lombok.SneakyThrows; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class IntegrationQueryServiceImplTest { + + IntegrationRepository integrationRepository; + + IntegrationQueryServiceImpl service; + + @BeforeEach + void setUp() { + integrationRepository = mock(IntegrationRepository.class); + service = new IntegrationQueryServiceImpl(integrationRepository); + } + + @Test + @SneakyThrows + void should_list_integrations_matching_environment_id() { + //Given + var envId = "my-env"; + var pageable = new PageableImpl(1, 5); + var expectedIntegration = IntegrationFixture.anIntegration(); + var page = integrationPage(pageable, expectedIntegration); + when(integrationRepository.findAllByEnvironment(any(), any())).thenReturn(page); + + //When + Page responsePage = service.findByEnvironment(envId, pageable); + + //Then + assertThat(responsePage).isNotNull(); + assertThat(responsePage.getPageNumber()).isEqualTo(1); + assertThat(responsePage.getPageElements()).isEqualTo(1); + assertThat(responsePage.getTotalElements()).isEqualTo(1); + assertThat(responsePage.getContent().get(0)).isEqualTo(expectedIntegration); + } + + @Test + @SneakyThrows + void should_throw_when_technical_exception_occurs() { + // Given + var envId = "different-env"; + var pageable = new PageableImpl(1, 5); + when(integrationRepository.findAllByEnvironment(any(), any())).thenThrow(TechnicalException.class); + + // When + Throwable throwable = catchThrowable(() -> service.findByEnvironment(envId, pageable)); + + // Then + assertThat(throwable) + .isInstanceOf(TechnicalManagementException.class) + .hasMessage("An error occurred while finding Integrations by environment id: different-env"); + } + + Page integrationPage(Pageable pageable, Integration integration) { + var repositoryIntegration = IntegrationAdapter.INSTANCE.toRepository(integration); + var integrations = List.of(repositoryIntegration); + return new Page<>(integrations, pageable.getPageNumber(), integrations.size(), integrations.size()); + } +}