Skip to content

Commit

Permalink
add more comments and explanation to tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ktuite committed Oct 28, 2024
1 parent f4d54fc commit 9dd9db0
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 6 deletions.
3 changes: 1 addition & 2 deletions lib/model/query/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,14 +304,13 @@ const _updateEntity = (dataset, entityData, submissionId, submissionDef, submiss
serverDiffData.label = serverEntity.aux.currentVersion.label;

conflictingProperties = Object.keys(clientEntity.def.dataReceived).filter(key => key in serverDiffData && clientEntity.def.dataReceived[key] !== serverDiffData[key]);

if (conflict !== ConflictType.HARD) { // We don't want to downgrade conflict here
conflict = conflictingProperties.length > 0 ? ConflictType.HARD : ConflictType.SOFT;
}
} else {
// This may still be a soft conflict if the new version is not contiguous with this branch's trunk version
const interrupted = await Entities._interruptedBranch(serverEntity.id, clientEntity);
if (interrupted) {
if (interrupted && conflict !== ConflictType.HARD) {
conflict = ConflictType.SOFT;
}
}
Expand Down
54 changes: 50 additions & 4 deletions test/integration/api/offline-entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -1353,15 +1353,20 @@ describe('Offline Entities', () => {
.send({ data: { age: '24' } })
.expect(200);

// Send update (change status from null to arrived)
// Send update (change status from null to arrived, no other properties included/changed)
// Introduces a soft conflict because baseVersion is 1
// But no hard conflict
await asAlice.post('/v1/projects/1/forms/offlineEntity/submissions')
.send(testData.instances.offlineEntity.one
.replace('branchId=""', `branchId="${branchId}"`)
)
.set('Content-Type', 'application/xml')
.expect(200);

// Send second update (change age from 22 to 26)
// Send second update (change age from 22 to 26, instead of changing status)
// Doesn't conflict with previous version (from the same offline branch)
// But it should be marked as a soft conflict because the branch was
// interrupted by the first API update.
await asAlice.post('/v1/projects/1/forms/offlineEntity/submissions')
.send(testData.instances.offlineEntity.one
.replace('branchId=""', `branchId="${branchId}"`)
Expand All @@ -1374,16 +1379,26 @@ describe('Offline Entities', () => {

await exhaust(container);

// Final version should have soft conflict
await asAlice.get('/v1/projects/1/datasets/people/entities/12345678-1234-4123-8234-123456789abc/versions')
.then(({ body: versions }) => {
versions.map(v => v.conflict).should.eql([null, null, 'soft', 'soft']);
});

// Overall entity should have soft conflict
// (A test below shows this is set explicitily and not just carried over
// from the previous conflict state.)
await asAlice.get('/v1/projects/1/datasets/people/entities/12345678-1234-4123-8234-123456789abc')
.then(({ body: entity }) => {
should(entity.conflict).equal('soft');
});
}));

it('should mark an update that is not contiguous (due to force processing) as a soft conflict', testOfflineEntities(async (service, container) => {
const asAlice = await service.login('alice');
const branchId = uuid();

// Scenario described in issue: c#698
// Send second update first
await asAlice.post('/v1/projects/1/forms/offlineEntity/submissions')
.send(testData.instances.offlineEntity.one
Expand All @@ -1399,6 +1414,9 @@ describe('Offline Entities', () => {
await container.Entities.processBacklog(true);

// Send first update now (it will be applied right away)
// Introduces a hard conflict because it will find baseVersion v1
// and the force-processed update above also branched of v1
// and both update 'status'.
await asAlice.post('/v1/projects/1/forms/offlineEntity/submissions')
.send(testData.instances.offlineEntity.one
.replace('branchId=""', `branchId="${branchId}"`)
Expand All @@ -1408,7 +1426,13 @@ describe('Offline Entities', () => {

await exhaust(container);

// Send fourth update
// Entity conflict should be hard at this point
await asAlice.get('/v1/projects/1/datasets/people/entities/12345678-1234-4123-8234-123456789abc')
.then(({ body: entity }) => {
should(entity.conflict).equal('hard');
});

// Send fourth update (skipping a 3rd update so this must be force-applied)
await asAlice.post('/v1/projects/1/forms/offlineEntity/submissions')
.send(testData.instances.offlineEntity.one
.replace('branchId=""', `branchId="${branchId}"`)
Expand All @@ -1422,10 +1446,19 @@ describe('Offline Entities', () => {
await exhaust(container);
await container.Entities.processBacklog(true);

// All updates are from the same branch, but 1 expected version is missing
// and updates came in out of order. Unclear if final 'soft' conflict is what we
// want or if it should possibly be null.
await asAlice.get('/v1/projects/1/datasets/people/entities/12345678-1234-4123-8234-123456789abc/versions')
.then(({ body: versions }) => {
versions.map(v => v.conflict).should.eql([null, null, 'hard', 'soft']);
});

// Hard conflict is carried forward
await asAlice.get('/v1/projects/1/datasets/people/entities/12345678-1234-4123-8234-123456789abc')
.then(({ body: entity }) => {
should(entity.conflict).equal('hard');
});
}));

it('should mark an update that is not contiguous with its trunk version as a soft conflict on entity despite earlier conflict resolution', testOfflineEntities(async (service, container) => {
Expand All @@ -1437,7 +1470,9 @@ describe('Offline Entities', () => {
.send({ data: { age: '24' } })
.expect(200);

// Send update (change status from null to arrived)
// Send update (change status from null to arrived, don't change age)
// Has soft conflict with parallel update but doesn't have hard conflict
// because different properties were changed.
await asAlice.post('/v1/projects/1/forms/offlineEntity/submissions')
.send(testData.instances.offlineEntity.one
.replace('branchId=""', `branchId="${branchId}"`)
Expand All @@ -1446,10 +1481,19 @@ describe('Offline Entities', () => {
.expect(200);
await exhaust(container);

// Entity has soft conflict at this point
await asAlice.get('/v1/projects/1/datasets/people/entities/12345678-1234-4123-8234-123456789abc')
.then(({ body: entity }) => {
should(entity.conflict).equal('soft');
});

await asAlice.patch('/v1/projects/1/datasets/people/entities/12345678-1234-4123-8234-123456789abc?resolve=true&baseVersion=3')
.expect(200);

// Send second update (change age from 22 to 26)
// Doesn't conflict with previous version (from the same offline branch)
// But it should be marked as a soft conflict because the branch was
// interrupted by the first API update.
await asAlice.post('/v1/projects/1/forms/offlineEntity/submissions')
.send(testData.instances.offlineEntity.one
.replace('branchId=""', `branchId="${branchId}"`)
Expand All @@ -1461,11 +1505,13 @@ describe('Offline Entities', () => {
.expect(200);
await exhaust(container);

// Final version conflict is soft because of interrupted branch
await asAlice.get('/v1/projects/1/datasets/people/entities/12345678-1234-4123-8234-123456789abc/versions')
.then(({ body: versions }) => {
versions.map(v => v.conflict).should.eql([null, null, 'soft', 'soft']);
});

// Entity version is soft
await asAlice.get('/v1/projects/1/datasets/people/entities/12345678-1234-4123-8234-123456789abc')
.then(({ body: entity }) => {
should(entity.conflict).equal('soft');
Expand Down

0 comments on commit 9dd9db0

Please sign in to comment.