-
Couldn't load subscription status.
- Fork 12
Fix how the Migrations with custom state update are applied
#1298
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
Conversation
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.
…into fix-migrations
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.
Codecov Report
@@ 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 |
|
@armiol, @yuri-sergiichuk PTAL. |
There was a problem hiding this 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.
| private boolean physicallyRemoveRecord; | ||
|
|
||
| private final E entity; | ||
| private @MonotonicNonNull Transaction<I, E, S, ?> tx; |
There was a problem hiding this comment.
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?
server/src/test/java/io/spine/server/procman/ProcessManagerRepositoryTest.java
Show resolved
Hide resolved
| assertThat(entityWithColumns.state() | ||
| .getIdString()).isEqualTo(id.toString()); |
There was a problem hiding this comment.
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.
server/src/test/java/io/spine/server/projection/given/SetTestProjectionName.java
Outdated
Show resolved
Hide resolved
server/src/test/java/io/spine/server/procman/given/repo/SetTestProcessName.java
Outdated
Show resolved
Hide resolved
| public final class SetTestProcessName | ||
| extends ProcessManagerMigration<ProjectId, TestProcessManager, Project, Project.Builder> { | ||
|
|
||
| public static final String NEW_NAME = "Migrated project"; |
There was a problem hiding this comment.
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.
| repository().applyMigration(id, new MarkPmDeleted<>()); | ||
|
|
||
| Optional<TestProcessManager> found = repository().find(id); | ||
| assertThat(found.isPresent()).isTrue(); |
There was a problem hiding this comment.
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?
|
|
||
| private boolean archive; | ||
| private boolean delete; | ||
| private boolean physicallyRemoveRecord; |
There was a problem hiding this comment.
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.
…SetTestProjectionName.java Co-authored-by: Yuri Sergiichuk <23313616+yuri-sergiichuk@users.noreply.github.com>
…o/SetTestProcessName.java Co-authored-by: Yuri Sergiichuk <23313616+yuri-sergiichuk@users.noreply.github.com>
…into fix-migrations
|
@yuri-sergiichuk PTAL again. |
There was a problem hiding this 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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
| BusFilter<CommandEnvelope> filter = new BusFilters.Accepting(); | ||
| Optional<Ack> ack = filter.filter(commandEnvelope); | ||
| assertThat(ack.isPresent()).isFalse(); | ||
| Truth8.assertThat(ack).isEmpty(); |
There was a problem hiding this comment.
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.
| // Check the column value is propagated to the entity state. | ||
| TestProcessManager entityWithColumns = afterMigration.next(); | ||
| assertThat(entityWithColumns.state().getIdString()).isEqualTo(id.toString()); | ||
| assertThat(entityWithColumns.state() |
There was a problem hiding this comment.
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?
| Optional<TestProcessManager> found = repository().find(id); | ||
| assertThat(found.isPresent()).isTrue(); | ||
| assertThat(found.get().isArchived()).isTrue(); | ||
| Truth8.assertThat(found).isPresent(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use static imports.
|
|
||
| private static boolean hasId(TestProcessManager projection, ProjectId id) { | ||
| return projection.id().equals(id); | ||
| return projection.id() |
There was a problem hiding this comment.
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.
| assertThat(results) | ||
| .comparingElementsUsing(idCorrespondence()) | ||
| .containsExactly(id1, id2); |
There was a problem hiding this comment.
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?
|
|
||
| Optional<TestProjection> found = repository().find(id); | ||
| assertThat(found.isPresent()).isTrue(); | ||
| Truth8.assertThat(found).isPresent(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use static imports.
…java Co-authored-by: Yuri Sergiichuk <23313616+yuri-sergiichuk@users.noreply.github.com>
# Conflicts: # server/src/main/java/io/spine/server/entity/Migration.java
|
@yuri-sergiichuk PTAL again. |
| assertThat(results).hasSize(2); | ||
| assertThat(results) | ||
| .comparingElementsUsing(stateWithPropagatedName()) | ||
| .containsExactly(pm1, pm2); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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...
There was a problem hiding this 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.
This PR fixes #1297.
The root cause of the bug is a discrepancy between entity and underlying transaction versions in
Migrationwhen updating the entity state.This PR thus adds the missing
setVersion(...)call.It also applies some refactoring to the
Migrationclass. 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(...).