当我使用 liquibase 更改模型数据时,JHipster 集成测试失败
JHipster integration tests fail when I used liquibase to change model data
总结:我更新了我的 类、测试 类 和我的数据库以使用电子邮件登录。我写了一个 liquibase 的变更日志来进行数据库的更改。
运行 项目,一切正常,但如果我执行集成测试,liquibase 的变更日志工作不正常。
我认为正在发生的事情:
- 我尝试执行测试。
- H2 数据库随每个更改日志(初始和自定义)初始化
- 测试开始执行。
- 在每次测试之前,H2 数据库不会被删除,但会调用变更日志(或仅调用我的自定义变更日志)。
- 我的自定义更改日志失败,因为它找不到在第 2 点删除的登录列,并且它不是 "restaurated" 初始
变更日志。
完整版:我用4.8.0生成了一个JHipster应用。我的.yo-rc.json:
{
"generator-jhipster": {
"promptValues": {
"packageName": "com.company.name",
"nativeLanguage": "es"
},
"jhipsterVersion": "4.8.0",
"baseName": "name",
"packageName": "com.company.name",
"packageFolder": "com/company/name",
"serverPort": "8080",
"authenticationType": "jwt",
"hibernateCache": "no",
"clusteredHttpSession": false,
"websocket": false,
"databaseType": "sql",
"devDatabaseType": "postgresql",
"prodDatabaseType": "postgresql",
"searchEngine": false,
"messageBroker": false,
"serviceDiscoveryType": false,
"buildTool": "gradle",
"enableSocialSignIn": false,
"enableSwaggerCodegen": false,
"jwtSecretKey": "secret",
"clientFramework": "angularX",
"useSass": true,
"clientPackageManager": "yarn",
"applicationType": "monolith",
"testFrameworks": [],
"jhiPrefix": "jhi",
"enableTranslation": true,
"nativeLanguage": "es",
"languages": [
"es"
]
}
}
我想从 JHI_USER 中删除登录列并从 JHI_USER 的电子邮件中删除唯一约束并使其不为空,然后,我进行了我需要的所有代码更改(我删除了每个参考登录,我将它们更改为电子邮件)并编码了三个 liquibase 更新日志文件:
a) 20170913130000_drop_login_column_JhiUser.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
<changeSet id="20170913130000" author="svalero">
<dropColumn columnName="login" tableName="jhi_user" />
</changeSet>
</databaseChangeLog>
B) 20170913180000_drop_unique_constraint_email_JhiUser.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
<changeSet id="20170913180000" author="svalero">
<dropUniqueConstraint constraintName="jhi_user_email_key"
tableName="jhi_user" />
</changeSet>
</databaseChangeLog>
C) 20170913182100_add_notnull_constraint_email_JhiUser.xml
<?xml version="1.0" encoding="UTF-8" ?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
<changeSet id="20170913182100" author="svalero">
<addNotNullConstraint columnDataType="varchar(100)"
columnName="email"
tableName="jhi_user"/>
</changeSet>
</databaseChangeLog>
我还在 master.xml 上添加了它们,一切都在应用程序上完美运行(./gradlew 和 yarn start)。
但是,当我尝试执行集成测试 (./gradlew test) 时,我在每次测试中都得到了这个:
com.company.name.web.rest.AuditResourceIntTest > getNonExistingAudit FAILED
java.lang.IllegalStateException
Caused by: org.springframework.beans.factory.BeanCreationException
Caused by: liquibase.exception.MigrationFailedException
Caused by: liquibase.exception.DatabaseException
Caused by: org.h2.jdbc.JdbcSQLException
从测试结果中我发现:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibase' defined in class path resource [com/company/name/config/DatabaseConfiguration.class]: Invocation of init method failed; nested exception is liquibase.exception.MigrationFailedException: Migration failed for change set config/liquibase/changelog/20170913180000_drop_unique_constraint_email_JhiUser.xml::20170913180000::svalero:
Reason: liquibase.exception.DatabaseException: Constraint "JHI_USER_EMAIL_KEY" not found;
SQL statement: ALTER TABLE PUBLIC.jhi_user DROP CONSTRAINT jhi_user_email_key [90057-196] [Failed SQL: ALTER TABLE PUBLIC.jhi_user DROP CONSTRAINT jhi_user_email_key]
然后,我认为在每次测试中都会调用我的自定义变更日志,但不会调用初始变更日志,因为我的变更日志找不到初始变更日志必须创建的列或约束。
我的第一个 "walkaround" 很简单,将前提条件添加到更改日志中,例如:
<preConditions onFail="MARK_RAN" onError="MARK_RAN">
<columnExists columnName="login" tableName="jhi_user" schemaName="public" />
</preConditions>
但是 Liquibase 没有 "unique constraint" 的先决条件,我发现这是为了检查 "jhi_user_email_key" 约束是否存在:
<preConditions onFail="MARK_RAN" onError="MARK_RAN">
<sqlCheck expectedResult="1">select count (*) from pg_constraint where conname='jhi_user_email_key'</sqlCheck>
</preConditions>
但是在 H2 中(JHipster 使用这种数据库进行测试)我们没有 pg_constraint 这不起作用。
最后,有什么问题吗?为什么测试 运行 只是我的变更日志,而它们忽略了初始变更日志?我该如何解决?
与此同时,我在 JHipster 上创建了一个 PR 6460,它被合并了,我猜它已经成为下一个版本 4.9.1 的一部分。唯一约束的名称是 ux_user_mail 即您的文件 B)20170913180000_drop_unique_constraint_email_JhiUser.xml 应该改为:
.....
<dropUniqueConstraint constraintName="ux_user_mail"
tableName="jhi_user" />
.....
仍然,删除 LOGIN 列将对登录过程产生影响,即您需要更改 UserService 的方法 getUserWithAuthorities class 例如
@Transactional(readOnly = true)
public User getUserWithAuthorities() {
return userRepository.findOneWithAuthoritiesByEmail(SecurityUtils.getCurrentUserLogin()).orElse(null);
}
和 loadUserByUsername 在 DomainUserDetailsService class:
@Override
@Transactional
public UserDetails loadUserByUsername(final String login) {
log.debug("Authenticating {}", login);
String lowercaseLogin = login.toLowerCase(Locale.ENGLISH);
Optional<User> userFromDatabase = userRepository.findOneWithAuthoritiesByEmail(lowercaseLogin);
return ........
UserRepository 也需要使用搜索方法来丰富,例如
@EntityGraph(attributePaths = "authorities")
Optional<User> findOneWithAuthoritiesByEmail(String email);
另一方面,您还需要删除域 class 用户的登录名 属性。仅删除 @Column 注释是不够的。即使 属性 login 在 class 中而没有 @Column 注释,hibernate 也会因为 SchemaManagementException 而消失JHipster命名策略是这样配置的
jpa:
hibernate:
naming:
physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
并且将不再期望列登录存在于 jhi_user table 中。可以找到命名策略的文档 here.
对于你的第二个 liquibase changeSet * 20170913180000_drop_unique_constraint_email_JhiUser.xml* 我会建议你验证约束 jhi_user_email_key 是否存在。
这将使您可以使用电子邮件登录。仍然通过从域 class User 中删除 login 属性 你将需要重构一些 classes 来自生产和测试代码
在 JHipster 4.10.0 或更高版本上,感谢@duderoot,它是这样创建的:
<column name="email" type="varchar(100)">
<constraints unique="true" nullable="true" uniqueConstraintName="ux_user_email"/>
</column>
然后,您可以使用此名称删除此约束,而不会在任何环境中出现问题。
在 JHipster 4.8.0 上,"unique constraint" 是这样创建的:
<column name="email" type="varchar(100)">
<constraints unique="true" nullable="true"/>
</column>
他们不使用 "uniqueConstraintName" 并且约束的名称在每个数据库上都不同。
在 Postgresql(开发配置文件)上,"jhi_user_email_key" 存在,但在 H2(测试配置文件)上不存在。
要解决这个问题,您可以在 Initial Schema 上添加 uniqueConstraintName:
<column name="email" type="varchar(100)">
<constraints unique="true" nullable="true" uniqueConstraintName="jhi_user_email_key"/>
</column>
或者根据 "dbms" 先决条件制作不同的变更日志。
总结:我更新了我的 类、测试 类 和我的数据库以使用电子邮件登录。我写了一个 liquibase 的变更日志来进行数据库的更改。 运行 项目,一切正常,但如果我执行集成测试,liquibase 的变更日志工作不正常。
我认为正在发生的事情:
- 我尝试执行测试。
- H2 数据库随每个更改日志(初始和自定义)初始化
- 测试开始执行。
- 在每次测试之前,H2 数据库不会被删除,但会调用变更日志(或仅调用我的自定义变更日志)。
- 我的自定义更改日志失败,因为它找不到在第 2 点删除的登录列,并且它不是 "restaurated" 初始 变更日志。
完整版:我用4.8.0生成了一个JHipster应用。我的.yo-rc.json:
{
"generator-jhipster": {
"promptValues": {
"packageName": "com.company.name",
"nativeLanguage": "es"
},
"jhipsterVersion": "4.8.0",
"baseName": "name",
"packageName": "com.company.name",
"packageFolder": "com/company/name",
"serverPort": "8080",
"authenticationType": "jwt",
"hibernateCache": "no",
"clusteredHttpSession": false,
"websocket": false,
"databaseType": "sql",
"devDatabaseType": "postgresql",
"prodDatabaseType": "postgresql",
"searchEngine": false,
"messageBroker": false,
"serviceDiscoveryType": false,
"buildTool": "gradle",
"enableSocialSignIn": false,
"enableSwaggerCodegen": false,
"jwtSecretKey": "secret",
"clientFramework": "angularX",
"useSass": true,
"clientPackageManager": "yarn",
"applicationType": "monolith",
"testFrameworks": [],
"jhiPrefix": "jhi",
"enableTranslation": true,
"nativeLanguage": "es",
"languages": [
"es"
]
}
}
我想从 JHI_USER 中删除登录列并从 JHI_USER 的电子邮件中删除唯一约束并使其不为空,然后,我进行了我需要的所有代码更改(我删除了每个参考登录,我将它们更改为电子邮件)并编码了三个 liquibase 更新日志文件:
a) 20170913130000_drop_login_column_JhiUser.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
<changeSet id="20170913130000" author="svalero">
<dropColumn columnName="login" tableName="jhi_user" />
</changeSet>
</databaseChangeLog>
B) 20170913180000_drop_unique_constraint_email_JhiUser.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
<changeSet id="20170913180000" author="svalero">
<dropUniqueConstraint constraintName="jhi_user_email_key"
tableName="jhi_user" />
</changeSet>
</databaseChangeLog>
C) 20170913182100_add_notnull_constraint_email_JhiUser.xml
<?xml version="1.0" encoding="UTF-8" ?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
<changeSet id="20170913182100" author="svalero">
<addNotNullConstraint columnDataType="varchar(100)"
columnName="email"
tableName="jhi_user"/>
</changeSet>
</databaseChangeLog>
我还在 master.xml 上添加了它们,一切都在应用程序上完美运行(./gradlew 和 yarn start)。
但是,当我尝试执行集成测试 (./gradlew test) 时,我在每次测试中都得到了这个:
com.company.name.web.rest.AuditResourceIntTest > getNonExistingAudit FAILED
java.lang.IllegalStateException
Caused by: org.springframework.beans.factory.BeanCreationException
Caused by: liquibase.exception.MigrationFailedException
Caused by: liquibase.exception.DatabaseException
Caused by: org.h2.jdbc.JdbcSQLException
从测试结果中我发现:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibase' defined in class path resource [com/company/name/config/DatabaseConfiguration.class]: Invocation of init method failed; nested exception is liquibase.exception.MigrationFailedException: Migration failed for change set config/liquibase/changelog/20170913180000_drop_unique_constraint_email_JhiUser.xml::20170913180000::svalero:
Reason: liquibase.exception.DatabaseException: Constraint "JHI_USER_EMAIL_KEY" not found;
SQL statement: ALTER TABLE PUBLIC.jhi_user DROP CONSTRAINT jhi_user_email_key [90057-196] [Failed SQL: ALTER TABLE PUBLIC.jhi_user DROP CONSTRAINT jhi_user_email_key]
然后,我认为在每次测试中都会调用我的自定义变更日志,但不会调用初始变更日志,因为我的变更日志找不到初始变更日志必须创建的列或约束。
我的第一个 "walkaround" 很简单,将前提条件添加到更改日志中,例如:
<preConditions onFail="MARK_RAN" onError="MARK_RAN">
<columnExists columnName="login" tableName="jhi_user" schemaName="public" />
</preConditions>
但是 Liquibase 没有 "unique constraint" 的先决条件,我发现这是为了检查 "jhi_user_email_key" 约束是否存在:
<preConditions onFail="MARK_RAN" onError="MARK_RAN">
<sqlCheck expectedResult="1">select count (*) from pg_constraint where conname='jhi_user_email_key'</sqlCheck>
</preConditions>
但是在 H2 中(JHipster 使用这种数据库进行测试)我们没有 pg_constraint 这不起作用。
最后,有什么问题吗?为什么测试 运行 只是我的变更日志,而它们忽略了初始变更日志?我该如何解决?
与此同时,我在 JHipster 上创建了一个 PR 6460,它被合并了,我猜它已经成为下一个版本 4.9.1 的一部分。唯一约束的名称是 ux_user_mail 即您的文件 B)20170913180000_drop_unique_constraint_email_JhiUser.xml 应该改为:
.....
<dropUniqueConstraint constraintName="ux_user_mail"
tableName="jhi_user" />
.....
仍然,删除 LOGIN 列将对登录过程产生影响,即您需要更改 UserService 的方法 getUserWithAuthorities class 例如
@Transactional(readOnly = true)
public User getUserWithAuthorities() {
return userRepository.findOneWithAuthoritiesByEmail(SecurityUtils.getCurrentUserLogin()).orElse(null);
}
和 loadUserByUsername 在 DomainUserDetailsService class:
@Override
@Transactional
public UserDetails loadUserByUsername(final String login) {
log.debug("Authenticating {}", login);
String lowercaseLogin = login.toLowerCase(Locale.ENGLISH);
Optional<User> userFromDatabase = userRepository.findOneWithAuthoritiesByEmail(lowercaseLogin);
return ........
UserRepository 也需要使用搜索方法来丰富,例如
@EntityGraph(attributePaths = "authorities")
Optional<User> findOneWithAuthoritiesByEmail(String email);
另一方面,您还需要删除域 class 用户的登录名 属性。仅删除 @Column 注释是不够的。即使 属性 login 在 class 中而没有 @Column 注释,hibernate 也会因为 SchemaManagementException 而消失JHipster命名策略是这样配置的
jpa:
hibernate:
naming:
physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
并且将不再期望列登录存在于 jhi_user table 中。可以找到命名策略的文档 here.
对于你的第二个 liquibase changeSet * 20170913180000_drop_unique_constraint_email_JhiUser.xml* 我会建议你验证约束 jhi_user_email_key 是否存在。
这将使您可以使用电子邮件登录。仍然通过从域 class User 中删除 login 属性 你将需要重构一些 classes 来自生产和测试代码
在 JHipster 4.10.0 或更高版本上,感谢@duderoot,它是这样创建的:
<column name="email" type="varchar(100)">
<constraints unique="true" nullable="true" uniqueConstraintName="ux_user_email"/>
</column>
然后,您可以使用此名称删除此约束,而不会在任何环境中出现问题。
在 JHipster 4.8.0 上,"unique constraint" 是这样创建的:
<column name="email" type="varchar(100)">
<constraints unique="true" nullable="true"/>
</column>
他们不使用 "uniqueConstraintName" 并且约束的名称在每个数据库上都不同。
在 Postgresql(开发配置文件)上,"jhi_user_email_key" 存在,但在 H2(测试配置文件)上不存在。
要解决这个问题,您可以在 Initial Schema 上添加 uniqueConstraintName:
<column name="email" type="varchar(100)">
<constraints unique="true" nullable="true" uniqueConstraintName="jhi_user_email_key"/>
</column>
或者根据 "dbms" 先决条件制作不同的变更日志。