Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support runWith executors committing after the change set completes #5329

Merged
merged 17 commits into from
Jan 22, 2024

Conversation

dzeigler
Copy link
Contributor

@dzeigler dzeigler commented Dec 7, 2023

Resolves #2696 by delegating Change execution to the executor's execute(Change, List) method

Impact

  • Bug fix (non-breaking change which fixes expected existing functionality)
  • Enhancement/New feature (adds functionality without impacting existing logic)
  • Breaking change (fix or feature that would cause existing functionality to change)

Description

AbstractJdbcDatabase delegates the execution of sqlstatements to executors. With this PR, AbstractJdbcDatabase delegates the execution of Changes to the executor too, which allows the executor more control over how Changes are executed. For example, a custom executor implementation that uses its own separate database connection can now have logic to commit after the last Change in a ChangeSet. Previously, the Executors had no access to the Change or ChangeSet and could not manage its transaction commits.

Things to be aware of

The change to AbstractExecutor brings its execute(Change change, List sqlVisitors) parity with execute(final SqlStatement[] statements, final List sqlVisitors).

Things to worry about

Additional Context

@dzeigler
Copy link
Contributor Author

Hi @filipelautert ,
Please let me know if you have any questions or feedback or need me to do anything else with this PR in order for the review to proceed.
Thanks!
David

@filipelautert
Copy link
Collaborator

Hello @dzeigler , thanks for the PR!
We will start to review it, but right now we are in the middle of build refactoring changes to the project that may slow down the review a bit.

@MalloD12
Copy link
Contributor

Hi @dzeigler,

I've been looking at your code changes and they look good to me. Something I was thinking it would be nice to have is another test scenario where we have a changeset with multiple changes, so we make sure after executing each of them executor triggers a commit and then we verify changes have been successfully deployed in the DB. This sounds to me more like an integration test than a unit test.

Can we do that?

Thanks,
Daniel.

@dzeigler
Copy link
Contributor Author

I agree. I thought about adding coverage for that scenario but wasn't sure if that was appropriate. I'll look at what's involved in adding the integration test and update accordingly sometime in the next few days.

@MalloD12
Copy link
Contributor

I agree. I thought about adding coverage for that scenario but wasn't sure if that was appropriate. I'll look at what's involved in adding the integration test and update accordingly sometime in the next few days.

Nice, thank you @dzeigler!

@dzeigler dzeigler force-pushed the master branch 2 times, most recently from 4837807 to 2fd1550 Compare December 18, 2023 12:14
@dzeigler
Copy link
Contributor Author

dzeigler commented Dec 18, 2023

@MalloD12 , please check my most recent commit. Its commit message explains the approach I took for the test. Let me know if anything needs to be adjusted.

…r's execute(Change, List<SqlVisitor>) method.

Delegating change execution to the executor allows the executor more control over how changes are executed. This change, for example, a custom executor implementation that uses its own separate database connection to commit changes after the last change in a changeset.
… execution

This commit adds the following
- An AlternateConnectionExecutor that extends JdbcExecutor and uses its
  own, separate JDBC connection to a test database (H2) and overrides
  the execute method to commit after each Change. The connection used by
  this executor is to H2 and uses an alternate schema by default.
- A test changelog whose change sets runwith the
  AlternateConnectionExecutor in order to create a table and then insert
  values into the table. The change intentionally fails in the final
  change of the last change set to help the test prove the preceding
  changes were committed.
- An integration test that executes the change log and asserts that the
  table was created in the alternate schema with the expected number of rows
  and that the table does not exist in the default database.
dzeigler and others added 4 commits December 21, 2023 00:53
… execution

This commit adds the following
- An AlternateConnectionExecutor that extends JdbcExecutor and uses its
  own, separate JDBC connection to a test database (H2) and overrides
  the execute method to commit after each Change. The connection used by
  this executor is to H2 and uses an alternate schema by default.
- A test changelog whose change sets runwith the
  AlternateConnectionExecutor in order to create a table and then insert
  values into the table. The change intentionally fails in the final
  change of the last change set to help the test prove the preceding
  changes were committed.
- An integration test that executes the change log and asserts that the
  table was created in the alternate schema with the expected number of rows
  and that the table does not exist in the default database.
