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

Fix how the Migrations with custom state update are applied #1298

Merged
merged 30 commits into from
Sep 4, 2020

Conversation

dmitrykuzmin
Copy link
Contributor

@dmitrykuzmin dmitrykuzmin commented Sep 2, 2020

This PR fixes #1297.

The root cause of the bug is a discrepancy between entity and underlying transaction versions in Migration when updating the entity state.

This PR thus adds the missing setVersion(...) call.

It also applies some refactoring to the Migration class. Its current logic is confusing, with entity updates being propagated partially in-place, partially on transaction commit. This leads to strange code paths and observed values when debugging.

After the refactoring, all entity changes will be propagated on transaction commit at the very end of Migration.applyTo(...).

yuri-sergiichuk and others added 11 commits September 2, 2020 12:06
Also, refactor the code so the entity changes are transaction-based and propagated to the entity on transaction commit, instead of being applied in-place. This should make the migration logic as well as the values observed when debugging clearer.
Removing this workaround leads to heavily verbose setup for some of the test cases, to the point where it makes it harder to understand the original meaning of the test.

To address the problem, the concept of having `repository.create(ID)` which returns an invalid entity, which then cannot be loaded, should be revisited as a whole.
@dmitrykuzmin dmitrykuzmin self-assigned this Sep 2, 2020
@codecov
Copy link

codecov bot commented Sep 2, 2020

Codecov Report

Merging #1298 into master will increase coverage by 0.04%.
The diff coverage is 100.00%.

@@             Coverage Diff              @@
##             master    #1298      +/-   ##
============================================
+ Coverage     91.04%   91.08%   +0.04%     
- Complexity     4745     4747       +2     
============================================
  Files           608      608              
  Lines         15088    15091       +3     
  Branches        854      854              
============================================
+ Hits          13737    13746       +9     
+ Misses         1083     1080       -3     
+ Partials        268      265       -3     

@dmitrykuzmin
Copy link
Contributor Author

@armiol, @yuri-sergiichuk PTAL.

Copy link
Contributor

@yuri-sergiichuk yuri-sergiichuk left a comment

Choose a reason for hiding this comment

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

@dmitrykuzmin PTAL at the comments below.

