diff --git a/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendApplicationDefaultHelpers.java b/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendApplicationDefaultHelpers.java index 5db1fada..58aadc51 100644 --- a/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendApplicationDefaultHelpers.java +++ b/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendApplicationDefaultHelpers.java @@ -108,6 +108,17 @@ public Collection findAggregateInputs(Map aggregate, Options options) { return new HashSet<>(JSONPath.get(aggregate, "$.commands[*].parameter", List.of())); } + public Collection findAggregates(Collection entities, Options options) { + return entities.stream().filter(entity -> isAggregate((String) entity.get("name"), options)).collect(Collectors.toList()); + } + + public boolean isAggregate(String entityName, Options options) { + var zdl = options.get("zdl"); + var isAggregateRoot = JSONPath.get(zdl, "$.entities." + entityName + "[?(@.options.aggregate == true)]", List.of()); + var aggregateName = findEntityAggregate(entityName, options); + return !isAggregateRoot.isEmpty() || aggregateName != null; + } + public String findEntityAggregate(String entityName, Options options) { var zdl = options.get("zdl"); var aggregateNames = JSONPath.get(zdl, "$.aggregates[*][?(@.aggregateRoot == '" + entityName + "')].name", List.of()); diff --git a/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendMultiModuleApplicationGenerator.java b/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendMultiModuleApplicationGenerator.java index 9ee7741a..00d97c15 100644 --- a/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendMultiModuleApplicationGenerator.java +++ b/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendMultiModuleApplicationGenerator.java @@ -65,6 +65,10 @@ protected ZDLProjectTemplates configureProjectTemplates() { "{{asPackageFolder configPackage}}/TestDataLoader.java", JAVA, null, true); ts.addTemplate(ts.singleTemplates, "src/test/java", "config/DockerComposeInitializer-{{persistence}}.java", "{{mavenModulesPrefix}}-core-impl", "{{asPackageFolder configPackage}}/DockerComposeInitializer.java", JAVA, null, true); + ts.addTemplate(ts.singleTemplates, "src/test/java", "config/TestDataLoader-{{persistence}}.java", "{{mavenModulesPrefix}}-infra", + "{{asPackageFolder configPackage}}/TestDataLoader.java", JAVA, null, true); + ts.addTemplate(ts.singleTemplates, "src/test/java", "config/DockerComposeInitializer-{{persistence}}.java", "{{mavenModulesPrefix}}-infra", + "{{asPackageFolder configPackage}}/DockerComposeInitializer.java", JAVA, null, true); ts.addTemplate(ts.singleTemplates, "src/main/java", "core/inbound/dtos/package-info.java", "{{mavenModulesPrefix}}-domain", "{{asPackageFolder inboundDtosPackage}}/package-info.java", JAVA, null, true); diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/jpa/Entity.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/jpa/Entity.java.hbs index 59a92b5f..d3ad9bd6 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/jpa/Entity.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/jpa/Entity.java.hbs @@ -109,7 +109,9 @@ public {{abstractClass entity}} class {{entity.className}} {{addExtends entity}} {{~#if (eq relationship.type 'OneToOne')}} public {{entity.className}} set{{capitalize relationship.fieldName}}({{{relationshipFieldType relationship}}} {{relationship.fieldName}}) { this.{{relationship.fieldName}} = {{relationship.fieldName}}; - {{relationship.fieldName}}.set{{capitalize relationship.otherEntityFieldName}}(this); + if ({{relationship.fieldName}} != null) { + {{relationship.fieldName}}.set{{capitalize relationship.otherEntityFieldName}}(this); + } return this; } {{~/if}} @@ -119,6 +121,11 @@ public {{abstractClass entity}} class {{entity.className}} {{addExtends entity}} {{relationship.fieldName}}.set{{capitalize relationship.otherEntityFieldName}}(this); return this; } + public {{entity.className}} remove{{capitalize relationship.fieldName}}({{relationship.otherEntityName}} {{relationship.fieldName}}) { + this.{{relationship.fieldName}}.remove({{relationship.fieldName}}); + {{relationship.fieldName}}.set{{capitalize relationship.otherEntityFieldName}}(null); + return this; + } {{~/if}} {{~#if (eq relationship.type 'ManyToMany')}} public {{entity.className}} add{{capitalize relationship.fieldName}}({{relationship.otherEntityName}} {{relationship.fieldName}}) { @@ -126,6 +133,11 @@ public {{abstractClass entity}} class {{entity.className}} {{addExtends entity}} {{relationship.fieldName}}.get{{capitalize relationship.otherEntityFieldName}}().add(this); return this; } + public {{entity.className}} remove{{capitalize relationship.fieldName}}({{relationship.otherEntityName}} {{relationship.fieldName}}) { + this.{{relationship.fieldName}}.remove({{relationship.fieldName}}); + {{relationship.fieldName}}.get{{capitalize relationship.otherEntityFieldName}}().remove(this); + return this; + } {{~/if}} {{~#if (and (eq relationship.type 'ManyToOne') relationship.otherEntityFieldName)}} public {{entity.className}} set{{capitalize relationship.fieldName}}({{{relationshipFieldType relationship}}} {{relationship.fieldName}}) { @@ -133,6 +145,11 @@ public {{abstractClass entity}} class {{entity.className}} {{addExtends entity}} {{relationship.fieldName}}.get{{capitalize relationship.otherEntityFieldName}}().add(this); return this; } + public {{entity.className}} remove{{capitalize relationship.fieldName}}({{{relationshipFieldType relationship}}} {{relationship.fieldName}}) { + this.{{relationship.fieldName}} = {{relationship.fieldName}}; + {{relationship.fieldName}}.get{{capitalize relationship.otherEntityFieldName}}().remove(this); + return this; + } {{~/if}} {{/each}} diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/implementation/partials/jpa/entities-crud-methodBody.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/implementation/partials/jpa/entities-crud-methodBody.hbs index 6b8cf897..e9e3481c 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/implementation/partials/jpa/entities-crud-methodBody.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/implementation/partials/jpa/entities-crud-methodBody.hbs @@ -6,13 +6,6 @@ // TODO: you may need to reload the entity here to fetch relationships 'mapped by id' {{~> (partial '../withEvents')}} return {{wrapWithMapper entity}}; -{{~else if (isCrudMethod 'update' method=method entity=entity )}} - log.debug("[CRUD] Request to update {{entity.className}}: {}", input); - var {{entity.instanceName}} = {{entity.instanceName}}Repository.findById(id); - // saving is unnecessary: https://vladmihalcea.com/best-spring-data-jparepository/ - {{entity.instanceName}} = {{entity.instanceName}}.map(existing{{entity.instanceName}} -> {{asInstanceName service.name}}Mapper.update(existing{{entity.instanceName}}, {{{mapperInputCallSignature method.parameter}}})); - {{~> (partial '../withEvents')}} - return {{wrapWithMapper entity}}; {{~else if (isCrudMethod 'list' method=method entity=entity )}} {{~#if method.options.paginated}} log.debug("[CRUD] Request list of {{entity.classNamePlural}}: {}", pageable); diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/implementation/partials/jpa/entities-methodBody.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/implementation/partials/jpa/entities-methodBody.hbs index 2d94f98e..6ad2ac27 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/implementation/partials/jpa/entities-methodBody.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/implementation/partials/jpa/entities-methodBody.hbs @@ -17,8 +17,7 @@ var {{entity.instanceName}} = {{entity.instanceName}}Repository.findById(id).map(existing{{entity.className}} -> { return {{asInstanceName service.name}}Mapper.update(existing{{entity.className}}, {{{mapperInputCallSignature method.parameter}}}); }) - // saving is unnecessary https://vladmihalcea.com/best-spring-data-jparepository/ - // .map({{entity.instanceName}}Repository::save) + .map({{entity.instanceName}}Repository::save) {{~#unless (eq entity.name method.returnType)}} .map({{asInstanceName service.name}}Mapper::as{{returnType}}) {{~/unless}} @@ -30,8 +29,7 @@ var {{entity.instanceName}} = {{entity.instanceName}}Repository.findById(id).map(existing{{entity.className}} -> { return {{asInstanceName service.name}}Mapper.update(existing{{entity.className}}, {{{mapperInputCallSignature method.parameter}}}); }) - // saving is unnecessary https://vladmihalcea.com/best-spring-data-jparepository/ - // .map({{entity.instanceName}}Repository::save) + .map({{entity.instanceName}}Repository::save) .orElseThrow(); {{~> (partial '../withEvents')}} return {{wrapWithMapper entity}}; diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/DockerComposeInitializer-jpa.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/DockerComposeInitializer-jpa.java.hbs index bffc3168..4db36ac3 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/DockerComposeInitializer-jpa.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/DockerComposeInitializer-jpa.java.hbs @@ -1,7 +1,9 @@ package {{basePackage}}.config; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.io.InputStreamReader; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -36,64 +38,86 @@ public class DockerComposeInitializer implements ApplicationContextInitializer SERVICES = List.of( + new Service("postgresql", 5432, "DATASOURCE_URL", "jdbc:postgresql://%s:%s/DATABASENAME"), + new Service("kafka", 9092, "KAFKA_BOOTSTRAP_SERVERS", "%s:%s") + ); + + static String HOST = DockerClientFactory.instance().dockerHostIpAddress(); + static DockerComposeContainer container = new DockerComposeContainer(new File(DOCKER_COMPOSE_FILE)).withEnv("HOST", HOST); + static { + for (Service service : SERVICES) { + if("schema-registry".equals(service.name)) { + container.withExposedService(service.name, service.port, Wait.forHttp("/subjects").forStatusCode(200)); + } + else { + container.withExposedService(service.name, service.port, Wait.forListeningPort()); + } + } + } + static boolean isContainerRunning = false; @SneakyThrows @Override public void initialize(ConfigurableApplicationContext ctx) { - if(isDockerComposeRunningAllServices(NUMBER_OF_SERVICES)) { + if(isDockerComposeRunningAllServices(SERVICES)) { log.info("Docker Compose Containers are running from local docker-compose. Skipping TestContainers..."); } else { log.info("Docker Compose Containers are not running from local docker-compose. Starting from TestContainers..."); if (isContainerRunning) { log.info("Docker Compose Containers are already running from TestContainers. Skipping..."); } else { - log.info("Starting Docker Compose Containers from TestContainers..."); - container.start(); - isContainerRunning = true; - - // TODO: Replace with JPA... - int mongodbPort = container.getServicePort("mongodb", 27017); - log.info("Docker Compose Containers are running from TestContainers. Mongodb: {}", HOST + ":" + mongodbPort); - - log.info("Container Ports Status: Mongodb: {}", isPortOpen(HOST, mongodbPort)); - - TestPropertyValues.of( - String.format("MONGODB_URI=mongodb://%s:%s/REVIEW?replicaSet=rs0", HOST, mongodbPort) - ).applyTo(ctx.getEnvironment()); + log.info("Starting Docker Compose Containers from TestContainers..."); + container.start(); + isContainerRunning = true; + + for (Service service : SERVICES) { + int port = container.getServicePort(service.name, service.port); + log.info("DockerCompose exposed port for {}: {}", service.name, HOST + ":" + port); + log.info("DockerCompose Service {} listening: {}", service.name, isPortOpen(HOST, port)); + if (service.envValueTemplate != null) { + TestPropertyValues.of(service.envVar + "=" +String.format(service.envValueTemplate, HOST, port)) + .applyTo(ctx.getEnvironment()); + } + } } } } - private boolean isDockerComposeRunningAllServices(int numberOfServices) { - return Stream.of("docker-compose", "docker-compose.exe").anyMatch(cmd -> { - try { - return readProcessOutputStream(cmd, "-f", "src/main/docker/docker-compose.yml", "ps").size() == (numberOfServices + 1); - } catch (IOException | InterruptedException e) { - return false; - } - }); - } - - private List readProcessOutputStream(String ...command) throws IOException, InterruptedException { - var process = new ProcessBuilder(command).start(); - var reader = new java.io.BufferedReader(new java.io.InputStreamReader(process.getInputStream())); - var line = ""; - var output = new ArrayList(); - while ((line = reader.readLine()) != null) { - output.add(line); - } - process.waitFor(); - return output; - } + private boolean isDockerComposeRunningAllServices(List services) { + var serviceNames = services.stream().map(Service::name).toList(); + return Stream.of("docker-compose", "docker-compose.exe").anyMatch(cmd -> { + try { + return getDockerComposeRunningServices(cmd, "-f", DOCKER_COMPOSE_FILE, "ps").containsAll(serviceNames); + } + catch (IOException | InterruptedException e) { + return false; + } + }); + } + + private static final int SERVICE_COLUMN = 3; + public List getDockerComposeRunningServices(String... command) throws IOException, InterruptedException { + List services = new ArrayList<>(); + var process = new ProcessBuilder(command).start(); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + + String line; + while ((line = reader.readLine()) != null) { + if (!line.isEmpty()) { + String[] columns = line.split("\\s+"); + if (columns.length > SERVICE_COLUMN) { + services.add(columns[SERVICE_COLUMN]); + } + } + } + + process.waitFor(); + return services.size() > 1? services.subList(1, services.size()) : services; + } boolean isPortOpen(String host, int port) { try (Socket socket = new Socket(host, port)) { diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/DockerComposeInitializer-mongodb.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/DockerComposeInitializer-mongodb.java.hbs index da4405da..ef15f2c4 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/DockerComposeInitializer-mongodb.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/DockerComposeInitializer-mongodb.java.hbs @@ -1,7 +1,9 @@ package {{basePackage}}.config; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.io.InputStreamReader; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -36,20 +38,32 @@ public class DockerComposeInitializer implements ApplicationContextInitializer SERVICES = List.of( + new Service("mongodb", 27017, "MONGODB_URI", "mongodb://%s:%s/DATABASENAME?replicaSet=rs0"), + new Service("kafka", 9092, "KAFKA_BOOTSTRAP_SERVERS", "%s:%s") + ); + + static String HOST = DockerClientFactory.instance().dockerHostIpAddress(); + static DockerComposeContainer container = new DockerComposeContainer(new File(DOCKER_COMPOSE_FILE)).withEnv("HOST", HOST); + static { + for (Service service : SERVICES) { + if("schema-registry".equals(service.name)) { + container.withExposedService(service.name, service.port, Wait.forHttp("/subjects").forStatusCode(200)); + } + else { + container.withExposedService(service.name, service.port, Wait.forListeningPort()); + } + } + } + static boolean isContainerRunning = false; @SneakyThrows @Override public void initialize(ConfigurableApplicationContext ctx) { - if(isDockerComposeRunningAllServices(NUMBER_OF_SERVICES)) { + if(isDockerComposeRunningAllServices(SERVICES)) { log.info("Docker Compose Containers are running from local docker-compose. Skipping TestContainers..."); } else { log.info("Docker Compose Containers are not running from local docker-compose. Starting from TestContainers..."); @@ -60,39 +74,50 @@ public class DockerComposeInitializer implements ApplicationContextInitializer { - try { - return readProcessOutputStream(cmd, "-f", "src/main/docker/docker-compose.yml", "ps").size() == (numberOfServices + 1); - } catch (IOException | InterruptedException e) { - return false; - } - }); - } - - private List readProcessOutputStream(String ...command) throws IOException, InterruptedException { - var process = new ProcessBuilder(command).start(); - var reader = new java.io.BufferedReader(new java.io.InputStreamReader(process.getInputStream())); - var line = ""; - var output = new ArrayList(); - while ((line = reader.readLine()) != null) { - output.add(line); - } - process.waitFor(); - return output; - } + private boolean isDockerComposeRunningAllServices(List services) { + var serviceNames = services.stream().map(Service::name).toList(); + return Stream.of("docker-compose", "docker-compose.exe").anyMatch(cmd -> { + try { + return getDockerComposeRunningServices(cmd, "-f", DOCKER_COMPOSE_FILE, "ps").containsAll(serviceNames); + } + catch (IOException | InterruptedException e) { + return false; + } + }); + } + + private static final int SERVICE_COLUMN = 3; + public List getDockerComposeRunningServices(String... command) throws IOException, InterruptedException { + List services = new ArrayList<>(); + var process = new ProcessBuilder(command).start(); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + + String line; + while ((line = reader.readLine()) != null) { + if (!line.isEmpty()) { + String[] columns = line.split("\\s+"); + if (columns.length > SERVICE_COLUMN) { + services.add(columns[SERVICE_COLUMN]); + } + } + } + + process.waitFor(); + return services.size() > 1? services.subList(1, services.size()) : services; + } boolean isPortOpen(String host, int port) { try (Socket socket = new Socket(host, port)) { diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/RepositoriesInMemoryConfig.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/RepositoriesInMemoryConfig.java.hbs index b13c8d5a..bc0e206a 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/RepositoriesInMemoryConfig.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/RepositoriesInMemoryConfig.java.hbs @@ -10,14 +10,13 @@ import {{infrastructureRepositoryPackage}}.inmemory.*; //@Configuration public class RepositoriesInMemoryConfig { -{{~#each services as |service|}} - {{~#each service.entities as |entity|}} +{{assign "aggregates" (findAggregates entities)}} +{{~#each aggregates as |entity|}} protected final {{entity.className}}Repository {{entity.instanceName}}Repository = new {{entity.className}}RepositoryInMemory(); @Bean @Primary public T {{entity.instanceName}}Repository() { return (T) {{entity.instanceName}}Repository; } - {{~/each}} {{~/each}} } diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/ServicesInMemoryConfig.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/ServicesInMemoryConfig.java.hbs index 044fab97..d9bd9fd5 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/ServicesInMemoryConfig.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/ServicesInMemoryConfig.java.hbs @@ -55,7 +55,7 @@ public class ServicesInMemoryConfig extends RepositoriesInMemoryConfig { } {{~/each}} -{{assign "aggregates" (jsonPath entities "[*][?(@.options.aggregate)]")}} +{{assign "aggregates" (findAggregates entities)}} {{~#each aggregates as |entity|}} static List<{{entity.className}}> _{{entity.instanceNamePlural}}; {{~/each}} @@ -63,8 +63,8 @@ public class ServicesInMemoryConfig extends RepositoriesInMemoryConfig { var testDataLoader = new TestDataLoader(List.of({{#joinWithTemplate entities delimiter=', ' as |entity|}}{{entity.className}}.class{{/joinWithTemplate}})); {{~#each aggregates as |entity|}} var {{entity.instanceNamePlural}} = _{{entity.instanceNamePlural}} != null? _{{entity.instanceNamePlural}} : testDataLoader.loadCollectionTestDataAsObjects({{entity.className}}.class); - {{entity.className}}Repository().deleteAll(); - {{entity.className}}Repository().saveAll({{entity.instanceNamePlural}}); + {{entity.instanceName}}Repository().deleteAll(); + {{entity.instanceName}}Repository().saveAll({{entity.instanceNamePlural}}); {{~/each}} } diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/TestDataLoader-jpa.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/TestDataLoader-jpa.java.hbs index 5e233456..09994b47 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/TestDataLoader-jpa.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/TestDataLoader-jpa.java.hbs @@ -1,5 +1,7 @@ package {{basePackage}}.config; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.persistence.Table; import java.io.File; @@ -13,6 +15,8 @@ public class TestDataLoader { private List> jpaManagedTypes; + private ObjectMapper objectMapper = new ObjectMapper(); + public TestDataLoader(List> jpaManagedTypes) { this.jpaManagedTypes = jpaManagedTypes; } @@ -28,14 +32,6 @@ public class TestDataLoader { return readDirectoryFilesAsString("src/test/resources/data/jpa/" + table); } - public List loadCollectionTestDataAsJson(String table) { - return readDirectoryFilesAsString("src/test/resources/data/jpa/" + table); - } - - public List listAllMongodbCollectionsWithTestData() { - return listFolders("src/test/resources/data/jpa"); - } - protected List listFolders(String directory) { return Stream.of(new File(directory).listFiles()).map(File::getName).collect(Collectors.toList()); } @@ -51,7 +47,11 @@ public class TestDataLoader { } public T read(Class type, String json) { - return null; // TODO + try { + return objectMapper.readValue(json, type); + } catch (JsonProcessingException e) { + throw new RuntimeException("Error reading json test data for " + type.getName(), e); + } } } diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/core/implementation/jpa/imperative/ServiceTest.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/core/implementation/jpa/imperative/ServiceTest.java.hbs index 64091edb..6f91a924 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/core/implementation/jpa/imperative/ServiceTest.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/core/implementation/jpa/imperative/ServiceTest.java.hbs @@ -9,10 +9,7 @@ import {{outboundRepositoryPackage}}.*; import {{infrastructureRepositoryPackage}}.inmemory.*; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; import org.mapstruct.factory.Mappers; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,7 +29,6 @@ import static org.mockito.Mockito.*; /** * Acceptance Test for {{service.name}}. */ -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class {{service.name}}Test { private final Logger log = LoggerFactory.getLogger(getClass()); @@ -48,41 +44,9 @@ public class {{service.name}}Test { context.reloadTestData(); } -{{#each entities as |entity|}} - @Test - @Order(0) - void testCRUD{{entity.className}}() { - /* - var input = new {{entity.className}}{{inputDTOSuffix}}(); - // TODO fill input data - {{~#each entity.fields as |field|}} - // input.set{{capitalize field.name}}({{{populateField field}}}); - {{~/each}} - var {{entity.instanceName}} = {{serviceInstance}}.create{{entity.className}}(input); - assertNotNull({{entity.instanceName}}.getId()); - assertTrue({{entity.instanceName}}Repository.containsEntity({{entity.instanceName}})); - - var id = {{entity.instanceName}}.getId(); - var {{entity.instanceName}}Update = new {{entity.className}}{{inputDTOSuffix}}(); - // TODO fill update data - {{~#each entity.fields as |field|}} - // {{entity.instanceName}}Update.set{{capitalize field.name}}({{{populateField field}}}); - {{~/each}} - assertTrue({{entity.instanceName}}Repository.containsKey(id)); - var {{entity.instanceName}}Updated = {{serviceInstance}}.update{{entity.className}}(id, {{entity.instanceName}}Update); - assertTrue({{entity.instanceName}}Updated.isPresent()); - assertTrue({{entity.instanceName}}Repository.containsEntity({{entity.instanceName}}Updated.get())); - - assertTrue({{entity.instanceName}}Repository.containsKey(id)); - {{serviceInstance}}.delete{{entity.className}}(id); - assertFalse({{entity.instanceName}}Repository.containsKey(id)); - */ - } -{{/each}} {{#each service.methods as |method|}} @Test - @Order({{@index}}) void {{method.name}}Test() { {{~> (partial 'testMethodBody')~}} } diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/core/implementation/mongodb/imperative/ServiceTest.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/core/implementation/mongodb/imperative/ServiceTest.java.hbs index 384f8882..130b935a 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/core/implementation/mongodb/imperative/ServiceTest.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/core/implementation/mongodb/imperative/ServiceTest.java.hbs @@ -10,10 +10,7 @@ import {{infrastructureRepositoryPackage}}.inmemory.*; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; import org.mapstruct.factory.Mappers; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,7 +28,6 @@ import static org.mockito.Mockito.*; /** * Acceptance Test for {{service.name}}. */ -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class {{service.name}}Test { private final Logger log = LoggerFactory.getLogger(getClass()); @@ -47,35 +43,8 @@ public class {{service.name}}Test { context.reloadTestData(); } -{{#each entities as |entity|}} - @Test - @Order(0) - void testCRUD{{entity.className}}() { - /* - var input = new {{entity.className}}{{inputDTOSuffix}}(); - // TODO fill input data - var {{entity.instanceName}} = {{serviceInstance}}.create{{entity.className}}(input); - assertNotNull({{entity.instanceName}}.getId()); - assertTrue({{entity.instanceName}}Repository.containsEntity({{entity.instanceName}})); - - var id = {{entity.instanceName}}.getId(); - var {{entity.instanceName}}Update = new {{entity.className}}{{inputDTOSuffix}}(); - // TODO fill update data - assertTrue({{entity.instanceName}}Repository.containsKey(id)); - var {{entity.instanceName}}Updated = {{serviceInstance}}.update{{entity.className}}(id, {{entity.instanceName}}Update); - assertTrue({{entity.instanceName}}Updated.isPresent()); - assertTrue({{entity.instanceName}}Repository.containsEntity({{entity.instanceName}}Updated.get())); - - assertTrue({{entity.instanceName}}Repository.containsKey(id)); - {{serviceInstance}}.delete{{entity.className}}(id); - assertFalse({{entity.instanceName}}Repository.containsKey(id)); - */ - } -{{/each}} - {{#each service.methods as |method|}} @Test - @Order({{@index}}) void {{method.name}}Test() { {{~> (partial 'testMethodBody')~}} } diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/jpa/imperative/BaseRepositoryIntegrationTest.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/jpa/imperative/BaseRepositoryIntegrationTest.java.hbs index 8d0fc960..7c9c1774 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/jpa/imperative/BaseRepositoryIntegrationTest.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/jpa/imperative/BaseRepositoryIntegrationTest.java.hbs @@ -1,10 +1,12 @@ package {{infrastructureRepositoryPackage}}; +import {{configPackage}}.DockerComposeInitializer; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) @ActiveProfiles("test") +@DockerComposeInitializer.EnableDockerCompose @org.springframework.transaction.annotation.Transactional public abstract class BaseRepositoryIntegrationTest { } diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/mongodb/imperative/BaseRepositoryIntegrationTest.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/mongodb/imperative/BaseRepositoryIntegrationTest.java.hbs index 8d0fc960..7c9c1774 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/mongodb/imperative/BaseRepositoryIntegrationTest.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/mongodb/imperative/BaseRepositoryIntegrationTest.java.hbs @@ -1,10 +1,12 @@ package {{infrastructureRepositoryPackage}}; +import {{configPackage}}.DockerComposeInitializer; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) @ActiveProfiles("test") +@DockerComposeInitializer.EnableDockerCompose @org.springframework.transaction.annotation.Transactional public abstract class BaseRepositoryIntegrationTest { } diff --git a/plugins/openapi-controllers/src/main/java/io/zenwave360/sdk/plugins/OpenAPIControllersGenerator.java b/plugins/openapi-controllers/src/main/java/io/zenwave360/sdk/plugins/OpenAPIControllersGenerator.java index e2142064..e9c2f66c 100644 --- a/plugins/openapi-controllers/src/main/java/io/zenwave360/sdk/plugins/OpenAPIControllersGenerator.java +++ b/plugins/openapi-controllers/src/main/java/io/zenwave360/sdk/plugins/OpenAPIControllersGenerator.java @@ -51,6 +51,8 @@ public class OpenAPIControllersGenerator extends AbstractOpenAPIGenerator { @DocumentedOption(description = "Programming Style") public ProgrammingStyle style = ProgrammingStyle.imperative; + public boolean simpleDomainPackaging = false; + @DocumentedOption(description = "JSONPath list to search for response DTO schemas for list or paginated results. User '$.items' for lists or '$.properties..items' for paginated results.") public List paginatedDtoItemsJsonPath = List.of("$.items", "$.properties.content.items"); @@ -77,6 +79,16 @@ protected TemplateInput asTemplateInput(Object[] templateNames) { .withSkip(skip); } + @Override + public void onPropertiesSet() { + if (simpleDomainPackaging) { + controllersPackage = "{{basePackage}}"; + entitiesPackage = "{{basePackage}}.model"; + inboundDtosPackage = "{{basePackage}}.dtos"; + servicesPackage = "{{basePackage}}"; + } + } + protected Map getZDLModel(Map contextModel) { return (Map) contextModel.get(zdlProperty); } diff --git a/plugins/openapi-controllers/src/main/resources/io/zenwave360/sdk/plugins/OpenAPIControllersGenerator/src/main/java/web/mvc/ServiceApiController.java.hbs b/plugins/openapi-controllers/src/main/resources/io/zenwave360/sdk/plugins/OpenAPIControllersGenerator/src/main/java/web/mvc/ServiceApiController.java.hbs index 2490d990..9d0720f2 100644 --- a/plugins/openapi-controllers/src/main/resources/io/zenwave360/sdk/plugins/OpenAPIControllersGenerator/src/main/java/web/mvc/ServiceApiController.java.hbs +++ b/plugins/openapi-controllers/src/main/resources/io/zenwave360/sdk/plugins/OpenAPIControllersGenerator/src/main/java/web/mvc/ServiceApiController.java.hbs @@ -50,6 +50,12 @@ public class {{serviceName}}ApiController implements {{serviceName}}Api { private {{serviceName}}DTOsMapper mapper = {{serviceName}}DTOsMapper.INSTANCE; + public {{serviceName}}ApiController({{#joinWithTemplate entitiesServices delimiter=", "}}{{this}} {{asInstanceName this}}{{/joinWithTemplate}}) { + {{#joinWithTemplate entitiesServices}} + this.{{asInstanceName this}} = {{asInstanceName this}}; + {{/joinWithTemplate}} + } + @Override public Optional getRequest() { return Optional.ofNullable(request); @@ -84,6 +90,9 @@ public class {{serviceName}}ApiController implements {{serviceName}}Api { {{responseDtoName}} responseDTO = mapper.as{{responseDtoName}}({{methodReturnTypeInstance}}); return ResponseEntity.status({{statusCode}}).body(responseDTO); {{~/if}} + {{~else if (and serviceMethod.serviceName serviceMethodCall)}} + {{asInstanceName serviceMethod.serviceName}}.{{serviceMethodCall}}; + return ResponseEntity.status({{statusCode}}).build(); {{~else}} // TODO: {{asInstanceName serviceMethod.serviceName}}.{{serviceMethodCall}}; return ResponseEntity.status({{statusCode}}).build(); diff --git a/plugins/openapi-controllers/src/main/resources/io/zenwave360/sdk/plugins/OpenAPIControllersGenerator/src/test/java/web/mvc/ServiceApiControllerTest.java.hbs b/plugins/openapi-controllers/src/main/resources/io/zenwave360/sdk/plugins/OpenAPIControllersGenerator/src/test/java/web/mvc/ServiceApiControllerTest.java.hbs index 467a745e..7e7356d6 100644 --- a/plugins/openapi-controllers/src/main/resources/io/zenwave360/sdk/plugins/OpenAPIControllersGenerator/src/test/java/web/mvc/ServiceApiControllerTest.java.hbs +++ b/plugins/openapi-controllers/src/main/resources/io/zenwave360/sdk/plugins/OpenAPIControllersGenerator/src/test/java/web/mvc/ServiceApiControllerTest.java.hbs @@ -23,11 +23,7 @@ public class {{serviceName}}ApiControllerTest { ServicesInMemoryConfig context = new ServicesInMemoryConfig(); - {{serviceName}}ApiController controller = new {{serviceName}}ApiController() -{{#each entitiesServices as |coreServiceName|}} - .set{{coreServiceName}}(context.{{asInstanceName coreServiceName}}()) -{{/each}} - ; + {{serviceName}}ApiController controller = new {{serviceName}}ApiController({{#joinWithTemplate entitiesServices delimiter=", "}} context.{{asInstanceName this}}() {{/joinWithTemplate}}); @BeforeEach void setUp() { diff --git a/plugins/openapi-controllers/src/test/java/io/zenwave360/sdk/plugins/OpenAPIControllersGeneratorTest.java b/plugins/openapi-controllers/src/test/java/io/zenwave360/sdk/plugins/OpenAPIControllersGeneratorTest.java index 37d4d731..d91d8462 100644 --- a/plugins/openapi-controllers/src/test/java/io/zenwave360/sdk/plugins/OpenAPIControllersGeneratorTest.java +++ b/plugins/openapi-controllers/src/test/java/io/zenwave360/sdk/plugins/OpenAPIControllersGeneratorTest.java @@ -69,4 +69,27 @@ public void test_generator_openapi_controllers_zdl_customer_address() throws Exc // Assertions.assertTrue(logs.contains("Writing template with targetFile: io/example/integration/test/api/provider_for_commands_reactive/DoCreateProductService.java")); } + @Test + public void test_generator_openapi_controllers_zdl_customer_address_simple_domain_packaging() throws Exception { + Plugin plugin = new OpenAPIControllersPlugin() + .withSpecFile("classpath:io/zenwave360/sdk/resources/openapi/customer-address-openapi.yml") + .withOption("zdlFile", "classpath:io/zenwave360/sdk/resources/zdl/customer-address.zdl") + .withOption("basePackage", "io.zenwave360.example") + .withOption("simpleDomainPackaging", true) + .withOption("openApiApiPackage", "io.zenwave360.example.web.api") + .withOption("openApiModelPackage", "io.zenwave360.example.web.api.model") + .withOption("openApiModelNameSuffix", "DTO") + // .withOption("operationIds", List.of("addPet", "updatePet")) + .withOption("style", ProgrammingStyle.imperative) + // .withOption("haltOnFailFormatting", false) + .withTargetFolder("target/out/customer_address_simple_domain_packaging"); + + new MainGenerator().generate(plugin); + + List logs = logCaptor.getLogs(); + // Assertions.assertTrue(logs.contains("Writing template with targetFile: io/example/integration/test/api/provider_for_commands_reactive/DoCreateProductConsumer.java")); + // Assertions.assertTrue(logs.contains("Writing template with targetFile: io/example/integration/test/api/provider_for_commands_reactive/DoCreateProductService.java")); + } + + } diff --git a/plugins/openapi-spring-webtestclient/src/main/java/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator.java b/plugins/openapi-spring-webtestclient/src/main/java/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator.java index d7dca895..da30624a 100644 --- a/plugins/openapi-spring-webtestclient/src/main/java/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator.java +++ b/plugins/openapi-spring-webtestclient/src/main/java/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator.java @@ -24,10 +24,24 @@ enum GroupByType { service, operation, partial, businessFlow } - public String sourceProperty = "api"; + public String apiProperty = "api"; + + @DocumentedOption(description = "The package to generate REST Controllers") + public String controllersPackage = "{{basePackage}}.adapters.web"; + + public String configPackage = "{{basePackage}}.config"; + + @DocumentedOption(description = "Package where your domain entities are") + public String entitiesPackage = "{{basePackage}}.core.domain"; + + @DocumentedOption(description = "Package where your inbound dtos are") + public String inboundDtosPackage = "{{basePackage}}.core.inbound.dtos"; + + @DocumentedOption(description = "Package where your domain services/usecases interfaces are") + public String servicesPackage = "{{basePackage}}.core.inbound"; @DocumentedOption(description = "Package name for generated tests") - public String testsPackage = "{{basePackage}}.adapters.web.tests"; + public String testsPackage = "{{basePackage}}.adapters.web"; @DocumentedOption(description = "Generate test classes grouped by", required = true) public GroupByType groupBy = GroupByType.service; @@ -50,29 +64,42 @@ enum GroupByType { @DocumentedOption(description = "@Transactional annotation class name") public String transactionalAnnotationClass = "org.springframework.transaction.annotation.Transactional"; - public SpringWebTestClientGenerator withSourceProperty(String sourceProperty) { - this.sourceProperty = sourceProperty; - return this; - } + public boolean simpleDomainPackaging = false; private HandlebarsEngine handlebarsEngine = new HandlebarsEngine(); - private String prefix = "io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/"; - private final TemplateInput partialTemplate = new TemplateInput(prefix + "partials/Operation.java", "{{asPackageFolder testsPackage}}/Operation.java"); + private final String prefix = "io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/"; + private final TemplateInput partialTemplate = new TemplateInput(prefix + "partials/Operation.java", "src/test/java/{{asPackageFolder testsPackage}}/Operation.java"); // private final TemplateInput testSetTemplate = new TemplateInput(prefix + "ControllersTestSet.java", "{{asPackageFolder testsPackage}}/ControllersTestSet.java").withMimeType(JAVA); - private final TemplateInput baseTestClassTemplate = new TemplateInput(prefix + "BaseWebTestClientTest.java", "{{asPackageFolder baseTestClassPackage}}/{{baseTestClassName}}.java").withMimeType(JAVA).withSkipOverwrite(true); + private final TemplateInput baseTestClassTemplate = new TemplateInput(prefix + "BaseWebTestClientTest.java", "src/test/java/{{asPackageFolder baseTestClassPackage}}/{{baseTestClassName}}.java").withMimeType(JAVA).withSkipOverwrite(true); - private final TemplateInput businessFlowTestTemplate = new TemplateInput(prefix + "BusinessFlowTest.java", "{{asPackageFolder testsPackage}}/{{businessFlowTestName}}.java").withMimeType(JAVA); - private final TemplateInput serviceTestTemplate = new TemplateInput(prefix + "ServiceIT.java", "{{asPackageFolder testsPackage}}/{{serviceName}}{{testSuffix}}.java").withMimeType(JAVA); - private final TemplateInput operationTestTemplate = new TemplateInput(prefix + "OperationIT.java", "{{asPackageFolder testsPackage}}/{{serviceName}}/{{asJavaTypeName operationId}}{{testSuffix}}.java").withMimeType(JAVA); + private final TemplateInput businessFlowTestTemplate = new TemplateInput(prefix + "BusinessFlowTest.java", "src/test/java/{{asPackageFolder testsPackage}}/{{businessFlowTestName}}.java").withMimeType(JAVA); + private final TemplateInput serviceTestTemplate = new TemplateInput(prefix + "ServiceIT.java", "src/test/java/{{asPackageFolder testsPackage}}/{{serviceName}}{{testSuffix}}.java").withMimeType(JAVA); + private final TemplateInput operationTestTemplate = new TemplateInput(prefix + "OperationIT.java", "src/test/java/{{asPackageFolder testsPackage}}/{{serviceName}}/{{asJavaTypeName operationId}}{{testSuffix}}.java").withMimeType(JAVA); + + @Override + public void onPropertiesSet() { + if(basePackage == null) { + basePackage = testsPackage; + configPackage = basePackage + ".config"; + } + if (simpleDomainPackaging) { + testsPackage = "{{basePackage}}"; + baseTestClassPackage = "{{basePackage}}.base"; + controllersPackage = "{{basePackage}}"; + entitiesPackage = "{{basePackage}}.model"; + inboundDtosPackage = "{{basePackage}}.dtos"; + servicesPackage = "{{basePackage}}"; + } + } public TemplateEngine getTemplateEngine() { return handlebarsEngine; } Model getApiModel(Map contextModel) { - return (Model) contextModel.get(sourceProperty); + return (Model) contextModel.get(apiProperty); } @Override diff --git a/plugins/openapi-spring-webtestclient/src/main/java/io/zenwave360/sdk/plugins/SpringWebTestClientPlugin.java b/plugins/openapi-spring-webtestclient/src/main/java/io/zenwave360/sdk/plugins/SpringWebTestClientPlugin.java index 5bc74c8a..31c40c5a 100644 --- a/plugins/openapi-spring-webtestclient/src/main/java/io/zenwave360/sdk/plugins/SpringWebTestClientPlugin.java +++ b/plugins/openapi-spring-webtestclient/src/main/java/io/zenwave360/sdk/plugins/SpringWebTestClientPlugin.java @@ -6,10 +6,12 @@ import io.zenwave360.sdk.processors.OpenApiProcessor; import io.zenwave360.sdk.writers.TemplateFileWriter; import io.zenwave360.sdk.writers.TemplateStdoutWriter; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static io.zenwave360.sdk.plugins.SpringWebTestClientGenerator.GroupByType.businessFlow; +import static io.zenwave360.sdk.plugins.SpringWebTestClientGenerator.GroupByType.partial; @DocumentedPlugin(value = "Generates test for SpringMVC or Spring WebFlux using WebTestClient based on OpenAPI specification.", shortCode = "spring-webtestclient") public class SpringWebTestClientPlugin extends Plugin { @@ -22,15 +24,15 @@ public SpringWebTestClientPlugin() { @Override public T processOptions() { - if (!hasOption("targetFolder")) { + if (hasOption("groupBy", partial)) { replaceInChain(TemplateFileWriter.class, TemplateStdoutWriter.class); - withOption(SpringWebTestClientGenerator.class.getName() + ".groupBy", SpringWebTestClientGenerator.GroupByType.partial.toString()); } if(hasOption("groupBy", businessFlow) && !hasOption("businessFlowTestName")) { log.info("Business flow test name option 'businessFlowTestName' not provided. Printing to stdout."); replaceInChain(TemplateFileWriter.class, TemplateStdoutWriter.class); withOption("businessFlowTestName", "BusinessFlowTest"); } + withOption("DefaultYamlParser.specFile", StringUtils.firstNonBlank((String) getOptions().get("openapiFile"), this.getSpecFile())); return (T) this; } } diff --git a/plugins/openapi-spring-webtestclient/src/main/resources/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/BaseWebTestClientTest.java.hbs b/plugins/openapi-spring-webtestclient/src/main/resources/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/BaseWebTestClientTest.java.hbs index 554d3c45..42318a80 100644 --- a/plugins/openapi-spring-webtestclient/src/main/resources/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/BaseWebTestClientTest.java.hbs +++ b/plugins/openapi-spring-webtestclient/src/main/resources/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/BaseWebTestClientTest.java.hbs @@ -1,13 +1,17 @@ package {{baseTestClassPackage}}; +// import {{configPackage}}.DockerComposeInitializer; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.test.web.servlet.client.MockMvcWebTestClient; import org.springframework.web.context.WebApplicationContext; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) +@ActiveProfiles("test") +// @DockerComposeInitializer.EnableDockerCompose {{#if transactional}}@{{transactionalAnnotationClass}}{{/if}} public abstract class BaseWebTestClientTest { diff --git a/plugins/openapi-spring-webtestclient/src/main/resources/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/OperationIT.java.hbs b/plugins/openapi-spring-webtestclient/src/main/resources/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/OperationIT.java.hbs index 1e61faa8..4064d0b1 100644 --- a/plugins/openapi-spring-webtestclient/src/main/resources/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/OperationIT.java.hbs +++ b/plugins/openapi-spring-webtestclient/src/main/resources/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/OperationIT.java.hbs @@ -8,10 +8,7 @@ import {{openApiModelPackage}}.*; {{~/if}} import {{baseTestClassPackage}}.{{baseTestClassName}}; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.web.reactive.server.WebTestClient; diff --git a/plugins/openapi-spring-webtestclient/src/main/resources/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/ServiceIT.java.hbs b/plugins/openapi-spring-webtestclient/src/main/resources/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/ServiceIT.java.hbs index 345bcd1c..f0758e8b 100644 --- a/plugins/openapi-spring-webtestclient/src/main/resources/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/ServiceIT.java.hbs +++ b/plugins/openapi-spring-webtestclient/src/main/resources/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/ServiceIT.java.hbs @@ -8,10 +8,7 @@ import {{openApiModelPackage}}.*; {{~/if}} import {{baseTestClassPackage}}.{{baseTestClassName}}; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.web.reactive.server.WebTestClient; @@ -23,7 +20,6 @@ import static org.springframework.http.HttpMethod.*; /** * Integration tests for the {@link {{serviceName~}} } REST controller. */ -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class {{serviceName}}{{testSuffix}} extends {{baseTestClassName}} { {{> (partial 'partials/Operation.java')}} diff --git a/plugins/openapi-spring-webtestclient/src/main/resources/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/partials/Operation.java.hbs b/plugins/openapi-spring-webtestclient/src/main/resources/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/partials/Operation.java.hbs index 6ef44a69..44753c75 100644 --- a/plugins/openapi-spring-webtestclient/src/main/resources/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/partials/Operation.java.hbs +++ b/plugins/openapi-spring-webtestclient/src/main/resources/io/zenwave360/sdk/plugins/SpringWebTestClientGenerator/partials/Operation.java.hbs @@ -5,7 +5,6 @@ * Test: {{operation.description}} for {{response.description}}. */ @Test - @Order({{@index}}) public void test{{asJavaTypeName operation.operationId}}_{{response.x--statusCode}}() { {{~#assign "requestDTOClassName"}}{{asDtoName operation.x--request-dto }}{{/assign~}} {{~#assign "requestBodyVar"}}requestBody{{/assign~}} diff --git a/plugins/openapi-spring-webtestclient/src/test/java/io/zenwave360/sdk/plugins/SpringWebTestClientGeneratorTest.java b/plugins/openapi-spring-webtestclient/src/test/java/io/zenwave360/sdk/plugins/SpringWebTestClientGeneratorTest.java index a0939784..e4a79473 100644 --- a/plugins/openapi-spring-webtestclient/src/test/java/io/zenwave360/sdk/plugins/SpringWebTestClientGeneratorTest.java +++ b/plugins/openapi-spring-webtestclient/src/test/java/io/zenwave360/sdk/plugins/SpringWebTestClientGeneratorTest.java @@ -53,7 +53,7 @@ public void test_output_partial_one_operation(String openapi, String operationId var templateOutputList = CapturingTemplateWriter.templateOutputList; Assertions.assertEquals(1, templateOutputList.size()); - Assertions.assertEquals("io/example/controller/tests/Operation.java", templateOutputList.get(0).getTargetFile()); + Assertions.assertEquals("src/test/java/io/example/controller/tests/Operation.java", templateOutputList.get(0).getTargetFile()); } @ParameterizedTest(name = "[{index}] {displayName} {0} {1}") @@ -65,7 +65,7 @@ public void test_output_business_flow(String openapi, String operationIds) throw String targetFolder = "target/test_output_business_flow_" + openapi.replaceAll("\\.", "_"); Plugin plugin = new SpringWebTestClientPlugin() .withSpecFile("classpath:io/zenwave360/sdk/resources/openapi/" + openapi) - .withTargetFolder(targetFolder + "/src/test/java") + .withTargetFolder(targetFolder) .withOption("groupBy", SpringWebTestClientGenerator.GroupByType.businessFlow) .withOption("businessFlowTestName", camelCase(operationIds.replaceAll(",", "_"))) .withOption("transactional", false) @@ -82,7 +82,7 @@ public void test_output_business_flow(String openapi, String operationIds) throw var templateOutputList = CapturingTemplateWriter.templateOutputList; Assertions.assertEquals(2, templateOutputList.size()); - Assertions.assertEquals("io/example/controller/tests/" + camelCase(operationIds.replaceAll(",", "_")) +".java", templateOutputList.get(0).getTargetFile()); + Assertions.assertEquals("src/test/java/io/example/controller/tests/" + camelCase(operationIds.replaceAll(",", "_")) +".java", templateOutputList.get(0).getTargetFile()); int exitCode = MavenCompiler.copyPomAndCompile("src/test/resources/pom.xml", targetFolder, "openapi.yml=" + OPENAPI_RESOURCES + openapi); Assertions.assertEquals(0, exitCode); @@ -98,7 +98,7 @@ public void test_output_by_one_service(String openapi, String operationId, Strin String targetFolder = "target/test_output_by_one_service_" + openapi.replaceAll("\\.", "_"); Plugin plugin = new SpringWebTestClientPlugin() .withSpecFile("classpath:io/zenwave360/sdk/resources/openapi/" + openapi) - .withTargetFolder(targetFolder + "/src/test/java") + .withTargetFolder(targetFolder) .withOption("groupBy", SpringWebTestClientGenerator.GroupByType.service) .withOption("transactional", false) .withOption("testsPackage", "io.example.controller.tests") @@ -118,6 +118,36 @@ public void test_output_by_one_service(String openapi, String operationId, Strin Assertions.assertEquals(0, exitCode); } + @ParameterizedTest(name = "[{index}] {displayName} {0}") + @CsvSource({ + "openapi-petstore.yml, addPet, 'PetApiIT'", + "openapi-orders.yml, createCustomer, 'CustomerApiIT'" + }) + public void test_output_by_one_service_simple_domain_packaging(String openapi, String operationId, String controllers) throws Exception { + String targetFolder = "target/test_output_by_one_service_simple_domain_packaging_" + openapi.replaceAll("\\.", "_"); + Plugin plugin = new SpringWebTestClientPlugin() + .withSpecFile("classpath:io/zenwave360/sdk/resources/openapi/" + openapi) + .withTargetFolder(targetFolder) + .withOption("groupBy", SpringWebTestClientGenerator.GroupByType.service) + .withOption("transactional", false) + .withOption("simpleDomainPackaging", true) + .withOption("basePackage", "io.example") + .withOption("openApiApiPackage", "io.example.api") + .withOption("openApiModelPackage", "io.example.api.model") + .withOption("openApiModelNameSuffix", "DTO") + .withOption("operationIds", List.of(operationId)); + + new MainGenerator().generate(plugin); + + Arrays.stream(controllers.split(",")).forEach(controller -> { + File file = new File(targetFolder + "/src/test/java/io/example/" + controller + ".java"); + Assertions.assertTrue(file.exists(), "File " + file.getAbsolutePath() + " does not exist"); + }); + + int exitCode = MavenCompiler.copyPomAndCompile("src/test/resources/pom.xml", targetFolder, "openapi.yml=" + OPENAPI_RESOURCES + openapi); + Assertions.assertEquals(0, exitCode); + } + @ParameterizedTest(name = "[{index}] {displayName} {0}") @CsvSource({ "openapi-petstore.yml, 'PetApiIT'", @@ -127,7 +157,7 @@ public void test_output_by_service(String openapi, String controllers) throws Ex String targetFolder = "target/test_output_by_service_" + openapi.replaceAll("\\.", "_"); Plugin plugin = new SpringWebTestClientPlugin() .withSpecFile("classpath:io/zenwave360/sdk/resources/openapi/" + openapi) - .withTargetFolder(targetFolder + "/src/test/java") + .withTargetFolder(targetFolder) .withOption("groupBy", SpringWebTestClientGenerator.GroupByType.service) .withOption("transactional", false) .withOption("testsPackage", "io.example.controller.tests") @@ -155,7 +185,7 @@ public void test_output_by_operation(String openapi, String controllers) throws String targetFolder = "target/test_output_by_operation_" + openapi.replaceAll("\\.", "_"); Plugin plugin = new SpringWebTestClientPlugin() .withSpecFile("classpath:io/zenwave360/sdk/resources/openapi/" + openapi) - .withTargetFolder(targetFolder + "/src/test/java") + .withTargetFolder(targetFolder) .withOption("groupBy", SpringWebTestClientGenerator.GroupByType.operation) .withOption("transactional", false) .withOption("testsPackage", "io.example.controller.tests")