- Moving the checks into the changelog removes the need for the test to
look up the executor
- Executors defined in liquibase-standard are picked up in Ubuntu
@dzeigler
Copy link
Contributor Author

@MalloD12 ,
I think the executor issue is resolved. It's working on windows and ubuntu now, at least in my local build. I had to move the executor definition to the META-INF/services/liquibase.executor.Executor file in the liquibase-standard project and I also eliminated the lookup in the test class itself.

I am running into different issues on this branch now when I build locally in ubuntu (fails on UpdateTestingRollbackCommandsIntegrationTest) and windows (fails in liquibase-cli). I don't see how what I changed affects those so I'm hoping it's just a local issue.
Let me know if you see any issues with the approach I took in the last commit.

@dzeigler
Copy link
Contributor Author

Hi @MalloD12, looks like all the tests passed and it's failing on a Run functional test step. When I click the details link, I get a 404 page so I don't think I have permissions to see. Is there anything I need to look into related to that failure?

@MalloD12
Copy link
Contributor

Hi @dzeigler,

Yeap, with your last change the test we were looking at started passing which is good. Now, yeah there is a functional test failing related to runWith for postgres. I'm not 100% it's related to this change but it could be. I would be able to check this with someone from the team next week (Tuesday) to understand whether this is related or not. I'll keep you posted.

2023-12-21T15:36:04.3899252Z [ERROR] Tests run: 563, Failures: 1, Errors: 0, Skipped: 14, Time elapsed: 4728 s <<< FAILURE! -- in TestSuite
2023-12-21T15:36:04.3901541Z [ERROR] tests.functional.update.UpdateRunWithPsqlTests.runWithPsqlAndKeepTempPathTest -- Time elapsed: 3.363 s <<< FAILURE!
2023-12-21T15:36:04.3910723Z org.assertj.core.api.SoftAssertionError: 
2023-12-21T15:36:04.3911495Z 
2023-12-21T15:36:04.3911873Z The following assertion failed:
2023-12-21T15:36:04.3912900Z 1) 'keep_temp_path/psql_log.log' file content does not contain 'CREATE VIEW'.
2023-12-21T15:36:04.3913744Z at TextFile.contains(TextFile.java:44)
2023-12-21T15:36:04.3914146Z 
2023-12-21T15:36:04.3914973Z 	at org.assertj.core.error.AssertionErrorCreator.multipleSoftAssertionsError(AssertionErrorCreator.java:100)
2023-12-21T15:36:04.3916574Z 	at org.assertj.core.api.AbstractSoftAssertions.assertAll(AbstractSoftAssertions.java:37)
2023-12-21T15:36:04.3918001Z 	at org.assertj.core.api.AbstractSoftAssertions.assertAll(AbstractSoftAssertions.java:42)
2023-12-21T15:36:04.3919352Z 	at utils.assertions.SoftAssert.check(SoftAssert.java:41)
2023-12-21T15:36:04.3920165Z 	at objects.file.TextFile.contains(TextFile.java:174)
2023-12-21T15:36:04.3921547Z 	at tests.functional.update.UpdateRunWithPsqlTests.runWithPsqlAndKeepTempPathTest(UpdateRunWithPsqlTests.java:178)
2023-12-21T15:36:04.3923161Z 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
2023-12-21T15:36:04.3924637Z 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
2023-12-21T15:36:04.3926284Z 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
2023-12-21T15:36:04.3927818Z 	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
2023-12-21T15:36:04.3929097Z 	at org.testng.internal.invokers.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:139)
2023-12-21T15:36:04.3930548Z 	at org.testng.internal.invokers.TestInvoker.invokeMethod(TestInvoker.java:664)
2023-12-21T15:36:04.3931804Z 	at org.testng.internal.invokers.TestInvoker.invokeTestMethod(TestInvoker.java:227)
2023-12-21T15:36:04.3933095Z 	at org.testng.internal.invokers.MethodRunner.runInSequence(MethodRunner.java:50)
2023-12-21T15:36:04.3934440Z 	at org.testng.internal.invokers.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:957)
2023-12-21T15:36:04.3935840Z 	at org.testng.internal.invokers.TestInvoker.invokeTestMethods(TestInvoker.java:200)
2023-12-21T15:36:04.3937255Z 	at org.testng.internal.invokers.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:148)
2023-12-21T15:36:04.3938621Z 	at org.testng.internal.invokers.TestMethodWorker.run(TestMethodWorker.java:128)
2023-12-21T15:36:04.3939704Z 	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
2023-12-21T15:36:04.3940576Z 	at org.testng.TestRunner.privateRun(TestRunner.java:848)
2023-12-21T15:36:04.3941360Z 	at org.testng.TestRunner.run(TestRunner.java:621)
2023-12-21T15:36:04.3964614Z 	at org.testng.SuiteRunner.runTest(SuiteRunner.java:443)
2023-12-21T15:36:04.3965620Z 	at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:437)
2023-12-21T15:36:04.3969094Z 	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:397)
2023-12-21T15:36:04.3970114Z 	at org.testng.SuiteRunner.run(SuiteRunner.java:336)
2023-12-21T15:36:04.3971023Z 	at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
2023-12-21T15:36:04.3972011Z 	at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:95)
2023-12-21T15:36:04.3972955Z 	at org.testng.TestNG.runSuitesSequentially(TestNG.java:1280)
2023-12-21T15:36:04.3973824Z 	at org.testng.TestNG.runSuitesLocally(TestNG.java:1200)
2023-12-21T15:36:04.3974609Z 	at org.testng.TestNG.runSuites(TestNG.java:1114)
2023-12-21T15:36:04.3975275Z 	at org.testng.TestNG.run(TestNG.java:1082)
2023-12-21T15:36:04.3976206Z 	at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:155)
2023-12-21T15:36:04.3977752Z 	at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.executeMulti(TestNGDirectoryTestSuite.java:169)
2023-12-21T15:36:04.3979481Z 	at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:88)
2023-12-21T15:36:04.3980990Z 	at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:137)
2023-12-21T15:36:04.3982454Z 	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385)
2023-12-21T15:36:04.3983831Z 	at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162)
2023-12-21T15:36:04.3985042Z 	at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507)
2023-12-21T15:36:04.3986230Z 	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495)

