diff --git a/.github/workflows/smoke-test-imperative.yml b/.github/workflows/smoke-test-imperative.yml index 35a70dd1..6b090156 100644 --- a/.github/workflows/smoke-test-imperative.yml +++ b/.github/workflows/smoke-test-imperative.yml @@ -14,11 +14,13 @@ jobs: node_version: [12.16.2] os: [ubuntu-latest] app: - - imperative-sql-jwt-maven-sample - - imperative-sql-jwt-maven-sqllight + - imperative-ngx-jwt-maven-mysql-caffeine + - imperative-ngx-jwt-maven-psql-nocache + - imperative-react-jwt-gradle-mysql-caffeine include: - - app: imperative-sql-jwt-maven-sample - - app: imperative-sql-jwt-maven-sqllight + - app: imperative-ngx-jwt-maven-mysql-caffeine + - app: imperative-ngx-jwt-maven-psql-nocache + - app: imperative-react-jwt-gradle-mysql-caffeine env: JHI_APP: ${{ matrix.app }} steps: diff --git a/generators/entity-server/files.js b/generators/entity-server/files.js index 2ec38939..de5977fb 100644 --- a/generators/entity-server/files.js +++ b/generators/entity-server/files.js @@ -20,6 +20,8 @@ const constants = require('generator-jhipster/generators/generator-constants'); const faker = require('faker'); const jhipsterUtils = require('generator-jhipster/generators/utils'); +const NeedleApi = require('../needle-api'); + const randexp = jhipsterUtils.RandexpWithFaker; /* Constants use throughout */ const SERVER_MAIN_SRC_DIR = constants.SERVER_MAIN_SRC_DIR; @@ -351,16 +353,16 @@ function writeFiles() { } this.addChangelogToLiquibase(`${this.changelogDate}_added_entity_${this.entityClass}`); } + } + }, - if (['ehcache', 'caffeine', 'infinispan', 'redis'].includes(this.cacheProvider) && this.enableHibernateCache) { - this.addEntityToCache( - this.asEntity(this.entityClass), - this.relationships, - this.packageName, - this.packageFolder, - this.cacheProvider - ); - } + updateCacheConfiguration() { + if (this.enableHibernateCache) { + new NeedleApi(this).quarkusServerCache.addEntityConfigurationToPropertiesFile( + this.asEntity(this.entityClass), + this.relationships, + this.packageName + ); } }, diff --git a/generators/entity-server/templates/quarkus/src/main/java/package/domain/Entity.java.ejs b/generators/entity-server/templates/quarkus/src/main/java/package/domain/Entity.java.ejs index 02e7489d..e453b109 100644 --- a/generators/entity-server/templates/quarkus/src/main/java/package/domain/Entity.java.ejs +++ b/generators/entity-server/templates/quarkus/src/main/java/package/domain/Entity.java.ejs @@ -70,7 +70,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.annotations.ApiModel; <%_ } if (!hasDto && importApiModelProperty === true) { _%> import io.swagger.annotations.ApiModelProperty; -<%_ } if (readOnly) { _%> +<%_ } if (enableHibernateCache) { _%> import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; <%_ } if (hasTextBlob === true || (fieldsContainUUID === true && ['mysql', 'mariadb'].includes(prodDatabaseType))) { _%> @@ -149,9 +149,9 @@ import static org.springframework.data.couchbase.core.mapping.id.GenerationStrat <%_ if (databaseType === 'sql') { _%> @Entity @Table(name = "<%= entityTableName %>") - <%_ if (readOnly) { _%> -@Cache(usage = CacheConcurrencyStrategy.READ_ONLY) - <%_ } _%> +<%_ if (enableHibernateCache) { _%> +<% if (readOnly) { %>@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)<% } else { %>@Cacheable<% } %> +<%_ } _%> <%_ } _%> <%_ if (databaseType === 'mongodb') { _%> @Document(collection = "<%= entityTableName %>") @@ -288,8 +288,8 @@ public class <%= asEntity(entityClass) %> extends PanacheEntityBase implements S if (databaseType === 'sql') { _%> @OneToMany(mappedBy = "<%= otherEntityRelationshipName %>") - <%_ if (readOnly) { _%> - @Cache(usage = CacheConcurrencyStrategy.READ_ONLY) + <%_ if (enableHibernateCache) { _%> + @Cache(usage = CacheConcurrencyStrategy.<% if (readOnly) { %>READ_ONLY<% } else { %>READ_WRITE<% } %>) <%_ } _%> <%_ } else if (databaseType === 'mongodb' || databaseType === 'couchbase') { if (databaseType === 'mongodb') { _%> @@ -333,9 +333,9 @@ public class <%= asEntity(entityClass) %> extends PanacheEntityBase implements S <%_ } else if (relationshipType === 'many-to-many') { if (databaseType === 'sql') { _%> @ManyToMany<% if (ownerSide === false) { %>(mappedBy = "<%= otherEntityRelationshipNamePlural %>")<% } %> - <%_ if (readOnly) { _%> - @Cache(usage = CacheConcurrencyStrategy.READ_ONLY) - <%_ } _%> + <%_ if (enableHibernateCache) { _%> + @Cache(usage = CacheConcurrencyStrategy.<% if (readOnly) { %>READ_ONLY<% } else { %>READ_WRITE<% } %>) + <%_ } _%> <%_ if (ownerSide === true) { if (relationshipValidate) { _%> <%- include(fetchFromInstalledJHipster('entity-server/templates') + '/src/main/java/package/domain/relationship_validators', { diff --git a/generators/generator-quarkus-constants.js b/generators/generator-quarkus-constants.js index 38feab4e..d8a38221 100644 --- a/generators/generator-quarkus-constants.js +++ b/generators/generator-quarkus-constants.js @@ -1,9 +1,14 @@ const DEFAULT_DATA_ACCESS = 'activeRecord'; const QUARKUS_VERSION = '1.10.2.Final'; +const CACHE_MAXIMUM_SIZE = 100; +const CACHE_EXPIRE_AFTER_WRITE = '3600S'; + const constants = { DEFAULT_DATA_ACCESS, - QUARKUS_VERSION + QUARKUS_VERSION, + CACHE_MAXIMUM_SIZE, + CACHE_EXPIRE_AFTER_WRITE }; module.exports = constants; diff --git a/generators/needle-api.js b/generators/needle-api.js new file mode 100644 index 00000000..40e47670 --- /dev/null +++ b/generators/needle-api.js @@ -0,0 +1,25 @@ +/** + * Copyright 2013-2020 the original author or authors from the JHipster project. + * + * This file is part of the JHipster project, see https://www.jhipster.tech/ + * for more information. + * + * 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. + */ +const ServerCache = require('./server/needle-api/needle-server-cache'); + +module.exports = class NeedleApi { + constructor(generator) { + this.quarkusServerCache = new ServerCache(generator); + } +}; diff --git a/generators/server/files.js b/generators/server/files.js index f1e34a72..1d2a008d 100644 --- a/generators/server/files.js +++ b/generators/server/files.js @@ -24,11 +24,7 @@ const jhipsterFiles = require('generator-jhipster/generators/server/files').serv /* Constants use throughout */ const INTERPOLATE_REGEX = constants.INTERPOLATE_REGEX; const DOCKER_DIR = constants.DOCKER_DIR; -// const TEST_DIR = constants.TEST_DIR; -const SERVER_MAIN_SRC_DIR = constants.SERVER_MAIN_SRC_DIR; -const SERVER_MAIN_RES_DIR = constants.SERVER_MAIN_RES_DIR; -const SERVER_TEST_SRC_DIR = constants.SERVER_TEST_SRC_DIR; -const SERVER_TEST_RES_DIR = constants.SERVER_TEST_RES_DIR; +const { SERVER_MAIN_SRC_DIR, SERVER_MAIN_RES_DIR, SERVER_TEST_SRC_DIR, SERVER_TEST_RES_DIR } = constants; const serverFiles = { serverBuild: [ @@ -76,6 +72,10 @@ const serverFiles = { 'application.properties', 'resources-config.json' ] + }, + { + path: SERVER_TEST_RES_DIR, + templates: ['application.properties'] } ], serverTestSupport: [ diff --git a/generators/server/index.js b/generators/server/index.js index bc10c63d..d8ee6802 100644 --- a/generators/server/index.js +++ b/generators/server/index.js @@ -4,7 +4,7 @@ const os = require('os'); const ServerGenerator = require('generator-jhipster/generators/server'); const prompts = require('./prompts'); const writeFiles = require('./files').writeFiles; -const quarkusVersion = require('../generator-quarkus-constants').QUARKUS_VERSION; +const { QUARKUS_VERSION, CACHE_MAXIMUM_SIZE, CACHE_EXPIRE_AFTER_WRITE } = require('../generator-quarkus-constants'); module.exports = class extends ServerGenerator { constructor(args, opts) { @@ -26,7 +26,9 @@ module.exports = class extends ServerGenerator { const phaseFromJHipster = super._initializing(); const phaseFromQuarkus = { defineQuarkusConstants() { - this.quarkusVersion = quarkusVersion; + this.quarkusVersion = QUARKUS_VERSION; + this.CACHE_MAXIMUM_SIZE = CACHE_MAXIMUM_SIZE; + this.CACHE_EXPIRE_AFTER_WRITE = CACHE_EXPIRE_AFTER_WRITE; } }; return { ...phaseFromJHipster, ...phaseFromQuarkus }; @@ -42,8 +44,15 @@ module.exports = class extends ServerGenerator { } get configuring() { - // Here we are not overriding this phase and hence its being handled by JHipster - return super._configuring(); + const phaseFromJHipster = super._configuring(); + const phaseFromQuarkus = { + configureGlobalQuarkus() { + // Override JHipster cacheManagerIsAvailable property to only handle Quarkus caches + this.cacheManagerIsAvailable = ['caffeine'].includes(this.cacheProvider); + } + }; + + return { ...phaseFromJHipster, ...phaseFromQuarkus }; } get default() { diff --git a/generators/server/needle-api/needle-server-cache.js b/generators/server/needle-api/needle-server-cache.js new file mode 100644 index 00000000..040926cf --- /dev/null +++ b/generators/server/needle-api/needle-server-cache.js @@ -0,0 +1,40 @@ +const chalk = require('chalk'); +const needleServerCache = require('generator-jhipster/generators/server/needle-api/needle-server-cache'); +const constants = require('generator-jhipster/generators/generator-constants'); +const { CACHE_MAXIMUM_SIZE, CACHE_EXPIRE_AFTER_WRITE } = require('../../generator-quarkus-constants'); + +const { SERVER_MAIN_RES_DIR } = constants; + +module.exports = class extends needleServerCache { + addEntityConfigurationToPropertiesFile(entityClass, relationships, packageName) { + const errorMessage = chalk.yellow(`\nUnable to add ${entityClass} to application.properties file.`); + const cacheName = `${packageName}.domain.${entityClass}`; + const applicationPropertiesFileName = `${SERVER_MAIN_RES_DIR}application.properties`; + const needle = 'jhipster-quarkus-needle-hibernate-cache-add-entry'; + const rewriteFileModel = this.generateFileModel( + applicationPropertiesFileName, + needle, + `quarkus.hibernate-orm.cache."${cacheName}".expiration.max-idle=${CACHE_EXPIRE_AFTER_WRITE}\n` + + `quarkus.hibernate-orm.cache."${cacheName}".memory.object-count=${CACHE_MAXIMUM_SIZE}` + ); + + this.addBlockContentToFile(rewriteFileModel, errorMessage); + + relationships.forEach(relationship => { + const relationshipType = relationship.relationshipType; + if (relationshipType === 'one-to-many' || relationshipType === 'many-to-many') { + const rewriteFileModelWithRelationships = this.generateFileModel( + applicationPropertiesFileName, + needle, + `quarkus.hibernate-orm.cache."${cacheName}.${ + relationship.relationshipFieldNamePlural + }".expiration.max-idle=${CACHE_EXPIRE_AFTER_WRITE}\n` + + `quarkus.hibernate-orm.cache."${cacheName}.${ + relationship.relationshipFieldNamePlural + }".memory.object-count=${CACHE_MAXIMUM_SIZE}` + ); + this.addBlockContentToFile(rewriteFileModelWithRelationships, errorMessage); + } + }); + } +}; diff --git a/generators/server/prompts.js b/generators/server/prompts.js index 5f7a1cb2..d9f4e0e8 100644 --- a/generators/server/prompts.js +++ b/generators/server/prompts.js @@ -189,46 +189,49 @@ function askForServerSideOpts(meta) { ].concat(constants.SQL_DB_OPTIONS.find(it => it.value === response.prodDatabaseType)), default: 0 }, - // , - // { - // when: () => !reactive, - // type: 'list', - // name: 'cacheProvider', - // message: 'Do you want to use the Spring cache abstraction?', - // choices: [ - // { - // value: 'ehcache', - // name: 'Yes, with the Ehcache implementation (local cache, for a single node)' - // }, - // { - // value: 'caffeine', - // name: 'Yes, with the Caffeine implementation (local cache, for a single node)' - // }, - // { - // value: 'hazelcast', - // name: - // 'Yes, with the Hazelcast implementation (distributed cache, for multiple nodes, supports rate-limiting for gateway applications)' - // }, - // { - // value: 'infinispan', - // name: '[BETA] Yes, with the Infinispan implementation (hybrid cache, for multiple nodes)' - // }, - // { - // value: 'memcached', - // name: - // 'Yes, with Memcached (distributed cache) - Warning, when using an SQL database, this will disable the Hibernate 2nd level cache!' - // }, - // { - // value: 'redis', - // name: 'Yes, with the Redis implementation' - // }, - // { - // value: 'no', - // name: 'No - Warning, when using an SQL database, this will disable the Hibernate 2nd level cache!' - // } - // ], - // default: applicationType === 'microservice' || applicationType === 'uaa' ? 2 : 0 - // }, + { + when: () => !reactive, + type: 'list', + name: 'cacheProvider', + message: 'Do you want to use the Quarkus cache abstraction?', + choices: [ + /* + { + value: 'ehcache', + name: 'Yes, with the Ehcache implementation (local cache, for a single node)' + }, + */ + { + value: 'caffeine', + name: 'Yes, with the Caffeine implementation (local cache, for a single node)' + }, + /* + { + value: 'hazelcast', + name: + 'Yes, with the Hazelcast implementation (distributed cache, for multiple nodes, supports rate-limiting for gateway applications)' + }, + { + value: 'infinispan', + name: '[BETA] Yes, with the Infinispan implementation (hybrid cache, for multiple nodes)' + }, + { + value: 'memcached', + name: + 'Yes, with Memcached (distributed cache) - Warning, when using an SQL database, this will disable the Hibernate 2nd level cache!' + }, + { + value: 'redis', + name: 'Yes, with the Redis implementation' + }, + */ + { + value: 'no', + name: 'No - Warning, when using an SQL database, this will disable the Hibernate 2nd level cache!' + } + ] + // default: applicationType === 'microservice' || applicationType === 'uaa' ? 2 : 0 + }, { when: response => response.databaseType === 'sql' && !reactive, type: 'confirm', diff --git a/generators/server/templates/quarkus/build.gradle.ejs b/generators/server/templates/quarkus/build.gradle.ejs index 2adfff4c..e2117032 100644 --- a/generators/server/templates/quarkus/build.gradle.ejs +++ b/generators/server/templates/quarkus/build.gradle.ejs @@ -237,6 +237,9 @@ dependencies { implementation "io.quarkus:quarkus-elytron-security" implementation "io.quarkus:quarkus-smallrye-jwt" implementation "io.quarkus:quarkus-smallrye-openapi" +<%_ if (cacheManagerIsAvailable) { _%> + implementation 'io.quarkus:quarkus-cache' +<%_ } _%> implementation "io.quarkus:quarkus-smallrye-health" implementation "io.quarkus:quarkus-micrometer" implementation "io.micrometer:micrometer-registry-prometheus" diff --git a/generators/server/templates/quarkus/gradle.properties.ejs b/generators/server/templates/quarkus/gradle.properties.ejs index bb030221..61aeb6d0 100644 --- a/generators/server/templates/quarkus/gradle.properties.ejs +++ b/generators/server/templates/quarkus/gradle.properties.ejs @@ -39,10 +39,7 @@ log4j2_mock_version=0.0.2 <%_ if (enableSwaggerCodegen) { _%> jackson_databind_nullable_version=<%= JACKSON_DATABIND_NULLABLE_VERSION %> <%_ } _%> -<%_ if (cacheProvider === 'caffeine') { _%> -caffeine_version=2.8.1 typesafe_config_version=1.4.0 -<%_ } _%> liquibase_hibernate5_version=3.8 liquibaseTaskPrefix=liquibase diff --git a/generators/server/templates/quarkus/gradle/swagger.gradle.ejs b/generators/server/templates/quarkus/gradle/swagger.gradle.ejs deleted file mode 100644 index b2f0fb43..00000000 --- a/generators/server/templates/quarkus/gradle/swagger.gradle.ejs +++ /dev/null @@ -1,47 +0,0 @@ -<%# - Copyright 2013-2020 the original author or authors from the JHipster project. - - This file is part of the JHipster project, see https://www.jhipster.tech/ - for more information. - - 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. --%> -/* - * Plugin that provides API-first development using OpenAPI-generator to - * generate Spring-MVC endpoint stubs at compile time from an OpenAPI definition file - */ -apply plugin: "org.openapi.generator" - -openApiGenerate { - generatorName = "spring" - inputSpec = "$rootDir/src/main/resources/swagger/api.yml".toString() - outputDir = "$buildDir/openapi".toString() - apiPackage = "<%= packageName %>.web.api" - modelPackage = "<%= packageName %>.web.api.model" - apiFilesConstrainedTo = [""] - modelFilesConstrainedTo = [""] - supportingFilesConstrainedTo = ["ApiUtil.java"] - configOptions = [delegatePattern: "true", title: "<%= dasherizedBaseName %>"] - validateSpec = true - importMappings = [Problem:"org.zalando.problem.Problem"] -} - -sourceSets { - main { - java { - srcDir file("${project.buildDir.path}/openapi/src/main/java") - } - } -} - -compileJava.dependsOn("openApiGenerate") diff --git a/generators/server/templates/quarkus/partials/cache_application.properties.ejs b/generators/server/templates/quarkus/partials/cache_application.properties.ejs new file mode 100644 index 00000000..a0e05013 --- /dev/null +++ b/generators/server/templates/quarkus/partials/cache_application.properties.ejs @@ -0,0 +1,27 @@ +<%# + Copyright 2013-2020 the original author or authors from the JHipster project. + + This file is part of the JHipster project, see https://www.jhipster.tech/ + for more information. + + 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. +-%> +## configure your caches +quarkus.cache.type=<%= cacheProvider %> +quarkus.cache.enabled=true +<%_ if (cacheProvider === 'caffeine') { _%> +quarkus.cache.caffeine."usersByEmail".maximum-size=<%= CACHE_MAXIMUM_SIZE %> +quarkus.cache.caffeine."usersByEmail".expire-after-write=<%= CACHE_EXPIRE_AFTER_WRITE %> +quarkus.cache.caffeine."usersByLogin".maximum-size=<%= CACHE_MAXIMUM_SIZE %> +quarkus.cache.caffeine."usersByLogin".expire-after-write=<%= CACHE_EXPIRE_AFTER_WRITE %> +<%_ } _%> diff --git a/generators/server/templates/quarkus/partials/data_application-test.properties.ejs b/generators/server/templates/quarkus/partials/data_application-test.properties.ejs new file mode 100644 index 00000000..867941ef --- /dev/null +++ b/generators/server/templates/quarkus/partials/data_application-test.properties.ejs @@ -0,0 +1,94 @@ +<%# + Copyright 2013-2020 the original author or authors from the JHipster project. + + This file is part of the JHipster project, see https://www.jhipster.tech/ + for more information. + + 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. +-%> +## configure your datasource +<%_ if (devDatabaseType === 'h2Disk') { _%> +%dev.quarkus.datasource.jdbc.url=jdbc:h2:file:./<%= BUILD_DIR %>h2db/db/<%= baseName.toLowerCase() %>;DB_CLOSE_DELAY=-1 +%dev.quarkus.datasource.db-kind=h2 +%dev.quarkus.datasource.username=<%= baseName %> +%dev.quarkus.datasource.password= +<%_ } _%> +<%_ if (devDatabaseType === 'h2Memory') { _%> +%dev.quarkus.datasource.jdbc.url=jdbc:h2:mem:<%= baseName.toLowerCase() %>;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE +%dev.quarkus.datasource.db-kind=h2 +%dev.quarkus.datasource.username=<%= baseName %> +%dev.quarkus.datasource.password= +<%_ } _%> +<%_ if (devDatabaseType === 'mariadb') { _%> +%dev.quarkus.datasource.jdbc.url=jdbc:mariadb://localhost:3306/<%= baseName %> +%dev.quarkus.datasource.db-kind=mariadb +%dev.quarkus.datasource.username=<%= baseName %> +%dev.quarkus.datasource.password= +<%_ } _%> +<%_ if (prodDatabaseType === 'mariadb') { _%> +%prod.quarkus.datasource.jdbc.url=jdbc:mariadb://localhost:3306/<%= baseName %> +%prod.quarkus.datasource.db-kind=mariadb +%prod.quarkus.datasource.username=root +%prod.quarkus.datasource.password= +<%_ } _%> +<%_ if (devDatabaseType === 'mssql') { _%> +%dev.quarkus.datasource.jdbc.url=jdbc:sqlserver://localhost:1433;database=<%= baseName %> +%dev.quarkus.datasource.db-kind=sqlserver +%dev.quarkus.datasource.username=SA +%dev.quarkus.datasource.password=yourStrong(!)Password +<%_ } _%> +<%_ if (prodDatabaseType === 'mssql') { _%> +%prod.quarkus.datasource.jdbc.url=jdbc:mariadb://localhost:3306/<%= baseName %> +%prod.quarkus.datasource.db-kind=sqlserver +%prod.quarkus.datasource.username=SA +%prod.quarkus.datasource.password=yourStrong(!)Password +<%_ } _%> +<%_ if (devDatabaseType === 'mysql') { _%> +%dev.quarkus.datasource.jdbc.url=jdbc:mysql://localhost:3306/<%= baseName %>?useUnicode=true&characterEncoding=utf8&useSSL=false +%dev.quarkus.datasource.db-kind=mysql +%dev.quarkus.datasource.username=root +%dev.quarkus.datasource.password= +<%_ } _%> +<%_ if (prodDatabaseType === 'mysql') { _%> +%prod.quarkus.datasource.jdbc.url=jdbc:mysql://localhost:3306/<%= baseName %>?useUnicode=true&characterEncoding=utf8&useSSL=false +%prod.quarkus.datasource.db-kind=mysql +%prod.quarkus.datasource.username=root +%prod.quarkus.datasource.password= +<%_ } _%> +<%_ if (devDatabaseType === 'postgresql') { _%> +%dev.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/<%= baseName %> +%dev.quarkus.datasource.db-kind=postgresql +%dev.quarkus.datasource.username=<%= baseName %> +%dev.quarkus.datasource.password= +<%_ } _%> +<%_ if (prodDatabaseType === 'postgresql') { _%> +%prod.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/<%= baseName %> +%prod.quarkus.datasource.db-kind=postgresql +%prod.quarkus.datasource.username=<%= baseName %> +%prod.quarkus.datasource.password= +<%_ } _%> +quarkus.datasource.jdbc.max-size=8 +quarkus.datasource.jdbc.min-size=2 +quarkus.hibernate-orm.database.generation=none +quarkus.hibernate-orm.log.sql=false +quarkus.hibernate-orm.sql-load-script=no-file +quarkus.hibernate-orm.implicit-naming-strategy=<%=packageName%>.config.hibernate.JHipsterCompatibleImplicitNamingStrategy +quarkus.hibernate-orm.physical-naming-strategy=<%=packageName%>.config.hibernate.JHipsterCompatiblePhysicalNamingStrategy +quarkus.hibernate-orm.second-level-caching-enabled=false + +quarkus.liquibase.change-log=config/liquibase/master.xml +%dev.quarkus.liquibase.migrate-at-start=true + +%test.quarkus.datasource.jdbc.url=jdbc:h2:tcp://localhost/mem:test +%test.quarkus.datasource.db-kind=h2 +%test.quarkus.liquibase.migrate-at-start=true diff --git a/generators/server/templates/quarkus/partials/data_application.properties.ejs b/generators/server/templates/quarkus/partials/data_application.properties.ejs index 815b2103..d1e9d133 100644 --- a/generators/server/templates/quarkus/partials/data_application.properties.ejs +++ b/generators/server/templates/quarkus/partials/data_application.properties.ejs @@ -85,6 +85,9 @@ quarkus.hibernate-orm.sql-load-script=no-file quarkus.hibernate-orm.implicit-naming-strategy=<%=packageName%>.config.hibernate.JHipsterCompatibleImplicitNamingStrategy quarkus.hibernate-orm.physical-naming-strategy=<%=packageName%>.config.hibernate.JHipsterCompatiblePhysicalNamingStrategy quarkus.hibernate-orm.second-level-caching-enabled=<%= enableHibernateCache %> +<%_ if (enableHibernateCache) { _%> +# jhipster-quarkus-needle-hibernate-cache-add-entry +<%_ } _%> quarkus.liquibase.change-log=config/liquibase/master.xml %dev.quarkus.liquibase.migrate-at-start=true diff --git a/generators/server/templates/quarkus/pom.xml.ejs b/generators/server/templates/quarkus/pom.xml.ejs index 045c9530..67e52afd 100644 --- a/generators/server/templates/quarkus/pom.xml.ejs +++ b/generators/server/templates/quarkus/pom.xml.ejs @@ -132,6 +132,12 @@ io.quarkus quarkus-smallrye-openapi + <%_ if (cacheManagerIsAvailable) { _%> + + io.quarkus + quarkus-cache + + <%_ } _%> org.mapstruct mapstruct diff --git a/generators/server/templates/quarkus/src/main/java/package/domain/Authority.java.ejs b/generators/server/templates/quarkus/src/main/java/package/domain/Authority.java.ejs index d458f76f..0ecc34dc 100644 --- a/generators/server/templates/quarkus/src/main/java/package/domain/Authority.java.ejs +++ b/generators/server/templates/quarkus/src/main/java/package/domain/Authority.java.ejs @@ -28,13 +28,18 @@ import javax.persistence.Id; import javax.persistence.Table; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; +<%_ if (enableHibernateCache) { _%> +import javax.persistence.*; +<%_ } _%> /** * An authority (a security role). */ @Entity @Table(name = "<%= jhiTablePrefix %>_authority") -//@Cache(usage = CacheConcurrencyStrategy.READ_ONLY) +<%_ if (enableHibernateCache) { _%> +@Cacheable +<%_ } _%> @RegisterForReflection public class Authority extends PanacheEntityBase implements Serializable { private static final long serialVersionUID = 1L; diff --git a/generators/server/templates/quarkus/src/main/java/package/domain/User.java.ejs b/generators/server/templates/quarkus/src/main/java/package/domain/User.java.ejs index 8d9ed037..5071a2f8 100644 --- a/generators/server/templates/quarkus/src/main/java/package/domain/User.java.ejs +++ b/generators/server/templates/quarkus/src/main/java/package/domain/User.java.ejs @@ -19,9 +19,11 @@ package <%=packageName%>.domain; import <%=packageName%>.config.Constants; +<%_ if (cacheManagerIsAvailable) { _%> +import io.quarkus.cache.CacheResult; +<%_ } _%> import io.quarkus.hibernate.orm.panache.PanacheEntityBase; import io.quarkus.panache.common.Page; -import io.quarkus.runtime.annotations.RegisterForReflection; import java.io.Serializable; import java.time.Instant; import java.util.HashSet; @@ -35,16 +37,25 @@ import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; import org.hibernate.annotations.BatchSize; +<%_ if (enableHibernateCache) { _%> +import org.hibernate.annotations.CacheConcurrencyStrategy; +import org.hibernate.annotations.Cache; +<%_ } _%> /** * A user. */ @Entity @Table(name = "<%= jhiTablePrefix %>_user") -//@Cache(usage = CacheConcurrencyStrategy.READ_ONLY) +<%_ if (enableHibernateCache) { _%> +@Cacheable +<%_ } _%> public class User extends PanacheEntityBase implements Serializable { private static final long serialVersionUID = 1L; - +<%_ if (cacheManagerIsAvailable) { _%> + public static final String USERS_BY_EMAIL_CACHE = "usersByEmail"; + public static final String USERS_BY_LOGIN_CACHE = "usersByLogin"; +<%_ } _%> @Id <%_ if (databaseType === 'sql') { _%> @@ -117,7 +128,9 @@ public class User extends PanacheEntityBase implements Serializable { joinColumns = { @JoinColumn(name = "user_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "authority_name", referencedColumnName = "name") } ) - // @Cache(usage = CacheConcurrencyStrategy.READ_ONLY) + <%_ if (enableHibernateCache) { _%> + @Cache(usage = CacheConcurrencyStrategy.READ_ONLY) + <%_ } _%> @BatchSize(size = 20) public Set authorities = new HashSet<>(); @@ -214,15 +227,15 @@ public class User extends PanacheEntityBase implements Serializable { return find("FROM User u LEFT JOIN FETCH u.authorities WHERE u.id = ?1", id).firstResultOptional(); } + <% if (cacheManagerIsAvailable) { %>@CacheResult(cacheName = USERS_BY_LOGIN_CACHE)<% } %> public static Optional findOneWithAuthoritiesByLogin(String login) { return find("FROM User u LEFT JOIN FETCH u.authorities WHERE u.login = ?1", login) - // .withHint(QueryHints.HINT_CACHEABLE, "true") .firstResultOptional(); } + <% if (cacheManagerIsAvailable) { %>@CacheResult(cacheName = USERS_BY_EMAIL_CACHE)<% } %> public static Optional findOneWithAuthoritiesByEmailIgnoreCase(String email) { return find("FROM User u LEFT JOIN FETCH u.authorities WHERE LOWER(u.login) = LOWER(?1)", email) - // .withHint(QueryHints.HINT_CACHEABLE, "true") .firstResultOptional(); } diff --git a/generators/server/templates/quarkus/src/main/java/package/service/UserService.java.ejs b/generators/server/templates/quarkus/src/main/java/package/service/UserService.java.ejs index 9fce74bd..630560e2 100644 --- a/generators/server/templates/quarkus/src/main/java/package/service/UserService.java.ejs +++ b/generators/server/templates/quarkus/src/main/java/package/service/UserService.java.ejs @@ -25,6 +25,9 @@ import <%=packageName%>.security.AuthoritiesConstants; import <%=packageName%>.security.BCryptPasswordHasher; import <%=packageName%>.security.RandomUtil; import <%=packageName%>.service.dto.UserDTO; +<%_ if (cacheManagerIsAvailable) { _%> +import io.quarkus.cache.CacheInvalidate; +<%_ } _%> import io.quarkus.panache.common.Page; import java.time.Instant; import java.util.HashSet; @@ -59,7 +62,9 @@ public class UserService { // activate given user for the registration key. user.activated = true; user.activationKey = null; - // this.clearUserCaches(user); + <%_ if (cacheManagerIsAvailable) { _%> + this.clearUserCaches(user); + <%_ } _%> log.debug("Activated user: {}", user); return user; } @@ -76,7 +81,9 @@ public class UserService { user.password = passwordHasher.hash(newPassword); user.resetKey = null; user.resetDate = null; - // this.clearUserCaches(user); + <%_ if (cacheManagerIsAvailable) { _%> + this.clearUserCaches(user); + <%_ } _%> return user; } ); @@ -90,7 +97,9 @@ public class UserService { user -> { user.resetKey = RandomUtil.generateResetKey(); user.resetDate = Instant.now(); - // this.clearUserCaches(user); + <%_ if (cacheManagerIsAvailable) { _%> + this.clearUserCaches(user); + <%_ } _%> return user; } ); @@ -117,11 +126,10 @@ public class UserService { } } ); - var encryptedPassword = passwordHasher.hash(password); var newUser = new User(); newUser.login = userDTO.login.toLowerCase(); // new user gets initially a generated password - newUser.password = encryptedPassword; + newUser.password = passwordHasher.hash(password); newUser.firstName = userDTO.firstName; newUser.lastName = userDTO.lastName; if (userDTO.email != null) { @@ -137,7 +145,9 @@ public class UserService { Authority.findByIdOptional(AuthoritiesConstants.USER).ifPresent(authorities::add); newUser.authorities = authorities; User.persist(newUser); - // this.clearUserCaches(newUser); + <%_ if (cacheManagerIsAvailable) { _%> + this.clearUserCaches(newUser); + <%_ } _%> log.debug("Created Information for User: {}", newUser); return newUser; } @@ -147,7 +157,9 @@ public class UserService { return false; } User.delete("id", existingUser.id); - // this.clearUserCaches(existingUser); + <%_ if (cacheManagerIsAvailable) { _%> + this.clearUserCaches(existingUser); + <%_ } _%> return true; } @@ -165,22 +177,22 @@ public class UserService { } else { user.langKey = userDTO.langKey; } - String encryptedPassword = passwordHasher.hash(RandomUtil.generatePassword()); - user.password = encryptedPassword; + user.password = passwordHasher.hash(RandomUtil.generatePassword()); user.resetKey = RandomUtil.generateResetKey(); user.resetDate = Instant.now(); user.activated = true; if (userDTO.authorities != null) { - Set authorities = userDTO + user.authorities = userDTO .authorities.stream() .map(authority -> Authority.findByIdOptional(authority)) .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toSet()); - user.authorities = authorities; } User.persist(user); - // this.clearUserCaches(user); + <%_ if (cacheManagerIsAvailable) { _%> + this.clearUserCaches(user); + <%_ } _%> log.debug("Created Information for User: {}", user); return user; } @@ -207,7 +219,9 @@ public class UserService { } user.langKey = langKey; user.imageUrl = imageUrl; - // this.clearUserCaches(user); + <%_ if (cacheManagerIsAvailable) { _%> + this.clearUserCaches(user); + <%_ } _%> log.debug("Changed Information for User: {}", user); } ); @@ -241,7 +255,9 @@ public class UserService { .filter(Optional::isPresent) .map(Optional::get) .forEach(managedAuthorities::add); - // this.clearUserCaches(user); + <%_ if (cacheManagerIsAvailable) { _%> + this.clearUserCaches(user); + <%_ } _%> log.debug("Changed Information for User: {}", user); return user; } @@ -255,7 +271,9 @@ public class UserService { .ifPresent( user -> { User.delete("id", user.id); - // this.clearUserCaches(user); + <%_ if (cacheManagerIsAvailable) { _%> + this.clearUserCaches(user); + <%_ } _%> log.debug("Deleted User: {}", user); } ); @@ -270,9 +288,10 @@ public class UserService { if (!passwordHasher.checkPassword(currentClearTextPassword, currentEncryptedPassword)) { throw new InvalidPasswordException(); } - String encryptedPassword = passwordHasher.hash(newPassword); - user.password = encryptedPassword; - // this.clearUserCaches(user); + user.password = passwordHasher.hash(newPassword); + <%_ if (cacheManagerIsAvailable) { _%> + this.clearUserCaches(user); + <%_ } _%> log.debug("Changed password for User: {}", user); } ); @@ -289,4 +308,19 @@ public class UserService { public List getAuthorities() { return Authority.streamAll().map(authority -> authority.name).collect(Collectors.toList()); } + + <%_ if (cacheManagerIsAvailable) { _%> + public void clearUserCaches(User user) { + this.clearUserCachesByLogin(user.login); + if (user.email != null) { + this.clearUserCachesByEmail(user.email); + } + } + + @CacheInvalidate(cacheName = User.USERS_BY_EMAIL_CACHE) + public void clearUserCachesByEmail(String email) {} + + @CacheInvalidate(cacheName = User.USERS_BY_LOGIN_CACHE) + public void clearUserCachesByLogin(String login) {} + <%_ } _%> } diff --git a/generators/server/templates/quarkus/src/main/resources/application.properties.ejs b/generators/server/templates/quarkus/src/main/resources/application.properties.ejs index 2fdb5a70..4d3b38de 100644 --- a/generators/server/templates/quarkus/src/main/resources/application.properties.ejs +++ b/generators/server/templates/quarkus/src/main/resources/application.properties.ejs @@ -18,7 +18,10 @@ -%> application.name=<%= baseName %> -<%- include('../../../partials/data_application.properties.ejs', { baseName: baseName, BUILD_DIR: BUILD_DIR, devDatabaseType:devDatabaseType, prodDatabaseType: prodDatabaseType}) -%> +<%- include('../../../partials/data_application.properties.ejs', { baseName: baseName, BUILD_DIR: BUILD_DIR, devDatabaseType:devDatabaseType, prodDatabaseType: prodDatabaseType }) -%> +<% if(cacheManagerIsAvailable) { %> +<%- include('../../../partials/cache_application.properties.ejs') -%> +<% } %> quarkus.mailer.from=<%= dasherizedBaseName %>@localhost quarkus.mailer.host=localhost quarkus.mailer.port=25 diff --git a/generators/server/templates/quarkus/src/test/resources/application.properties.ejs b/generators/server/templates/quarkus/src/test/resources/application.properties.ejs new file mode 100644 index 00000000..5cd92d27 --- /dev/null +++ b/generators/server/templates/quarkus/src/test/resources/application.properties.ejs @@ -0,0 +1,68 @@ +<%# + Copyright 2013-2020 the original author or authors from the JHipster project. + + This file is part of the JHipster project, see https://www.jhipster.tech/ + for more information. + + 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. +-%> +application.name=<%= baseName %> + +<%- include('../../../partials/data_application-test.properties.ejs', { baseName: baseName, BUILD_DIR: BUILD_DIR, devDatabaseType:devDatabaseType, prodDatabaseType: prodDatabaseType}) -%> +quarkus.mailer.from=<%= dasherizedBaseName %>@localhost +quarkus.mailer.host=localhost +quarkus.mailer.port=25 +quarkus.mailer.ssl=false +quarkus.mailer.username= +quarkus.mailer.password= + +quarkus.micrometer.export.prometheus.path=/management/jhimetrics + +quarkus.smallrye-health.root-path=/management/health + +mp.jwt.verify.publickey.location=META-INF/resources/publicKey.pem +mp.jwt.verify.issuer=https://www.jhipster.tech +quarkus.smallrye-jwt.enabled=true + +jhipster.security.authentication.jwt.private-key.location=/jwt/privateKey.pem +jhipster.security.authentication.jwt.issuer=https://www.jhipster.tech +jhipster.security.authentication.jwt.token-validity-in-seconds=86400 +jhipster.security.authentication.jwt.token-validity-in-seconds-for-remember-me=2592000 +jhipster.mail.base-url=http://127.0.0.1:8080 +jhipster.info.swagger.enable=true + +quarkus.http.auth.permission.public.paths=/api/authenticate,/api/register,/api/activate,/api/account/reset-password/init,/api/account/reset-password/finish,/management/health,/management/info,/management/prometheus +quarkus.http.auth.permission.public.policy=permit + +quarkus.http.auth.policy.admin-role.roles-allowed=ROLE_ADMIN +quarkus.http.auth.permission.admin.paths=/api/users,/management/** +quarkus.http.auth.permission.admin.policy=admin-role + +quarkus.http.auth.policy.user-role.roles-allowed=ROLE_USER +quarkus.http.auth.permission.user.paths=/api/** +quarkus.http.auth.permission.user.policy=user-role + +quarkus.smallrye-openapi.path=/v2/api-docs +quarkus.swagger-ui.always-include=true +quarkus.swagger-ui.path=/swagger-ui + +quarkus.native.additional-build-args=\ + -H:ResourceConfigurationFiles=resources-config.json,\ + --initialize-at-run-time=<%= packageName %>.security.RandomUtil + +<%if (buildTool === 'gradle') { _%> +# Docker image build properties, for more information https://quarkus.io/guides/container-image +quarkus.container-image.group= +quarkus.container-image.name=<%= baseName %> +quarkus.container-image.tag=latest +<%_ } _%> diff --git a/test-integration/samples/imperative-sql-jwt-maven-sample.jh b/test-integration/samples/imperative-ngx-jwt-maven-mysql-caffeine.jh similarity index 88% rename from test-integration/samples/imperative-sql-jwt-maven-sample.jh rename to test-integration/samples/imperative-ngx-jwt-maven-mysql-caffeine.jh index 31b572c9..238f4475 100644 --- a/test-integration/samples/imperative-sql-jwt-maven-sample.jh +++ b/test-integration/samples/imperative-ngx-jwt-maven-mysql-caffeine.jh @@ -7,6 +7,8 @@ application { databaseType sql packageName io.github.jhipster.sample prodDatabaseType mysql + enableHibernateCache true + cacheProvider caffeine } entities * @@ -22,7 +24,7 @@ entity Label { entity Operation { date Instant required, description String, - amount BigDecimal required + amount BigDecimal required unique } relationship OneToMany { BankAccount{operation} to Operation{bankAccount(name)} diff --git a/test-integration/samples/imperative-sql-jwt-maven-sqllight.jh b/test-integration/samples/imperative-ngx-jwt-maven-psql-nocache.jh similarity index 67% rename from test-integration/samples/imperative-sql-jwt-maven-sqllight.jh rename to test-integration/samples/imperative-ngx-jwt-maven-psql-nocache.jh index d85f9645..bf9ca4c2 100644 --- a/test-integration/samples/imperative-sql-jwt-maven-sqllight.jh +++ b/test-integration/samples/imperative-ngx-jwt-maven-psql-nocache.jh @@ -1,15 +1,17 @@ application { - config { - applicationType monolith - authenticationType jwt - baseName jhipsterSampleApplication - buildTool maven - databaseType sql - packageName io.github.jhipster.sample - prodDatabaseType mysql - } + config { + applicationType monolith + authenticationType jwt + baseName jhipsterSampleApplication + buildTool maven + databaseType sql + packageName io.github.jhipster.sample + prodDatabaseType postgresql + enableHibernateCache false + cacheProvider no + } - entities * + entities * } entity BankAccount { diff --git a/test-integration/samples/imperative-react-jwt-gradle-mysql-caffeine.jh b/test-integration/samples/imperative-react-jwt-gradle-mysql-caffeine.jh new file mode 100644 index 00000000..00a1236e --- /dev/null +++ b/test-integration/samples/imperative-react-jwt-gradle-mysql-caffeine.jh @@ -0,0 +1,40 @@ +application { + config { + applicationType monolith + clientFramework react + authenticationType jwt + baseName jhipsterSampleApplication + buildTool gradle + databaseType sql + packageName io.github.jhipster.sample + prodDatabaseType mysql + enableHibernateCache true + cacheProvider caffeine + } + + entities * +} + +entity BankAccount { + name String required, + balance BigDecimal required +} +entity Label { + label String required minlength(3) +} +entity Operation { + date Instant required, + description String, + amount BigDecimal required unique +} +relationship OneToMany { + BankAccount{operation} to Operation{bankAccount(name)} +} +relationship ManyToOne { + BankAccount{user(login)} to User +} +relationship ManyToMany { + Operation{label(label)} to Label{operation} +} + +paginate Operation with infinite-scroll diff --git a/test/client.spec.js b/test/client.spec.js index d37870a8..aefb3f8b 100644 --- a/test/client.spec.js +++ b/test/client.spec.js @@ -1,13 +1,13 @@ -const path = require('path'); const assert = require('yeoman-assert'); -const helpers = require('yeoman-test'); const constants = require('generator-jhipster/generators/generator-constants'); +const { buildClientGeneratorContext } = require('./utils/generator-testing-api'); + const ANGULAR_DIR = constants.ANGULAR_DIR; describe('Subgenerator client of quarkus JHipster blueprint', () => { describe('Angular tests', () => { - before(initTests('angularX')); + before(buildClientGeneratorContext()); it('Angular health check files contain expected content', () => { assert.fileContent( @@ -27,38 +27,10 @@ describe('Subgenerator client of quarkus JHipster blueprint', () => { }); describe('React tests', () => { - before(initTests('react')); + before(buildClientGeneratorContext({ clientFramework: 'react' })); it('React health check files contain expected content', () => { assert.fileContent(`${ANGULAR_DIR}modules/administration/health/health.tsx`, '{data[configPropKey].name}'); }); }); - - function initTests(framework) { - return done => { - helpers - .run('generator-jhipster/generators/client') - .withOptions({ - 'from-cli': true, - skipInstall: true, - blueprint: 'quarkus', - skipChecks: true - }) - .withGenerators([ - [ - require('../generators/client/index.js'), // eslint-disable-line global-require - 'jhipster-quarkus:client', - path.join(__dirname, '../generators/client/index.js') - ] - ]) - .withPrompts({ - baseName: 'jhipster', - clientFramework: framework, - enableTranslation: true, - nativeLanguage: 'en', - languages: ['fr'] - }) - .on('end', done); - }; - } }); diff --git a/test/common.spec.js b/test/common.spec.js index f1bf30f4..1c718a34 100644 --- a/test/common.spec.js +++ b/test/common.spec.js @@ -1,46 +1,13 @@ -const path = require('path'); const assert = require('yeoman-assert'); -const helpers = require('yeoman-test'); + +const { buildCommonGeneratorContext } = require('./utils/generator-testing-api'); describe('Subgenerator common of quarkus JHipster blueprint', () => { - describe('Sample test', () => { - before(done => { - helpers - .run('generator-jhipster/generators/common') - .withOptions({ - 'from-cli': true, - skipInstall: true, - blueprint: 'quarkus', - skipChecks: true - }) - .withGenerators([ - [ - require('../generators/common'), // eslint-disable-line global-require - 'jhipster-quarkus:common', - path.join(__dirname, '../generators/common/index.js') - ] - ]) - .withPrompts({ - baseName: 'sampleMysql', - packageName: 'com.mycompany.myapp', - applicationType: 'monolith', - databaseType: 'sql', - devDatabaseType: 'h2Disk', - prodDatabaseType: 'mysql', - cacheProvider: 'ehcache', - authenticationType: 'session', - enableTranslation: true, - nativeLanguage: 'en', - languages: ['fr', 'de'], - buildTool: 'maven', - rememberMeKey: '2bb60a80889aa6e6767e9ccd8714982681152aa5' - }) - .on('end', done); - }); + describe('with Quarkus blueprint config', () => { + before(buildCommonGeneratorContext()); - it('it works', () => { - // Adds your tests here - assert.textEqual('Write your own tests!', 'Write your own tests!'); + it('README.md should contains Quarkus references', () => { + assert.fileContent('README.md', /JHipster Quarkus/); }); }); }); diff --git a/test/entity.spec.js b/test/entity.spec.js index 9451f8a6..e37e674e 100644 --- a/test/entity.spec.js +++ b/test/entity.spec.js @@ -1,48 +1,13 @@ -const path = require('path'); -const fse = require('fs-extra'); const assert = require('yeoman-assert'); -const helpers = require('yeoman-test'); const constants = require('generator-jhipster/generators/generator-constants'); const expectedFiles = require('./utils/expected-files').entity; +const { buildEntityGeneratorContext } = require('./utils/generator-testing-api'); -// const CLIENT_MAIN_SRC_DIR = constants.CLIENT_MAIN_SRC_DIR; -const SERVER_MAIN_SRC_DIR = constants.SERVER_MAIN_SRC_DIR; -// const SERVER_MAIN_RES_DIR = constants.SERVER_MAIN_RES_DIR; -// const SERVER_TEST_SRC_DIR = constants.SERVER_TEST_SRC_DIR; +const { SERVER_MAIN_SRC_DIR } = constants; describe('Subgenerator entity of quarkus JHipster blueprint', () => { describe('with default options (no repository, no service, no dto, no pagination)', () => { - before(done => { - helpers - .run('generator-jhipster/generators/entity') - .inTmpDir(dir => { - fse.copySync(path.join(__dirname, '../test/templates/ngx-blueprint'), dir); - }) - .withOptions({ - 'from-cli': true, - skipInstall: true, - blueprint: 'quarkus', - skipChecks: true, - creationTimestamp: '2019-11-06' - }) - .withGenerators([ - [ - require('../generators/entity'), // eslint-disable-line global-require - 'jhipster-quarkus:entity', - path.join(__dirname, '../generators/entity/index.js') - ] - ]) - .withArguments(['foo']) - .withPrompts({ - fieldAdd: false, - relationshipAdd: false, - dataAccess: 'activeRecord', - dto: 'no', - service: 'no', - pagination: 'no' - }) - .on('end', done); - }); + before(buildEntityGeneratorContext()); it('creates expected entity as active record and resources files', () => { assert.file(expectedFiles.server); @@ -69,39 +34,12 @@ describe('Subgenerator entity of quarkus JHipster blueprint', () => { assert.file('.jhipster/Foo.json'); assert.fileContent('.jhipster/Foo.json', '"dataAccess": "activeRecord"'); }); - }); - describe('with repository', () => { - before(done => { - helpers - .run('generator-jhipster/generators/entity') - .inTmpDir(dir => { - fse.copySync(path.join(__dirname, '../test/templates/ngx-blueprint'), dir); - }) - .withOptions({ - 'from-cli': true, - skipInstall: true, - blueprint: 'quarkus', - skipChecks: true, - creationTimestamp: '2019-11-06' - }) - .withGenerators([ - [ - require('../generators/entity'), // eslint-disable-line global-require - 'jhipster-quarkus:entity', - path.join(__dirname, '../generators/entity/index.js') - ] - ]) - .withArguments(['foo']) - .withPrompts({ - fieldAdd: false, - relationshipAdd: false, - dataAccess: 'repository', - dto: 'no', - service: 'no', - pagination: 'no' - }) - .on('end', done); + it('contains javax persistence cache annotation', () => { + assert.fileContent(`${SERVER_MAIN_SRC_DIR}com/mycompany/myapp/domain/Foo.java`, '@Cacheable'); }); + }); + describe('with repository and no hibernate second level cache', () => { + before(buildEntityGeneratorContext({ dataAccess: 'repository' }, {}, 'ngx-nocache')); it('creates expected entity with the corresponding repository', () => { assert.file(expectedFiles.server); @@ -120,40 +58,13 @@ describe('Subgenerator entity of quarkus JHipster blueprint', () => { assert.file('.jhipster/Foo.json'); assert.fileContent('.jhipster/Foo.json', '"dataAccess": "repository"'); }); + it('not contains javax persistence cache annotation', () => { + assert.noFileContent(`${SERVER_MAIN_SRC_DIR}com/mycompany/myapp/domain/Foo.java`, '@Cacheable'); + }); }); describe('with dto', () => { - before(done => { - helpers - .run('generator-jhipster/generators/entity') - .inTmpDir(dir => { - fse.copySync(path.join(__dirname, '../test/templates/ngx-blueprint'), dir); - }) - .withOptions({ - 'from-cli': true, - skipInstall: true, - blueprint: 'quarkus', - skipChecks: true, - creationTimestamp: '2019-11-06' - }) - .withGenerators([ - [ - require('../generators/entity'), // eslint-disable-line global-require - 'jhipster-quarkus:entity', - path.join(__dirname, '../generators/entity/index.js') - ] - ]) - .withArguments(['foo']) - .withPrompts({ - fieldAdd: false, - relationshipAdd: false, - dataAccess: 'activeRecord', - dto: 'mapstruct', - service: 'serviceClass', - pagination: 'no' - }) - .on('end', done); - }); + before(buildEntityGeneratorContext({ dto: 'mapstruct', service: 'serviceClass', pagination: 'no' }, {})); it('creates expected entity with the corresponding dto', () => { assert.file(expectedFiles.server); @@ -172,37 +83,7 @@ describe('Subgenerator entity of quarkus JHipster blueprint', () => { }); }); describe('with dto and service interface and service implementation', () => { - before(done => { - helpers - .run('generator-jhipster/generators/entity') - .inTmpDir(dir => { - fse.copySync(path.join(__dirname, '../test/templates/ngx-blueprint'), dir); - }) - .withOptions({ - 'from-cli': true, - skipInstall: true, - blueprint: 'quarkus', - skipChecks: true, - creationTimestamp: '2019-11-06' - }) - .withGenerators([ - [ - require('../generators/entity'), // eslint-disable-line global-require - 'jhipster-quarkus:entity', - path.join(__dirname, '../generators/entity/index.js') - ] - ]) - .withArguments(['foo']) - .withPrompts({ - fieldAdd: false, - relationshipAdd: false, - dataAccess: 'activeRecord', - dto: 'mapstruct', - service: 'serviceImpl', - pagination: 'no' - }) - .on('end', done); - }); + before(buildEntityGeneratorContext({ dto: 'mapstruct', service: 'serviceImpl', pagination: 'no' }, {})); it('creates expected entity with the corresponding dto', () => { assert.file(expectedFiles.server); @@ -220,38 +101,8 @@ describe('Subgenerator entity of quarkus JHipster blueprint', () => { ); }); }); - describe('with pagination', () => { - before(done => { - helpers - .run('generator-jhipster/generators/entity') - .inTmpDir(dir => { - fse.copySync(path.join(__dirname, '../test/templates/ngx-blueprint'), dir); - }) - .withOptions({ - 'from-cli': true, - skipInstall: true, - blueprint: 'quarkus', - skipChecks: true, - creationTimestamp: '2019-11-06' - }) - .withGenerators([ - [ - require('../generators/entity'), // eslint-disable-line global-require - 'jhipster-quarkus:entity', - path.join(__dirname, '../generators/entity/index.js') - ] - ]) - .withArguments(['foo']) - .withPrompts({ - fieldAdd: false, - relationshipAdd: false, - dataAccess: 'activeRecord', - dto: 'no', - service: 'no', - pagination: 'pagination' - }) - .on('end', done); - }); + describe('with pagination and readOnly', () => { + before(buildEntityGeneratorContext({ pagination: 'pagination', readOnly: true }, {})); it('creates expected pagination file', () => { assert.file(expectedFiles.server); @@ -269,41 +120,17 @@ describe('Subgenerator entity of quarkus JHipster blueprint', () => { 'public Response getAllFoos(@BeanParam PageRequestVM pageRequest, @BeanParam SortRequestVM sortRequest, @Context UriInfo uriInfo)' ); }); + it('contains READ_ONLY Hibernate cache annotation', () => { + assert.noFileContent( + `${SERVER_MAIN_SRC_DIR}com/mycompany/myapp/domain/Foo.java`, + '@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)' + ); + }); }); describe('with pagination(infinite-scroll), service and dto', () => { - before(done => { - helpers - .run('generator-jhipster/generators/entity') - .inTmpDir(dir => { - fse.copySync(path.join(__dirname, '../test/templates/ngx-blueprint'), dir); - }) - .withOptions({ - 'from-cli': true, - skipInstall: true, - blueprint: 'quarkus', - skipChecks: true, - creationTimestamp: '2019-11-06' - }) - .withGenerators([ - [ - require('../generators/entity'), // eslint-disable-line global-require - 'jhipster-quarkus:entity', - path.join(__dirname, '../generators/entity/index.js') - ] - ]) - .withArguments(['foo']) - .withPrompts({ - fieldAdd: false, - relationshipAdd: false, - dataAccess: 'activeRecord', - dto: 'mapstruct', - service: 'serviceClass', - pagination: 'infinite-scroll' - }) - .on('end', done); - }); + before(buildEntityGeneratorContext({ dto: 'mapstruct', service: 'serviceClass', pagination: 'infinite-scroll' }, {})); - it('creates expected pagination file', () => { + it('creates expected infinite-scroll file', () => { assert.file(expectedFiles.server); assert.file(expectedFiles.fakeData); assert.file(expectedFiles.serverLiquibase); diff --git a/test/server.spec.js b/test/server.spec.js index 54917e9b..6b69e7e6 100644 --- a/test/server.spec.js +++ b/test/server.spec.js @@ -1,15 +1,14 @@ -const path = require('path'); const assert = require('yeoman-assert'); -const helpers = require('yeoman-test'); const constants = require('generator-jhipster/generators/generator-constants'); +const { buildServerGeneratorContext } = require('./utils/generator-testing-api'); const expectedFiles = require('./utils/expected-files'); -const { SERVER_MAIN_RES_DIR } = constants; +const { SERVER_MAIN_SRC_DIR, SERVER_MAIN_RES_DIR } = constants; describe('Subgenerator server of quarkus JHipster blueprint', () => { describe('With monolith Maven Mysql', () => { - before(buildGeneratorContext()); + before(buildServerGeneratorContext()); it('creates expected files for default configuration for server generator', () => { assert.file(expectedFiles.server); @@ -29,11 +28,43 @@ describe('Subgenerator server of quarkus JHipster blueprint', () => { it('second cache level property is true', () => { assert.fileContent(`${SERVER_MAIN_RES_DIR}application.properties`, 'quarkus.hibernate-orm.second-level-caching-enabled=true'); }); + + it('User and Authority cache properties are set', () => { + assert.noFileContent( + `${SERVER_MAIN_RES_DIR}application.properties`, + 'quarkus.cache.caffeine."usersByEmail".maximum-size=100\n' + + 'quarkus.cache.caffeine."usersByEmail".expire-after-write=3600S\n' + + 'quarkus.cache.caffeine."usersByLogin".maximum-size=100\n' + + 'quarkus.cache.caffeine."usersByLogin".expire-after-write=3600S' + ); + }); + + it('contains hibernate second level cache needle', () => { + assert.fileContent(`${SERVER_MAIN_RES_DIR}application.properties`, '# jhipster-quarkus-needle-hibernate-cache-add-entry'); + }); + }); + + describe('With monolith Gradle Mysql', () => { + before( + buildServerGeneratorContext({ + buildTool: 'gradle', + cacheProvider: 'caffeine' + }) + ); + + it('creates expected files for default configuration for server generator', () => { + assert.file(expectedFiles.server); + assert.file(expectedFiles.gradle); + }); + + it('build.gradle contains health check dependency', () => { + assert.fileContent('build.gradle', "implementation 'io.quarkus:quarkus-cache'"); + }); }); describe('With maven Mysql no second cache level', () => { before( - buildGeneratorContext({ + buildServerGeneratorContext({ enableHibernateCache: false }) ); @@ -48,42 +79,89 @@ describe('Subgenerator server of quarkus JHipster blueprint', () => { assert.fileContent(`${SERVER_MAIN_RES_DIR}application.properties`, 'quarkus.hibernate-orm.second-level-caching-enabled=false'); }); }); -}); -function buildGeneratorContext(prompts) { - return done => { - helpers - .run('generator-jhipster/generators/server') - .withOptions({ - 'from-cli': true, - skipInstall: true, - blueprint: 'quarkus', - skipChecks: true + describe('With maven Mysql and caffeine cache', () => { + before( + buildServerGeneratorContext({ + cacheProvider: 'caffeine' }) - .withGenerators([ - [ - require('../generators/server'), // eslint-disable-line global-require - 'jhipster-quarkus:server', - path.join(__dirname, '../generators/server/index.js') - ] - ]) - .withPrompts({ - baseName: 'sampleMysql', - packageName: 'com.mycompany.myapp', - applicationType: 'monolith', - databaseType: 'sql', - devDatabaseType: 'h2Disk', - prodDatabaseType: 'mysql', - cacheProvider: 'ehcache', - authenticationType: 'session', - enableTranslation: true, - nativeLanguage: 'en', - languages: ['fr', 'de'], - buildTool: 'maven', - enableHibernateCache: true, - rememberMeKey: '2bb60a80889aa6e6767e9ccd8714982681152aa5', - ...prompts + ); + + it('should pom.xml contains Quarkus cache dependency', () => { + assert.fileContent( + 'pom.xml', + ' \n' + + ' io.quarkus\n' + + ' quarkus-cache\n' + + ' ' + ); + }); + + it('should UserService contains cache implementation', () => { + assert.fileContent( + `${SERVER_MAIN_SRC_DIR}com/mycompany/myapp/service/UserService.java`, + 'import io.quarkus.cache.CacheInvalidate;' + ); + + assert.fileContent( + `${SERVER_MAIN_SRC_DIR}com/mycompany/myapp/service/UserService.java`, + '@CacheInvalidate(cacheName = User.USERS_BY_EMAIL_CACHE)' + ); + + assert.fileContent( + `${SERVER_MAIN_SRC_DIR}com/mycompany/myapp/service/UserService.java`, + '@CacheInvalidate(cacheName = User.USERS_BY_LOGIN_CACHE)' + ); + }); + + it('Quarkus caffeine cache is enabled', () => { + assert.fileContent(`${SERVER_MAIN_RES_DIR}application.properties`, 'quarkus.cache.enabled=true'); + assert.fileContent(`${SERVER_MAIN_RES_DIR}application.properties`, 'quarkus.cache.type=caffeine'); + }); + + it('User and Authority cache properties are set', () => { + assert.fileContent( + `${SERVER_MAIN_RES_DIR}application.properties`, + 'quarkus.cache.caffeine."usersByEmail".maximum-size=100\n' + + 'quarkus.cache.caffeine."usersByEmail".expire-after-write=3600S\n' + + 'quarkus.cache.caffeine."usersByLogin".maximum-size=100\n' + + 'quarkus.cache.caffeine."usersByLogin".expire-after-write=3600S' + ); + }); + }); + + describe('With maven Mysql and no cache', () => { + before( + buildServerGeneratorContext({ + cacheProvider: 'no' }) - .on('end', done); - }; -} + ); + + it('should pom.xml not contains Quarkus cache dependency', () => { + assert.noFileContent( + 'pom.xml', + ' \n' + + ' io.quarkus\n' + + ' quarkus-cache\n' + + ' ' + ); + }); + + it('should UserService not contains cache implementation', () => { + assert.noFileContent( + `${SERVER_MAIN_SRC_DIR}com/mycompany/myapp/service/UserService.java`, + 'import io.quarkus.cache.CacheInvalidate;' + ); + + assert.noFileContent( + `${SERVER_MAIN_SRC_DIR}com/mycompany/myapp/service/UserService.java`, + '@CacheInvalidate(cacheName = User.USERS_BY_EMAIL_CACHE)' + ); + + assert.noFileContent( + `${SERVER_MAIN_SRC_DIR}com/mycompany/myapp/service/UserService.java`, + '@CacheInvalidate(cacheName = User.USERS_BY_LOGIN_CACHE)' + ); + }); + }); +}); diff --git a/test/templates/ngx-nocache/.yo-rc.json b/test/templates/ngx-nocache/.yo-rc.json new file mode 100644 index 00000000..783b67ef --- /dev/null +++ b/test/templates/ngx-nocache/.yo-rc.json @@ -0,0 +1,42 @@ +{ + "generator-jhipster-quarkus": { + "promptValues": { + "packageName": "com.mycompany.myapp" + }, + "applicationType": "monolith", + "baseName": "jhipsterBlueprint", + "packageName": "com.mycompany.myapp", + "packageFolder": "com/mycompany/myapp", + "serverPort": "8080", + "authenticationType": "jwt", + "cacheProvider": "no", + "enableHibernateCache": false, + "websocket": false, + "databaseType": "sql", + "devDatabaseType": "h2Disk", + "prodDatabaseType": "mysql", + "searchEngine": false, + "messageBroker": false, + "serviceDiscoveryType": false, + "buildTool": "maven", + "enableSwaggerCodegen": false, + "jwtSecretKey": "147e04cf224f52908a60d7a2902e19e0648d0a8c52503b4624f1708478dd29ba2885a9bb823c85873a76b27964a90e22f1e8", + "clientFramework": "angularX", + "useSass": false, + "clientPackageManager": "npm" + }, + "generator-jhipster": { + "promptValues": { + "nativeLanguage": "en" + }, + "applicationType": "monolith", + "baseName": "jhipsterBlueprint", + "testFrameworks": ["gatling", "protractor"], + "jhiPrefix": "jhi", + "enableTranslation": true, + "clientPackageManager": "npm", + "nativeLanguage": "en", + "languages": ["en", "fr"], + "blueprint": "generator-jhipster-quarkus" + } +} diff --git a/test/utils/constants.js b/test/utils/constants.js new file mode 100644 index 00000000..355fc1d9 --- /dev/null +++ b/test/utils/constants.js @@ -0,0 +1,56 @@ +const DEFAULT_ENTITY_ANSWERS = { + fieldAdd: false, + relationshipAdd: false, + dataAccess: 'activeRecord', + dto: 'no', + service: 'no', + pagination: 'no' +}; + +const DEFAULT_SERVER_ANSWERS = { + baseName: 'sampleMysql', + packageName: 'com.mycompany.myapp', + applicationType: 'monolith', + databaseType: 'sql', + devDatabaseType: 'h2Disk', + prodDatabaseType: 'mysql', + cacheProvider: 'ehcache', + authenticationType: 'session', + enableTranslation: true, + nativeLanguage: 'en', + languages: ['fr', 'de'], + buildTool: 'maven', + enableHibernateCache: true, + rememberMeKey: '2bb60a80889aa6e6767e9ccd8714982681152aa5' +}; + +const DEFAULT_CLIENT_ANSWERS = { + baseName: 'jhipster', + clientFramework: 'angularX', + enableTranslation: true, + nativeLanguage: 'en', + languages: ['fr'] +}; + +const DEFAULT_QUARKUS_BP_OPTIONS = { + 'from-cli': true, + skipInstall: true, + blueprint: 'quarkus', + skipChecks: true +}; + +const DEFAULT_QUARKUS_ENTITY_BP_OPTIONS = { + ...DEFAULT_QUARKUS_BP_OPTIONS, + creationTimestamp: '2019-11-06' +}; + +const DEFAULT_YORC_FILENAME = 'ngx-blueprint'; + +module.exports = { + DEFAULT_ENTITY_ANSWERS, + DEFAULT_SERVER_ANSWERS, + DEFAULT_CLIENT_ANSWERS, + DEFAULT_QUARKUS_BP_OPTIONS, + DEFAULT_QUARKUS_ENTITY_BP_OPTIONS, + DEFAULT_YORC_FILENAME +}; diff --git a/test/utils/expected-files.js b/test/utils/expected-files.js index a65aa805..5c647936 100644 --- a/test/utils/expected-files.js +++ b/test/utils/expected-files.js @@ -1,9 +1,21 @@ const constants = require('generator-jhipster/generators/generator-constants'); -const { SERVER_MAIN_SRC_DIR, SERVER_MAIN_RES_DIR, SERVER_TEST_SRC_DIR, DOCKER_DIR /* , SERVER_TEST_RES_DIR */ } = constants; +const { SERVER_MAIN_SRC_DIR, SERVER_MAIN_RES_DIR, SERVER_TEST_SRC_DIR, DOCKER_DIR, SERVER_TEST_RES_DIR } = constants; const expectedFiles = { maven: ['pom.xml', 'mvnw', 'mvnw.cmd', '.mvn/wrapper/maven-wrapper.jar', '.mvn/wrapper/maven-wrapper.properties'], + gradle: [ + 'build.gradle', + 'gradlew', + 'gradle.properties', + 'settings.gradle', + 'gradle/docker.gradle', + 'gradle/profile_dev.gradle', + 'gradle/profile_prod.gradle', + 'gradle/sonar.gradle', + 'gradle/wrapper/gradle-wrapper.jar', + 'gradle/wrapper/gradle-wrapper.properties' + ], docker: [`${DOCKER_DIR}Dockerfile.jvm`, `${DOCKER_DIR}Dockerfile.native`, `${DOCKER_DIR}Dockerfile.fast-jar`], @@ -47,6 +59,7 @@ const expectedFiles = { `${SERVER_MAIN_SRC_DIR}com/mycompany/myapp/web/rest/UserResource.java`, `${SERVER_MAIN_SRC_DIR}com/mycompany/myapp/web/util/HeaderUtil.java`, `${SERVER_MAIN_SRC_DIR}com/mycompany/myapp/web/util/ResponseUtil.java`, + `${SERVER_TEST_RES_DIR}application.properties`, `${SERVER_TEST_SRC_DIR}com/mycompany/myapp/domain/AuthorityTest.java`, `${SERVER_TEST_SRC_DIR}com/mycompany/myapp/domain/UserTest.java`, `${SERVER_TEST_SRC_DIR}com/mycompany/myapp/service/mapper/UserMapperTest.java`, diff --git a/test/utils/generator-builder.js b/test/utils/generator-builder.js new file mode 100644 index 00000000..50f73109 --- /dev/null +++ b/test/utils/generator-builder.js @@ -0,0 +1,42 @@ +const helpers = require('yeoman-test'); +const fse = require('fs-extra'); +const path = require('path'); + +module.exports = class { + constructor(generatorName) { + this.runContext = helpers.run(`generator-jhipster/generators/${generatorName}`).withGenerators([ + [ + // eslint-disable-next-line import/no-dynamic-require + require(`../../generators/${generatorName}`), // eslint-disable-line global-require + `jhipster-quarkus:${generatorName}`, + path.join(__dirname, `../../generators/${generatorName}/index.js`) + ] + ]); + } + + withPrompts(answers) { + this.runContext.withPrompts(answers); + return this; + } + + withYoRc(fileName) { + this.runContext.inTmpDir(dir => { + fse.copySync(path.join(__dirname, `../templates/${fileName}`), dir); + }); + return this; + } + + withOptions(options) { + this.runContext.withOptions(options); + return this; + } + + withArguments(args) { + this.runContext.withArguments(args); + return this; + } + + build(callBack) { + return this.runContext.on('end', callBack); + } +}; diff --git a/test/utils/generator-testing-api.js b/test/utils/generator-testing-api.js new file mode 100644 index 00000000..c5d29eeb --- /dev/null +++ b/test/utils/generator-testing-api.js @@ -0,0 +1,55 @@ +const GeneratorTestBuilder = require('./generator-builder'); +const { + DEFAULT_ENTITY_ANSWERS, + DEFAULT_SERVER_ANSWERS, + DEFAULT_CLIENT_ANSWERS, + DEFAULT_QUARKUS_ENTITY_BP_OPTIONS, + DEFAULT_QUARKUS_BP_OPTIONS, + DEFAULT_YORC_FILENAME +} = require('./constants'); + +function buildEntityGeneratorContext( + answers = DEFAULT_ENTITY_ANSWERS, + options = DEFAULT_QUARKUS_ENTITY_BP_OPTIONS, + yoRcFileName = DEFAULT_YORC_FILENAME +) { + return done => { + new GeneratorTestBuilder('entity') + .withPrompts({ ...DEFAULT_ENTITY_ANSWERS, ...answers }) + .withYoRc(yoRcFileName) + .withOptions({ ...DEFAULT_QUARKUS_ENTITY_BP_OPTIONS, ...options }) + .withArguments(['foo']) + .build(done); + }; +} + +function buildServerGeneratorContext(answers = DEFAULT_SERVER_ANSWERS, options = DEFAULT_QUARKUS_BP_OPTIONS) { + return done => { + new GeneratorTestBuilder('server') + .withPrompts({ ...DEFAULT_SERVER_ANSWERS, ...answers }) + .withOptions({ ...DEFAULT_QUARKUS_ENTITY_BP_OPTIONS, ...options }) + .build(done); + }; +} + +function buildClientGeneratorContext(answers = DEFAULT_CLIENT_ANSWERS, options = DEFAULT_QUARKUS_BP_OPTIONS) { + return done => { + new GeneratorTestBuilder('client') + .withPrompts({ ...DEFAULT_CLIENT_ANSWERS, ...answers }) + .withOptions({ ...DEFAULT_QUARKUS_ENTITY_BP_OPTIONS, ...options }) + .build(done); + }; +} + +function buildCommonGeneratorContext(options = DEFAULT_QUARKUS_BP_OPTIONS) { + return done => { + new GeneratorTestBuilder('common').withOptions({ ...DEFAULT_QUARKUS_ENTITY_BP_OPTIONS, ...options }).build(done); + }; +} + +module.exports = { + buildEntityGeneratorContext, + buildServerGeneratorContext, + buildClientGeneratorContext, + buildCommonGeneratorContext +};