@ibgib/core-gib 0.1.38 → 0.1.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/common/other/graph-helper.d.mts.map +1 -1
- package/dist/common/other/graph-helper.mjs +18 -3
- package/dist/common/other/graph-helper.mjs.map +1 -1
- package/dist/sync/graft-info/graft-info-helpers.mjs +1 -1
- package/dist/sync/graft-info/graft-info-helpers.mjs.map +1 -1
- package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs +321 -235
- package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs.map +1 -1
- package/dist/sync/sync-conflict-basic-multitimelines.respec.mjs +6 -6
- package/dist/sync/sync-conflict-basic-multitimelines.respec.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +1 -1
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
- package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
- package/dist/sync/sync-saga-coordinator.mjs +49 -12
- package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
- package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +4 -0
- package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -1
- package/dist/test-helpers.d.mts +104 -47
- package/dist/test-helpers.d.mts.map +1 -1
- package/dist/test-helpers.mjs +335 -131
- package/dist/test-helpers.mjs.map +1 -1
- package/dist/test-types.d.mts +25 -7
- package/dist/test-types.d.mts.map +1 -1
- package/dist/witness/space/reconciliation-space/reconciliation-space-helper.mjs +2 -2
- package/dist/witness/space/reconciliation-space/reconciliation-space-helper.mjs.map +1 -1
- package/package.json +1 -1
- package/src/common/other/graph-helper.mts +14 -2
- package/src/sync/SYNC_TESTING.md +135 -70
- package/src/sync/graft-info/graft-info-helpers.mts +1 -1
- package/src/sync/sync-conflict-adv-multitimelines.respec.mts +332 -245
- package/src/sync/sync-conflict-basic-multitimelines.respec.mts +5 -5
- package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +1 -1
- package/src/sync/sync-saga-coordinator.mts +58 -14
- package/src/sync/sync-saga-message/sync-saga-message-types.mts +4 -0
- package/src/test-helpers.mts +429 -152
- package/src/test-types.mts +30 -7
- package/src/witness/space/reconciliation-space/reconciliation-space-helper.mts +2 -2
- package/tmp.md +205 -1160
|
@@ -7,26 +7,24 @@
|
|
|
7
7
|
import { respecfully, iReckon, ifWeMight } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
|
|
8
8
|
const maam = `[${import.meta.url}]`, sir = maam;
|
|
9
9
|
import { clone, delay, extractErrorMsg, pretty } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
10
|
-
import {
|
|
10
|
+
import { GLOBAL_LOG_A_LOT } from '../core-constants.mjs';
|
|
11
|
+
import { TestTransformer, getTestKeystoneServiceHelper } from '../test-helpers.mjs';
|
|
11
12
|
import { SyncSagaCoordinator } from './sync-saga-coordinator.mjs';
|
|
12
13
|
import { getFromSpace } from '../witness/space/space-helper.mjs';
|
|
13
14
|
import { Metaspace_Innerspace } from '../witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mjs';
|
|
14
15
|
import { InnerSpace_V1 } from '../witness/space/inner-space/inner-space-v1.mjs';
|
|
15
|
-
import { createTimelineRootTestHelper, getTestKeystoneServiceHelper } from '../test-helpers.mjs';
|
|
16
|
-
import { appendToTimeline, mut8Timeline } from '../timeline/timeline-api.mjs';
|
|
17
16
|
import { SyncPeerInnerspace_V1 } from './sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs';
|
|
18
17
|
import { DEFAULT_INNER_SPACE_DATA_V1 } from '../witness/space/inner-space/inner-space-types.mjs';
|
|
19
|
-
import { getIbGibsFromCache_fallbackToSpaces, getTjpAddr } from '../common/other/ibgib-helper.mjs';
|
|
20
|
-
import { fnObs } from '../common/pubsub/observer/observer-helper.mjs';
|
|
18
|
+
import { getIbGibsFromCache_fallbackToSpaces, getTjpAddr, } from '../common/other/ibgib-helper.mjs';
|
|
21
19
|
import { getDependencyGraph, graphsAreEquivalent } from '../common/other/graph-helper.mjs';
|
|
22
20
|
import { SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1 } from './sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs';
|
|
23
21
|
import { SyncConflictStrategy } from './sync-constants.mjs';
|
|
24
|
-
import {
|
|
25
|
-
const logalot =
|
|
22
|
+
import { getHistory } from '../timeline/timeline-api.mjs';
|
|
23
|
+
const logalot = GLOBAL_LOG_A_LOT;
|
|
26
24
|
const lc = sir;
|
|
27
25
|
const TEST_REL8N_NAME = 'testrel8n';
|
|
28
|
-
await respecfully(sir, `
|
|
29
|
-
//
|
|
26
|
+
await respecfully(sir, `Multi-round/timeline permutations`, async () => {
|
|
27
|
+
// #region Init/Setup
|
|
30
28
|
const metaspace = new Metaspace_Innerspace(undefined);
|
|
31
29
|
await metaspace.initialize({
|
|
32
30
|
getFnAlert: () => async ({ title, msg }) => { console.log(`[Alert] ${title}: ${msg}`); },
|
|
@@ -52,287 +50,325 @@ await respecfully(sir, `Two different fields and rel8d`, async () => {
|
|
|
52
50
|
description: 'dest test space',
|
|
53
51
|
});
|
|
54
52
|
await destSpace.initialized;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
53
|
+
const testTransformer = new TestTransformer(metaspace, sourceSpace, destSpace);
|
|
54
|
+
if (logalot) {
|
|
55
|
+
console.log(`${lc} Setting up Coordinators...`);
|
|
56
|
+
}
|
|
57
|
+
const mockKeystone = await getTestKeystoneServiceHelper();
|
|
58
|
+
const senderCoordinator = new SyncSagaCoordinator(mockKeystone);
|
|
59
|
+
const receiverCoordinator = new SyncSagaCoordinator(mockKeystone);
|
|
60
|
+
async function newTestPeer() {
|
|
61
|
+
const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
|
|
62
|
+
await peer.initialized;
|
|
63
|
+
await peer.initializeSender({
|
|
64
|
+
senderSpace: sourceSpace,
|
|
65
|
+
receiverSpace: destSpace,
|
|
66
|
+
receiverCoordinator: receiverCoordinator,
|
|
67
|
+
receiverMetaspace: metaspace,
|
|
68
|
+
});
|
|
69
|
+
return peer;
|
|
70
|
+
}
|
|
71
|
+
// #endregion Init/Setup
|
|
72
|
+
// #region Round 1: Seed common history
|
|
66
73
|
/**
|
|
67
|
-
*
|
|
74
|
+
* not sure if we're going to do anything with the round info itself
|
|
68
75
|
*/
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
const _r1 = testTransformer.newRound({
|
|
77
|
+
name: 'r1_seedCommonHistory',
|
|
78
|
+
description: 'Create alpha v0 and v1 on source, sync to dest so both v0 and v1 are established as synced.',
|
|
79
|
+
});
|
|
80
|
+
// #region r1 setup
|
|
81
|
+
if (logalot) {
|
|
82
|
+
console.log(`${lc} Creating common History...`);
|
|
83
|
+
}
|
|
84
|
+
const r1_alpha_v0_source = await testTransformer.create({
|
|
85
|
+
atom: 'alpha',
|
|
86
|
+
in: 'source',
|
|
87
|
+
name: 'r1_alpha_v0_source', // should be auto-calculated?
|
|
88
|
+
});
|
|
89
|
+
// Create v1 (common) - will be synced to dest
|
|
90
|
+
const r1_alpha_v1_source_common = await testTransformer.mut8({
|
|
91
|
+
stepInfo: r1_alpha_v0_source,
|
|
92
|
+
strField: 'commonField',
|
|
93
|
+
name: 'r1_alpha_v1_source_common'
|
|
94
|
+
});
|
|
95
|
+
const alpha_tjpAddr = getTjpAddr({ ibGib: r1_alpha_v0_source.ibGib, defaultIfNone: 'incomingAddr' });
|
|
96
|
+
// #endregion r1 setup
|
|
97
|
+
await respecfully(sir, `r1 verify pre`, async () => {
|
|
98
|
+
await ifWeMight(sir, 'dest should NOT have alpha', async () => {
|
|
99
|
+
const resGet = await getFromSpace({
|
|
100
|
+
space: destSpace,
|
|
101
|
+
addr: alpha_tjpAddr,
|
|
102
|
+
});
|
|
103
|
+
// When timeline doesn't exist, getFromSpace returns success:false
|
|
104
|
+
iReckon(sir, resGet.success).asTo('getFromSpace should return false for missing timeline').isGonnaBeFalse();
|
|
105
|
+
iReckon(sir, resGet.ibGibs?.length ?? 0).asTo('Dest should NOT have alpha timeline yet').isGonnaBe(0);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
const r1_syncSaga = await senderCoordinator.sync({
|
|
109
|
+
peer: await newTestPeer(),
|
|
110
|
+
localSpace: sourceSpace,
|
|
75
111
|
metaspace,
|
|
76
|
-
|
|
112
|
+
domainIbGibs: [r1_alpha_v1_source_common.ibGib],
|
|
113
|
+
conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
|
|
114
|
+
useSessionIdentity: false,
|
|
77
115
|
});
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
// must get the entire dependency graph for alpha
|
|
82
|
-
const depGraph_alpha_v1Andcommon = await getDependencyGraph({
|
|
83
|
-
ibGibAddrs: [tjpAddr],
|
|
84
|
-
space: sourceSpace,
|
|
85
|
-
live: true,
|
|
86
|
-
}) ?? {};
|
|
87
|
-
console.log(`${lc} depGraph_testRootAndV1Common: ${pretty(depGraph_alpha_v1Andcommon)}`);
|
|
88
|
-
if (Object.keys(depGraph_alpha_v1Andcommon).length === 0) {
|
|
89
|
-
throw new Error(`(UNEXPECTED) depGraph_testRootAndV1Common empty? (E: 39b4d855ffa65476084b4123786da826)`);
|
|
116
|
+
await r1_syncSaga.done;
|
|
117
|
+
if (logalot) {
|
|
118
|
+
console.log(`${lc} r1_syncSaga Complete.`);
|
|
90
119
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
120
|
+
await respecfully(sir, `r1 verify post`, async () => {
|
|
121
|
+
await ifWeMight(sir, 'dest should have alpha', async () => {
|
|
122
|
+
// alpha's full dep graph should exist on dest
|
|
123
|
+
const [alpha_dest] = await getIbGibsFromCache_fallbackToSpaces({
|
|
124
|
+
addrs: [r1_alpha_v0_source.addr],
|
|
125
|
+
space: destSpace,
|
|
126
|
+
});
|
|
127
|
+
iReckon(sir, alpha_dest).asTo('alpha exists in dest').isGonnaBeTruthy();
|
|
128
|
+
if (alpha_dest) {
|
|
129
|
+
const depGraph_alpha_source = await getDependencyGraph({ ibGib: r1_alpha_v0_source.ibGib, space: sourceSpace });
|
|
130
|
+
const depGraph_alpha_dest = await getDependencyGraph({ ibGib: alpha_dest, space: destSpace });
|
|
131
|
+
const alphaDepsAreEqual = graphsAreEquivalent({
|
|
132
|
+
graphA: depGraph_alpha_source, graphB: depGraph_alpha_dest
|
|
133
|
+
});
|
|
134
|
+
iReckon(sir, alphaDepsAreEqual).asTo('alpha got synced and graphs are equal').isGonnaBeTrue();
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
// Get alpha_v1_common from destSpace for Round 2
|
|
139
|
+
const resGetDest = await getFromSpace({ space: destSpace, addr: alpha_tjpAddr });
|
|
94
140
|
if (!resGetDest.success || !resGetDest.ibGibs || resGetDest.ibGibs.length === 0) {
|
|
95
|
-
throw new Error(`Failed to retrieve
|
|
141
|
+
throw new Error(`Failed to retrieve alpha from destSpace after sync. (E: 40c67811eba14f729880a46dcbb65126)`);
|
|
96
142
|
}
|
|
97
|
-
/**
|
|
98
|
-
* same as v1_common
|
|
99
|
-
*/
|
|
100
143
|
const alpha_v1_common_onDest = resGetDest.ibGibs[0];
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
// syncing will obviously blur this line.
|
|
107
|
-
console.log(`${lc} Creating Divergence...`);
|
|
108
|
-
// #region edit on source
|
|
109
|
-
// Source: v1 (common) -> v2source (Edit Field A and rel8 beta)
|
|
110
|
-
const beta_v0_source = await createTimelineRootTestHelper({
|
|
111
|
-
ib: 'beta',
|
|
112
|
-
data: {
|
|
113
|
-
fieldA: 'beta field A created on source',
|
|
114
|
-
},
|
|
115
|
-
space: sourceSpace,
|
|
144
|
+
// #endregion Round 1: Seed common history
|
|
145
|
+
// #region Round 2: Create Divergence (v2source vs v2dest) - "simultaneous" parallel edits
|
|
146
|
+
const _r2 = testTransformer.newRound({
|
|
147
|
+
name: 'r2_divergent_edits',
|
|
148
|
+
description: 'Create conflicts on alpha, add beta relation on source, separate edit on dest'
|
|
116
149
|
});
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
150
|
+
// #region r2 source edits
|
|
151
|
+
if (logalot) {
|
|
152
|
+
console.log(`${lc} Creating Divergence...`);
|
|
153
|
+
}
|
|
154
|
+
// Source: Create beta, mutate alpha fieldA, add beta relation
|
|
155
|
+
const r2_beta_v0_source = await testTransformer.create({
|
|
156
|
+
atom: 'beta',
|
|
157
|
+
in: 'source',
|
|
158
|
+
data: { fieldA: 'beta field A created on source' },
|
|
159
|
+
name: 'r2_beta_v0_source'
|
|
126
160
|
});
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
],
|
|
161
|
+
const r2_alpha_v2_source_arbitraryMut8 = await testTransformer.mut8({
|
|
162
|
+
ibGib: r1_alpha_v1_source_common.ibGib,
|
|
163
|
+
in: 'source',
|
|
164
|
+
strField: 'fieldA',
|
|
165
|
+
name: 'r2_alpha_v2_source_arbitraryMut8',
|
|
166
|
+
comments_snake_plus_CamelCase: 'editedOnSource',
|
|
134
167
|
});
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
* timestamp/timestampMs drives orphan/base timeline selection in
|
|
142
|
-
* graftTimelines
|
|
143
|
-
*/
|
|
144
|
-
await delay(16);
|
|
145
|
-
// #region edit on dest
|
|
146
|
-
// Dest: v1 (common) -> alpha_v2_dest (Edit Field B)
|
|
147
|
-
const alpha_v2_dest = await mut8Timeline({
|
|
148
|
-
timeline: alpha_v1_common_onDest,
|
|
149
|
-
mut8Opts: {
|
|
150
|
-
mut8Ib: alpha_v0.ib + '_v2dest',
|
|
151
|
-
dataToAddOrPatch: { fieldB: 'dest_edit' }
|
|
152
|
-
},
|
|
153
|
-
metaspace,
|
|
154
|
-
space: destSpace,
|
|
168
|
+
const r2_alpha_v3_source_rel8dBeta = await testTransformer.rel8({
|
|
169
|
+
stepInfo: r2_alpha_v2_source_arbitraryMut8,
|
|
170
|
+
in: 'source',
|
|
171
|
+
targetIbGibs: [r2_beta_v0_source.ibGib],
|
|
172
|
+
rel8nName: TEST_REL8N_NAME,
|
|
173
|
+
name: 'r2_alpha_v3_source_rel8dBeta'
|
|
155
174
|
});
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const mockKeystone = await getTestKeystoneServiceHelper();
|
|
166
|
-
const senderCoordinator = new SyncSagaCoordinator(mockKeystone);
|
|
167
|
-
const receiverCoordinator = new SyncSagaCoordinator(mockKeystone);
|
|
168
|
-
const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
|
|
169
|
-
await peer.initialized;
|
|
170
|
-
await peer.initializeSender({
|
|
171
|
-
senderSpace: sourceSpace, // "Client"
|
|
172
|
-
receiverSpace: destSpace, // "Server"
|
|
173
|
-
receiverCoordinator,
|
|
174
|
-
receiverMetaspace: metaspace,
|
|
175
|
+
// #endregion r2 source edits
|
|
176
|
+
// #region r2 dest edits
|
|
177
|
+
// Dest: Mutate alpha fieldB (different field than source)
|
|
178
|
+
const r2_alpha_v2_dest_mut8FieldB = await testTransformer.mut8({
|
|
179
|
+
ibGib: alpha_v1_common_onDest,
|
|
180
|
+
in: 'dest',
|
|
181
|
+
strField: 'fieldB',
|
|
182
|
+
name: 'r2_alpha_v2_dest_mut8FieldB',
|
|
183
|
+
comments_snake_plus_CamelCase: 'editedOnDest',
|
|
175
184
|
});
|
|
185
|
+
if (logalot) {
|
|
186
|
+
console.log(`${lc} Divergence created.`);
|
|
187
|
+
}
|
|
188
|
+
// #endregion r2 dest edits
|
|
176
189
|
// Verify Receiver has correct KV (Pre-Sync Check)
|
|
177
190
|
// This ensures the conflict precondition exists.
|
|
178
|
-
await
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
+
await respecfully(sir, `r2 verify pre`, async () => {
|
|
192
|
+
await ifWeMight(sir, 'dest has alpha v1 common', async () => {
|
|
193
|
+
try {
|
|
194
|
+
const destKV = await receiverCoordinator.getKnowledgeMap({
|
|
195
|
+
space: destSpace,
|
|
196
|
+
metaspace,
|
|
197
|
+
domainIbGibs: [alpha_v1_common_onDest]
|
|
198
|
+
});
|
|
199
|
+
const alpha_v1_common_tjpAddr_onDest = getTjpAddr({ ibGib: alpha_v1_common_onDest, defaultIfNone: 'incomingAddr' });
|
|
200
|
+
const destTip = destKV[alpha_v1_common_tjpAddr_onDest];
|
|
201
|
+
iReckon(sir, !!destTip).asTo(`Dest KV has timeline tip for ${alpha_v1_common_tjpAddr_onDest}`).isGonnaBeTruthy();
|
|
202
|
+
if (!destTip) {
|
|
203
|
+
throw new Error(`Test Setup Fail: Dest Space does not have index for timeline ${alpha_v1_common_tjpAddr_onDest}. Seeding failed. (E: c194a80b4e4877b77826c37a1753b826)`);
|
|
204
|
+
}
|
|
191
205
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
208
|
+
iReckon(sir, true).asTo('getKnowledgeMap errored out').isGonnaBeFalse();
|
|
209
|
+
}
|
|
210
|
+
});
|
|
197
211
|
});
|
|
198
|
-
|
|
199
|
-
|
|
212
|
+
if (logalot) {
|
|
213
|
+
console.log(`${lc} Running Sync (ConflictStrategy: optimistic)...`);
|
|
214
|
+
}
|
|
215
|
+
let r2_syncSaga;
|
|
200
216
|
try {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
217
|
+
if (logalot) {
|
|
218
|
+
console.dir(sourceSpace);
|
|
219
|
+
}
|
|
220
|
+
if (logalot) {
|
|
221
|
+
console.dir(destSpace);
|
|
222
|
+
}
|
|
223
|
+
r2_syncSaga = await senderCoordinator.sync({
|
|
224
|
+
peer: await newTestPeer(),
|
|
205
225
|
localSpace: sourceSpace,
|
|
206
226
|
metaspace,
|
|
207
|
-
domainIbGibs: [
|
|
227
|
+
domainIbGibs: [r2_alpha_v3_source_rel8dBeta.ibGib],
|
|
208
228
|
conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
|
|
209
229
|
useSessionIdentity: false,
|
|
210
230
|
});
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
// console.log(`${sublc} next fired. ${JSON.stringify(ctxIbGib)}`);
|
|
219
|
-
console.log(`${sublc} next fired. (I: e68d8894bac8800f9f3430e8a38d6626)`);
|
|
220
|
-
},
|
|
221
|
-
error: async (e) => {
|
|
222
|
-
if (e.data) {
|
|
223
|
-
console.error(`${sublc} error fired. error: ${JSON.stringify(e.data)} (E: eddf17f76a486b9c5a2f4ee86ed38b26)`);
|
|
224
|
-
}
|
|
225
|
-
else {
|
|
226
|
-
console.dir(e);
|
|
227
|
-
console.error(`${sublc} error fired. error: ${extractErrorMsg(e)} (E: af9c3b6f1c88befeff77ca46111b3826)`);
|
|
228
|
-
}
|
|
229
|
-
},
|
|
230
|
-
complete: async () => {
|
|
231
|
-
console.log(`${sublc} complete fired`);
|
|
232
|
-
},
|
|
233
|
-
}));
|
|
234
|
-
console.log(`${lc} awaiting resSync.done`);
|
|
235
|
-
await resSync.done;
|
|
236
|
-
console.log(`${lc} Sync Complete.`);
|
|
231
|
+
if (logalot) {
|
|
232
|
+
console.log(`${lc} awaiting r2_syncSaga.done`);
|
|
233
|
+
}
|
|
234
|
+
await r2_syncSaga.done;
|
|
235
|
+
if (logalot) {
|
|
236
|
+
console.log(`${lc} r2_syncSaga Complete.`);
|
|
237
|
+
}
|
|
237
238
|
}
|
|
238
239
|
catch (e) {
|
|
239
240
|
console.error(`${lc} Sync Failed with Error:`, e);
|
|
240
241
|
iReckon(sir, false).asTo(`Sync failed with error: ${e}`).isGonnaBeTruthy();
|
|
241
242
|
return; // Exit test early
|
|
242
243
|
}
|
|
243
|
-
// 5. Verification
|
|
244
244
|
// Expectation: Both Spaces should now have a NEW tip (V3) that merges v2source and v2dest.
|
|
245
|
-
|
|
246
|
-
await respecfully(sir, `verify merge`, async () => {
|
|
245
|
+
await respecfully(sir, `r2 verify post`, async () => {
|
|
247
246
|
// Retrieve updated KV from Source (or check what happened to v2source)
|
|
248
247
|
// Ideally, we just check the source space for the timeline tip
|
|
249
248
|
// The timeline tip for alpha/v0 should now be NEW.
|
|
250
249
|
try {
|
|
251
250
|
// Get the KV for the Source Space
|
|
252
|
-
const
|
|
251
|
+
const alpha_sourceKV_afterSync = await senderCoordinator.getKnowledgeMap({
|
|
253
252
|
space: sourceSpace,
|
|
254
253
|
metaspace,
|
|
255
|
-
domainIbGibs: [
|
|
254
|
+
domainIbGibs: [r1_alpha_v0_source.ibGib] // We want to know the tip of this timeline
|
|
255
|
+
});
|
|
256
|
+
if (logalot) {
|
|
257
|
+
console.log(`${lc} getKnowledgeMap returned. sourceKV_afterSync: ${pretty(alpha_sourceKV_afterSync)} (I: e8780cda37c8b2a46eeb85786874e926)`);
|
|
258
|
+
}
|
|
259
|
+
const alpha_source_tipAddr = alpha_sourceKV_afterSync[alpha_tjpAddr];
|
|
260
|
+
if (logalot) {
|
|
261
|
+
console.log(`${lc} alpha_source_tipAddr: ${alpha_source_tipAddr} (I: 34590f29c9b706ba04a54b0f633a6426)`);
|
|
262
|
+
}
|
|
263
|
+
if (!alpha_source_tipAddr) {
|
|
264
|
+
throw new Error(`Source Space missing timeline tip for ${alpha_tjpAddr} (E: ec95980b9c980c5c5870812e15e43826)`);
|
|
265
|
+
}
|
|
266
|
+
const alpha_destKV_afterSync = await senderCoordinator.getKnowledgeMap({
|
|
267
|
+
space: destSpace,
|
|
268
|
+
metaspace,
|
|
269
|
+
domainIbGibs: [r1_alpha_v0_source.ibGib] // We want to know the tip of this timeline
|
|
256
270
|
});
|
|
257
|
-
const tjpAddr = getTjpAddr({ ibGib: alpha_v0, defaultIfNone: 'incomingAddr' }) ??
|
|
258
|
-
getIbGibAddr({ ibGib: alpha_v0 });
|
|
259
271
|
if (logalot) {
|
|
260
|
-
console.log(`${lc} getKnowledgeMap returned.
|
|
272
|
+
console.log(`${lc} getKnowledgeMap returned. destKV_afterSync: ${pretty(alpha_destKV_afterSync)} (I: e8780cda37c8b2a46eeb85786874e926)`);
|
|
273
|
+
}
|
|
274
|
+
const alpha_dest_tipAddr = alpha_destKV_afterSync[alpha_tjpAddr];
|
|
275
|
+
if (logalot) {
|
|
276
|
+
console.log(`${lc} alpha_dest_tipAddr: ${alpha_dest_tipAddr} (I: afac71eba4e6d3f3c47952680ad8b826)`);
|
|
261
277
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
throw new Error(`Source Space missing timeline tip for ${tjpAddr} (E: ec95980b9c980c5c5870812e15e43826)`);
|
|
278
|
+
if (!alpha_dest_tipAddr) {
|
|
279
|
+
throw new Error(`dest Space missing timeline tip for ${alpha_tjpAddr} (E: 30b018c6349917aa28c9f538fa567826)`);
|
|
265
280
|
}
|
|
281
|
+
await ifWeMight(sir, 'tip addrs', async () => {
|
|
282
|
+
iReckon(sir, alpha_source_tipAddr).asTo('source/dest have same tip addrs').isGonnaBe(alpha_dest_tipAddr);
|
|
283
|
+
});
|
|
266
284
|
// Fetch the new tip
|
|
267
|
-
const
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
285
|
+
const resGet_alpha_source_tipAddr = await getFromSpace({ space: sourceSpace, addr: alpha_source_tipAddr });
|
|
286
|
+
const gotten_alpha_source_tipIbGib = resGet_alpha_source_tipAddr.ibGibs[0];
|
|
287
|
+
if (logalot || true) {
|
|
288
|
+
console.log(`${lc} gotten_alpha_source_tipIbGib:\n${pretty(gotten_alpha_source_tipIbGib)} (I: e9c608c1fcb85f08d17d4af319d62726)`);
|
|
289
|
+
}
|
|
290
|
+
// #region DEBUG SANITY CHECK
|
|
291
|
+
const resGetTjp = await getFromSpace({ space: sourceSpace, addr: alpha_tjpAddr });
|
|
292
|
+
const gottenTjp = resGetTjp.ibGibs[0];
|
|
293
|
+
debugger;
|
|
294
|
+
const history = await getHistory({
|
|
295
|
+
timeline: gotten_alpha_source_tipIbGib,
|
|
296
|
+
space: sourceSpace,
|
|
297
|
+
metaspace,
|
|
298
|
+
includeDna: true,
|
|
275
299
|
});
|
|
276
|
-
|
|
277
|
-
//
|
|
278
|
-
await ifWeMight(sir, '
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const orphanRel = graftInfo.rel8ns[GRAFT_ORPHAN_REL8N_NAME];
|
|
297
|
-
iReckon(sir, baseRel).asTo('Graft Base exists').isGonnaBeTruthy();
|
|
298
|
-
iReckon(sir, baseRel.length).asTo('Graft Base length is 2').isGonnaBe(2);
|
|
299
|
-
iReckon(sir, orphanRel).asTo('Graft Orphan exists').isGonnaBeTruthy();
|
|
300
|
-
iReckon(sir, orphanRel.length).asTo('Graft Orphan length is 1').isGonnaBe(1);
|
|
301
|
-
iReckon(sir, baseRel.at(-1)).asTo('base rel8ns final addr will be baseAddr').isGonnaBe(baseAddr);
|
|
302
|
-
iReckon(sir, orphanRel[0]).asTo('orphan rel8ns will be later addr').isGonnaBe(orphanAddr);
|
|
300
|
+
debugger;
|
|
301
|
+
// #endregion DEBUG SANITY CHECK
|
|
302
|
+
await ifWeMight(sir, 'r2 basics of alpha merge', async () => {
|
|
303
|
+
iReckon(sir, alpha_source_tipAddr)
|
|
304
|
+
.asTo(`Source Tip (${alpha_source_tipAddr}) should NOT be r2_alpha_v3_source_rel8dBeta`)
|
|
305
|
+
.not.isGonnaBe(r2_alpha_v3_source_rel8dBeta.addr);
|
|
306
|
+
iReckon(sir, alpha_source_tipAddr)
|
|
307
|
+
.asTo(`Source Tip (${alpha_source_tipAddr}) should NOT be r2_alpha_v2_dest_mut8FieldB`)
|
|
308
|
+
.not.isGonnaBe(r2_alpha_v2_dest_mut8FieldB.addr);
|
|
309
|
+
// Check Data: Should have BOTH edits (using testTransformer-generated values)
|
|
310
|
+
const r2_source_mut8Info = r2_alpha_v2_source_arbitraryMut8.infos[0];
|
|
311
|
+
const r2_dest_mut8Info = r2_alpha_v2_dest_mut8FieldB.infos[0];
|
|
312
|
+
const a = gotten_alpha_source_tipIbGib.data[r2_source_mut8Info.key];
|
|
313
|
+
const a2 = r2_source_mut8Info.value;
|
|
314
|
+
console.log(`${a} should be ${a2}`);
|
|
315
|
+
iReckon(sir, gotten_alpha_source_tipIbGib.data[r2_source_mut8Info.key]).asTo(`New Tip has source field ${r2_source_mut8Info.key}`).isGonnaBe(r2_source_mut8Info.value);
|
|
316
|
+
const b = gotten_alpha_source_tipIbGib.data[r2_dest_mut8Info.key];
|
|
317
|
+
const b2 = r2_dest_mut8Info.value;
|
|
318
|
+
console.log(`${b} should be ${b2}`);
|
|
319
|
+
iReckon(sir, gotten_alpha_source_tipIbGib.data[r2_dest_mut8Info.key]).asTo(`New Tip has dest field ${r2_dest_mut8Info.key}`).isGonnaBe(r2_dest_mut8Info.value);
|
|
303
320
|
});
|
|
304
|
-
await ifWeMight(sir, 'alpha and deps synced', async () => {
|
|
305
|
-
// alpha's full dep graph should exist on dest
|
|
306
|
-
|
|
307
|
-
|
|
321
|
+
await ifWeMight(sir, 'r2 alpha and deps synced', async () => {
|
|
322
|
+
// alpha's full dep graph should exist on dest, even though its
|
|
323
|
+
// timeline was grafted
|
|
324
|
+
const [alpha_dest] = await getIbGibsFromCache_fallbackToSpaces({
|
|
325
|
+
addrs: [r1_alpha_v0_source.addr],
|
|
308
326
|
space: destSpace,
|
|
309
327
|
});
|
|
310
|
-
iReckon(sir,
|
|
311
|
-
if (
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
328
|
+
iReckon(sir, alpha_dest).asTo('alpha exists in dest').isGonnaBeTruthy();
|
|
329
|
+
if (alpha_dest) {
|
|
330
|
+
try {
|
|
331
|
+
const depGraph_alpha_source = await getDependencyGraph({
|
|
332
|
+
ibGib: r1_alpha_v0_source.ibGib,
|
|
333
|
+
live: true,
|
|
334
|
+
space: sourceSpace
|
|
335
|
+
});
|
|
336
|
+
const depGraph_alpha_dest = await getDependencyGraph({
|
|
337
|
+
ibGib: alpha_dest,
|
|
338
|
+
live: true,
|
|
339
|
+
space: destSpace
|
|
340
|
+
});
|
|
341
|
+
const alphaDepsAreEqual = graphsAreEquivalent({
|
|
342
|
+
graphA: depGraph_alpha_source,
|
|
343
|
+
graphB: depGraph_alpha_dest,
|
|
344
|
+
slowButThorough: true,
|
|
345
|
+
});
|
|
346
|
+
iReckon(sir, alphaDepsAreEqual).asTo('alpha got synced and graphs are equal').isGonnaBeTrue();
|
|
347
|
+
}
|
|
348
|
+
catch (error) {
|
|
349
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
350
|
+
iReckon(sir, true).asTo('ERROR: alpha exists in dest').isGonnaBeFalse(); // fails
|
|
315
351
|
}
|
|
316
|
-
const depGraph_beta_dest = await getDependencyGraph({ ibGib: beta_dest, space: destSpace });
|
|
317
|
-
const betaDepsAreEqual = graphsAreEquivalent({
|
|
318
|
-
graphA: depGraph_beta_source, graphB: depGraph_beta_dest
|
|
319
|
-
});
|
|
320
|
-
iReckon(sir, betaDepsAreEqual).asTo('beta got synced and graphs are equal').isGonnaBeTrue();
|
|
321
352
|
}
|
|
322
353
|
});
|
|
323
|
-
await ifWeMight(sir, 'beta and deps synced', async () => {
|
|
354
|
+
await ifWeMight(sir, 'r2 beta and deps synced', async () => {
|
|
324
355
|
// beta's full dep graph should exist on dest
|
|
325
356
|
const [beta_dest] = await getIbGibsFromCache_fallbackToSpaces({
|
|
326
|
-
addrs: [
|
|
357
|
+
addrs: [r2_beta_v0_source.addr],
|
|
327
358
|
space: destSpace,
|
|
328
359
|
});
|
|
329
360
|
iReckon(sir, beta_dest).asTo('beta exists in dest').isGonnaBeTruthy();
|
|
330
361
|
if (beta_dest) {
|
|
331
|
-
const depGraph_beta_source = await getDependencyGraph({
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
362
|
+
const depGraph_beta_source = await getDependencyGraph({
|
|
363
|
+
ibGib: r2_beta_v0_source.ibGib,
|
|
364
|
+
live: true,
|
|
365
|
+
space: sourceSpace
|
|
366
|
+
});
|
|
367
|
+
const depGraph_beta_dest = await getDependencyGraph({
|
|
368
|
+
ibGib: beta_dest,
|
|
369
|
+
live: true,
|
|
370
|
+
space: destSpace
|
|
371
|
+
});
|
|
336
372
|
const betaDepsAreEqual = graphsAreEquivalent({
|
|
337
373
|
graphA: depGraph_beta_source,
|
|
338
374
|
graphB: depGraph_beta_dest,
|
|
@@ -347,5 +383,55 @@ await respecfully(sir, `Two different fields and rel8d`, async () => {
|
|
|
347
383
|
iReckon(sir, true).asTo('getKnowledgeMap errored out').isGonnaBeFalse();
|
|
348
384
|
}
|
|
349
385
|
});
|
|
386
|
+
// #endregion Round 2: Create Divergence (v2source vs v2dest) - "simultaneous" parallel edits
|
|
387
|
+
// #region Round 3: Multiple Timeline Conflicts
|
|
388
|
+
const _r3 = testTransformer.newRound({
|
|
389
|
+
name: 'r3_multiple_timeline_conflicts',
|
|
390
|
+
description: 'Both alpha AND beta have divergent edits on source vs dest - tests multiple simultaneous grafts'
|
|
391
|
+
});
|
|
392
|
+
// #region r3 source edits
|
|
393
|
+
if (logalot) {
|
|
394
|
+
console.log(`${lc} Creating r3 divergent edits on source...`);
|
|
395
|
+
}
|
|
396
|
+
// Source: Mutate alpha fieldC, mutate beta betaFieldA
|
|
397
|
+
// TODO: Add source edits here
|
|
398
|
+
// #endregion r3 source edits
|
|
399
|
+
// #region r3 dest edits
|
|
400
|
+
if (logalot) {
|
|
401
|
+
console.log(`${lc} Creating r3 divergent edits on dest...`);
|
|
402
|
+
}
|
|
403
|
+
// Dest: Mutate alpha fieldD, mutate beta betaFieldB
|
|
404
|
+
// TODO: Add dest edits here
|
|
405
|
+
// #endregion r3 dest edits
|
|
406
|
+
await respecfully(sir, `r3 verify pre`, async () => {
|
|
407
|
+
// TODO: Verify pre-sync state
|
|
408
|
+
await ifWeMight(sir, 'source has divergent alpha and beta', async () => {
|
|
409
|
+
// Verify source has its versions
|
|
410
|
+
});
|
|
411
|
+
await ifWeMight(sir, 'dest has divergent alpha and beta', async () => {
|
|
412
|
+
// Verify dest has its versions
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
if (logalot) {
|
|
416
|
+
console.log(`${lc} Running r3 Sync...`);
|
|
417
|
+
}
|
|
418
|
+
// TODO: Add sync operation here
|
|
419
|
+
// const r3_syncSaga = await senderCoordinator.sync({...});
|
|
420
|
+
await respecfully(sir, `r3 verify post`, async () => {
|
|
421
|
+
// TODO: Verify post-sync state
|
|
422
|
+
await ifWeMight(sir, 'r3 alpha merge has both edits', async () => {
|
|
423
|
+
// Verify alpha has fieldC (source) AND fieldD (dest)
|
|
424
|
+
});
|
|
425
|
+
await ifWeMight(sir, 'r3 beta merge has both edits', async () => {
|
|
426
|
+
// Verify beta has betaFieldA (source) AND betaFieldB (dest)
|
|
427
|
+
});
|
|
428
|
+
await ifWeMight(sir, 'r3 alpha and deps synced', async () => {
|
|
429
|
+
// Verify alpha's full dep graph on both spaces
|
|
430
|
+
});
|
|
431
|
+
await ifWeMight(sir, 'r3 beta and deps synced', async () => {
|
|
432
|
+
// Verify beta's full dep graph on both spaces
|
|
433
|
+
});
|
|
434
|
+
});
|
|
435
|
+
// #endregion Round 3: Multiple Timeline Conflicts
|
|
350
436
|
});
|
|
351
437
|
//# sourceMappingURL=sync-conflict-adv-multitimelines.respec.mjs.map
|