Thanks,
Daniel.


<changeSet id="3" author="your.name" runWith="h2alt">
<preConditions onFail="HALT">
<sqlCheck expectedResult="2">select count(*) from test_numbers where id in (1,2)</sqlCheck>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't be enough only one of these sqlCheck without filtering by id and expecting 2 results?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that'd be enough. I thought having the id there might make the test expectation more clear to someone reading, but you're right that checking the count is 2 would be a sufficient check.

final String changeLogFile = "changelogs/common/runWith.executor.changelog.xml";
try {
Liquibase liquibase = createLiquibase(changeLogFile);
liquibase.update();

Check notice

Code scanning / CodeQL

Deprecated method or constructor invocation Note

Invoking
Liquibase.update
should be avoided because it has been deprecated.
// Confirm the number of expected rows were inserted into the table in the alt schema by running the changelog again to get to the precondition checks
try {
Liquibase liquibase = createLiquibase(changeLogFile);
liquibase.update();

Check notice

Code scanning / CodeQL

Deprecated method or constructor invocation Note

Invoking
Liquibase.update
should be avoided because it has been deprecated.
Copy link
Contributor

@MalloD12 MalloD12 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved.

With latest changes made that we have been discussing last week and considering build and test checks have been successfully executed, I think this is ready to move forward.

Thanks @dzeigler for creating this PR and being very receptive with feedback provided here.

Daniel.

@dzeigler
Copy link
Contributor Author

Hi @MalloD12 ,
What should I expect in terms of next steps and including this change in a release?
Thanks!

@MalloD12
Copy link
Contributor

Hi @MalloD12 , What should I expect in terms of next steps and including this change in a release? Thanks!

Hi @dzeigler,

To be included in the next release this still needs to be reviewed/tested by QA team, so then we can merge it. I think that will happen soon.

We are expecting to have our next release end of this month or the beginning of February.

Thanks,
Daniel.

@filipelautert filipelautert added this to the 1NEXT milestone Jan 22, 2024
@filipelautert filipelautert changed the title Resolves #2696 by delegating Change execution to the executor's execute(Change, List<SqlVisitor>) method Support runWith executors committing after the change set completes Jan 22, 2024
@filipelautert filipelautert merged commit f0a0b09 into liquibase:master Jan 22, 2024
30 of 31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Support runWith executors committing after the change set completes
4 participants