@@ -238,6 +239,7 @@ private void warnOnNoSystemEventsPosted() {
private boolean physicallyRemoveRecord;

private final E entity;
private @MonotonicNonNull Transaction<I, E, S, ?> tx;
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you please reorder fields so that finals are grouped together?

Also, it looks like the tx should be marked as @LazyInit as well, right?

Comment on lines 685 to 686
assertThat(entityWithColumns.state()
.getIdString()).isEqualTo(id.toString());
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd actually compare state and not the ID only.

public final class SetTestProcessName
extends ProcessManagerMigration<ProjectId, TestProcessManager, Project, Project.Builder> {

public static final String NEW_NAME = "Migrated project";
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe Migrated process? You have Migrated projection in the projection migration below.

@@ -738,7 +815,8 @@ void deleteEntityViaMigration() {

Optional<TestProcessManager> found = repository().find(id);
assertThat(found.isPresent()).isTrue();
Copy link
Contributor

Choose a reason for hiding this comment

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

There's a whole set of Truth8 assertions that should allow having a bit nicer syntax for Optionals. Could you please check it out and consider using them instead?

@@ -238,6 +239,7 @@ private void warnOnNoSystemEventsPosted() {
private boolean physicallyRemoveRecord;
Copy link
Contributor

Choose a reason for hiding this comment

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

In the Operation docs it states that it's the operation done on an entity instance. In fact, we apply the migration to the tx().builder() now, right?

I guess it really worth adding some more details on how the migration operation is actually being done while you're in the context now.

@dmitrykuzmin
Copy link
Contributor Author

@yuri-sergiichuk PTAL again.

Copy link
Contributor

@yuri-sergiichuk yuri-sergiichuk left a comment

Choose a reason for hiding this comment

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

@dmitrykuzmin PTAL at the comments.

* <p>The operation is performed in scope of an active {@link Transaction}.
*
* <p>All entity state and meta-data changes are propagated to the transaction and remain in
* pending state until a transaction {@linkplain Transaction#commit() commit} which is the
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess it should be either a transaction is committed or a transaction commit is called

* {@linkplain Operation operation}.
* Applies the migration {@linkplain Operation operation} to a given entity.
*
* @see Operation Migration.Operation for details
Copy link
Contributor

Choose a reason for hiding this comment

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

This see section looks redundant. You have the very same link as for operation. I'd better remove it.

server/src/main/java/io/spine/server/entity/Migration.java Outdated Show resolved Hide resolved
@@ -71,15 +72,15 @@ void passNullToleranceCheck() {
void letPass() {
BusFilter<CommandEnvelope> filter = new BusFilters.Accepting();
Optional<Ack> ack = filter.filter(commandEnvelope);
assertThat(ack.isPresent()).isFalse();
Truth8.assertThat(ack).isEmpty();
Copy link
Contributor

Choose a reason for hiding this comment

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

Please import assertThat statically here and in the other places.

@@ -675,7 +754,8 @@ void updateColumns() {

// Check the column value is propagated to the entity state.
TestProcessManager entityWithColumns = afterMigration.next();
assertThat(entityWithColumns.state().getIdString()).isEqualTo(id.toString());
assertThat(entityWithColumns.state()
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we please have expected state here as well?

@@ -723,8 +803,9 @@ void archiveEntityViaMigration() {
repository().applyMigration(id, new MarkPmArchived<>());

Optional<TestProcessManager> found = repository().find(id);
assertThat(found.isPresent()).isTrue();
assertThat(found.get().isArchived()).isTrue();
Truth8.assertThat(found).isPresent();
Copy link
Contributor

Choose a reason for hiding this comment

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

Please use static imports.

@@ -773,6 +855,7 @@ private static TargetFilters targetFilters(QueryFilter first, QueryFilter... res
}

private static boolean hasId(TestProcessManager projection, ProjectId id) {
return projection.id().equals(id);
return projection.id()
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's flip the params. You'll then be able to have them on the same line.

Comment on lines 622 to 624
assertThat(results)
.comparingElementsUsing(idCorrespondence())
.containsExactly(id1, id2);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we test states here as well?

@@ -623,7 +699,7 @@ void archiveEntityViaMigration() {
repository().applyMigration(id, new MarkProjectionArchived<>());

Optional<TestProjection> found = repository().find(id);
assertThat(found.isPresent()).isTrue();
Truth8.assertThat(found).isPresent();
Copy link
Contributor

Choose a reason for hiding this comment

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

Please use static imports.

@dmitrykuzmin
Copy link
Contributor Author

@yuri-sergiichuk PTAL again.

assertThat(results).hasSize(2);
assertThat(results)
.comparingElementsUsing(stateWithPropagatedName())
.containsExactly(pm1, pm2);
Copy link
Contributor

Choose a reason for hiding this comment

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

So the migration does nothing? We're comparing the results to the same PMs we've manually stored.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, now I see that inside the correspondence we actually manually change the state of the PMs to match the actual one. It looks a bit too complicated...

Copy link
Contributor

@yuri-sergiichuk yuri-sergiichuk left a comment

Choose a reason for hiding this comment

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

@dmitrykuzmin in general LGTM.

I'd prefer to have a bit more straight-forward states comparison.

@dmitrykuzmin dmitrykuzmin merged commit 9d1f4cc into master Sep 4, 2020
@dmitrykuzmin dmitrykuzmin deleted the fix-migrations branch September 4, 2020 13:24
@dmitrykuzmin dmitrykuzmin mentioned this pull request Sep 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

The Migration result is not stored if it is equal to entityStateWithColumns
2 participants