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: anchor after each write #167

Merged
merged 2 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions hermetic/src/cli/tester.rs
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,7 @@ fn job_init() -> Container {
Container {
name: "init-tests".to_owned(),
image: Some("stedolan/jq".to_owned()),
image_pull_policy: Some("IfNotPresent".to_owned()),
command: Some(vec![
"/bin/bash".to_owned(),
"-c".to_owned(),
Expand Down
2 changes: 1 addition & 1 deletion suite/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ RUN pnpm install
COPY src/ ./src

# Select all tests by default
ENV TEST_SELECTOR "correctness"
ENV TEST_SELECTOR="correctness"

ENTRYPOINT ["/app/entrypoint.sh", "run", "test", "--testPathPattern", "$TEST_SELECTOR"]
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ describe('Ceramic<->CAS basic integration', () => {

// Test document creation is anchored correctly
console.log('Waiting for anchor of genesis record')
await waitForAnchor(doc).catch((errStr) => {
throw new Error(errStr)
})
await waitForAnchor(doc)
expect(doc.state.log.length).toEqual(2)

// Test document update
Expand All @@ -50,9 +48,7 @@ describe('Ceramic<->CAS basic integration', () => {

// Test document update is anchored correctly
console.log('Waiting for anchor of update')
await waitForAnchor(doc).catch((errStr) => {
throw new Error(errStr)
})
await waitForAnchor(doc)
expect(doc.content).toEqual(newContent)
expect(doc.state.log.length).toEqual(4)
})
Expand All @@ -78,18 +74,10 @@ describe('Ceramic<->CAS basic integration', () => {

// Test document creation is anchored correctly
console.log('Waiting for anchor of genesis records')
await waitForAnchor(doc1).catch((errStr) => {
throw new Error(errStr)
})
await waitForAnchor(doc2).catch((errStr) => {
throw new Error(errStr)
})
await waitForAnchor(doc3).catch((errStr) => {
throw new Error(errStr)
})
await waitForAnchor(doc4).catch((errStr) => {
throw new Error(errStr)
})
await waitForAnchor(doc1)
await waitForAnchor(doc2)
await waitForAnchor(doc3)
await waitForAnchor(doc4)

expect(doc1.state.anchorStatus).toEqual(AnchorStatus.ANCHORED)
expect(doc1.state.log.length).toEqual(2)
Expand All @@ -101,20 +89,32 @@ describe('Ceramic<->CAS basic integration', () => {
expect(doc4.state.log.length).toEqual(2)

// Test document updates
// The anchor option is no longer honored when ceramic-one does the anchroing.
console.log('Updating documents')
await doc1.replace(content1, undefined, { anchor: true })
await doc2.replace(content1, undefined, { anchor: false })
await doc3.replace(content1, undefined, { anchor: false })
await doc4.replace(content1, undefined, { anchor: false })
await doc1.replace(content1, undefined)
Copy link
Collaborator

Choose a reason for hiding this comment

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

the second undefined arg can be removed now

await doc2.replace(content1, undefined)
await doc3.replace(content1, undefined)
await doc4.replace(content1, undefined)
await waitForAnchor(doc1)
Copy link
Collaborator

Choose a reason for hiding this comment

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

this is going to dramatically increase the time this test takes to run.

I think we should just do this one round where we update all 4 streams then wait for them to be anchored, and that's it. Remove all updates after this point, so that we still have only a single round of anchoring we are waiting on in this test.

We would then lose any integration test coverage that anchoring works when multiple consecutive writes are anchored by a single time event, but it sounds like we have no reliable way to introduce such a scenario anymore.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I started with that plan however this creates races the test cannot deal with. The current conflict resolution rules prefer branches that have the earlier time event. Its easy to get unanchored writes pruned in these tests because we anchor so quickly.

Basically what happens is that the test writes 4 events to a stream. If its right before an anchor batch then say only the first two writes get anchored. But the test didn't wait to see if the updates are anchored and so the last two writes are pruned and it causes the test to fail.

This is basically the race we already know exists but in these test envs the race window is large.

As discussed before the solution here is to change/update conflict resolution rules and make time events branches so that time events cannot prune valid data events. Until we have that fix we have to wait for anchors in the test case.

Copy link
Collaborator

Choose a reason for hiding this comment

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

sorry, my proposal was to do a single update to each stream and get them anchored. Not to do 4 updates in a row

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ok can do, I misunderstood. Keeping it simple works for me.

await waitForAnchor(doc2)
await waitForAnchor(doc3)
await waitForAnchor(doc4)

await doc2.replace(content2, undefined)
await doc3.replace(content2, undefined)
await doc4.replace(content2, undefined)
await waitForAnchor(doc2)
await waitForAnchor(doc3)
await waitForAnchor(doc4)

await doc3.replace(content3, undefined)
await doc4.replace(content3, undefined)
await waitForAnchor(doc3)
await waitForAnchor(doc4)

await doc4.replace(content4, undefined)
await waitForAnchor(doc4)

await doc2.replace(content2, undefined, { anchor: true })
await doc3.replace(content2, undefined, { anchor: false })
await doc4.replace(content2, undefined, { anchor: false })

await doc3.replace(content3, undefined, { anchor: true })
await doc4.replace(content3, undefined, { anchor: false })

await doc4.replace(content4, undefined, { anchor: true })

expect(doc1.content).toEqual(content1)
expect(doc2.content).toEqual(content2)
Expand All @@ -123,18 +123,6 @@ describe('Ceramic<->CAS basic integration', () => {

// Test document updates are anchored correctly
console.log('Waiting for anchor of updates')
Copy link
Collaborator

Choose a reason for hiding this comment

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

this log is no longer accurrate.

await waitForAnchor(doc1).catch((errStr) => {
throw new Error(errStr)
})
await waitForAnchor(doc2).catch((errStr) => {
throw new Error(errStr)
})
await waitForAnchor(doc3).catch((errStr) => {
throw new Error(errStr)
})
await waitForAnchor(doc4).catch((errStr) => {
throw new Error(errStr)
})

expect(doc1.state.anchorStatus).toEqual(AnchorStatus.ANCHORED)
expect(doc2.state.anchorStatus).toEqual(AnchorStatus.ANCHORED)
Expand All @@ -145,8 +133,8 @@ describe('Ceramic<->CAS basic integration', () => {
expect(doc3.content).toEqual(content3)
expect(doc4.content).toEqual(content4)
expect(doc1.state.log.length).toEqual(4)
expect(doc2.state.log.length).toEqual(5)
expect(doc3.state.log.length).toEqual(6)
expect(doc4.state.log.length).toEqual(7)
expect(doc2.state.log.length).toEqual(6)
expect(doc3.state.log.length).toEqual(8)
expect(doc4.state.log.length).toEqual(10)
})
})
Loading