@boxxy/dispatch 0.1.1 → 0.1.3
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/attempts/attempt-machine.d.ts +804 -0
- package/dist/attempts/attempt-moves.d.ts +2 -0
- package/dist/attempts/bind-attempt-session.d.ts +14 -0
- package/dist/attempts/build-attempt-change.d.ts +73 -0
- package/dist/attempts/build-attempt-fact.d.ts +3 -0
- package/dist/attempts/end-item-attempts.d.ts +18 -0
- package/dist/attempts/is-same-guard.d.ts +5 -0
- package/dist/attempts/pick-call-attempt.d.ts +10 -0
- package/dist/attempts/stop-stray-session.d.ts +11 -0
- package/dist/attempts/types.d.ts +142 -0
- package/dist/attempts/write-attempt-move.d.ts +7 -0
- package/dist/attempts/write-session-bind.d.ts +3 -0
- package/dist/claims/build-snapshot-hash.d.ts +2 -0
- package/dist/claims/claim-next.d.ts +6 -0
- package/dist/claims/pick-kept-session.d.ts +9 -0
- package/dist/claims/request-wake.d.ts +3 -0
- package/dist/claims/resume-claim.d.ts +3 -0
- package/dist/claims/start-claim.d.ts +3 -0
- package/dist/claims/types.d.ts +44 -0
- package/dist/closeouts/build-settle-plans.d.ts +17 -0
- package/dist/closeouts/close-out-attempt.d.ts +3 -0
- package/dist/closeouts/effect-handlers.d.ts +2 -0
- package/dist/closeouts/pick-settlement.d.ts +14 -0
- package/dist/closeouts/settle-attempt.d.ts +3 -0
- package/dist/closeouts/types.d.ts +50 -0
- package/dist/index.d.ts +38 -0
- package/dist/notices/constants.d.ts +4 -0
- package/dist/notices/create-null-notifier.d.ts +2 -0
- package/dist/notices/send-notices.d.ts +2 -0
- package/dist/notices/types.d.ts +11 -0
- package/dist/outbox/build-backoff-ms.d.ts +2 -0
- package/dist/outbox/build-initial-sender-state.d.ts +2 -0
- package/dist/outbox/build-outbox-status.d.ts +15 -0
- package/dist/outbox/constants.d.ts +2 -0
- package/dist/outbox/measure-wire-bytes.d.ts +2 -0
- package/dist/outbox/pick-sender-move.d.ts +10 -0
- package/dist/outbox/run-sender-once.d.ts +2 -0
- package/dist/outbox/take-batch.d.ts +3 -0
- package/dist/outbox/types.d.ts +61 -0
- package/dist/pull-requests/build-link-change.d.ts +11 -0
- package/dist/pull-requests/build-state-fact.d.ts +8 -0
- package/dist/pull-requests/collect-attempt-trailers.d.ts +2 -0
- package/dist/pull-requests/collect-seen-state.d.ts +7 -0
- package/dist/pull-requests/constants.d.ts +3 -0
- package/dist/pull-requests/link-pull-request.d.ts +2 -0
- package/dist/pull-requests/parse-pull-request-url.d.ts +2 -0
- package/dist/pull-requests/types.d.ts +37 -0
- package/dist/pull-requests/watch-pull-requests.d.ts +2 -0
- package/dist/readings/act-on-reading.d.ts +3 -0
- package/dist/readings/find-waiting-since.d.ts +9 -0
- package/dist/readings/pick-reading-action.d.ts +2 -0
- package/dist/readings/types.d.ts +79 -0
- package/dist/sessions/build-keep-writes.d.ts +9 -0
- package/dist/sessions/build-kept-clear.d.ts +2 -0
- package/dist/sessions/forget-sessions.d.ts +2 -0
- package/dist/sessions/is-kept-due.d.ts +2 -0
- package/dist/sessions/resume-kept-session.d.ts +6 -0
- package/dist/sessions/types.d.ts +19 -0
- package/dist/test-utils/apply-memory-change.d.ts +3 -0
- package/dist/test-utils/build-memory-reader.d.ts +3 -0
- package/dist/test-utils/build-mock-claim-change.d.ts +2 -2
- package/dist/test-utils/build-mock-new-id.d.ts +2 -0
- package/dist/test-utils/build-mock-note-change.d.ts +2 -0
- package/dist/test-utils/build-mock-pull-request-change.d.ts +1 -0
- package/dist/test-utils/{build-mock-link-change.d.ts → build-mock-relation-change.d.ts} +2 -2
- package/dist/test-utils/build-mock-running-reading.d.ts +6 -0
- package/dist/test-utils/build-mock-start-change.d.ts +2 -2
- package/dist/test-utils/claim-store-close-cases.d.ts +2 -0
- package/dist/test-utils/claim-store-copy-cases.d.ts +2 -0
- package/dist/test-utils/claim-store-outbox-cases.d.ts +2 -0
- package/dist/test-utils/claim-store-race-cases.d.ts +2 -0
- package/dist/test-utils/claim-store-seat-cases.d.ts +2 -0
- package/dist/test-utils/claim-store-session-cases.d.ts +2 -0
- package/dist/test-utils/collect-memory-limit-fills.d.ts +3 -0
- package/dist/test-utils/compare-text.d.ts +1 -0
- package/dist/test-utils/create-fake-backoff.d.ts +2 -0
- package/dist/test-utils/create-fake-clock.d.ts +5 -0
- package/dist/test-utils/create-fake-fact-sink.d.ts +8 -0
- package/dist/test-utils/create-fake-forge.d.ts +17 -0
- package/dist/test-utils/create-fake-worker.d.ts +42 -0
- package/dist/test-utils/create-memory-claim-store.d.ts +2 -2
- package/dist/test-utils/create-test-dispatch.d.ts +46 -0
- package/dist/test-utils/forge-contract.d.ts +15 -0
- package/dist/test-utils/is-same-held-seat.d.ts +2 -0
- package/dist/test-utils/types.d.ts +12 -2
- package/dist/test-utils/worker-contract.d.ts +14 -0
- package/dist/timeouts.d.ts +2 -0
- package/dist/types.d.ts +13 -0
- package/package.json +10 -3
- package/src/attempts/attempt-machine.ts +147 -0
- package/src/attempts/attempt-moves.ts +218 -0
- package/src/attempts/bind-attempt-session.ts +61 -0
- package/src/attempts/build-attempt-change.ts +540 -0
- package/src/attempts/build-attempt-fact.ts +135 -0
- package/src/attempts/end-item-attempts.ts +95 -0
- package/src/attempts/is-same-guard.ts +22 -0
- package/src/attempts/pick-call-attempt.ts +32 -0
- package/src/attempts/stop-stray-session.ts +48 -0
- package/src/attempts/types.ts +231 -0
- package/src/attempts/write-attempt-move.ts +41 -0
- package/src/attempts/write-session-bind.ts +47 -0
- package/src/claims/build-snapshot-hash.ts +9 -0
- package/src/claims/claim-next.ts +306 -0
- package/src/claims/pick-kept-session.ts +41 -0
- package/src/claims/request-wake.ts +17 -0
- package/src/claims/resume-claim.ts +56 -0
- package/src/claims/start-claim.ts +99 -0
- package/src/claims/types.ts +67 -0
- package/src/closeouts/build-settle-plans.ts +173 -0
- package/src/closeouts/close-out-attempt.ts +156 -0
- package/src/closeouts/effect-handlers.ts +232 -0
- package/src/closeouts/pick-settlement.ts +80 -0
- package/src/closeouts/settle-attempt.ts +161 -0
- package/src/closeouts/types.ts +87 -0
- package/src/index.ts +61 -0
- package/src/notices/constants.ts +7 -0
- package/src/notices/create-null-notifier.ts +6 -0
- package/src/notices/send-notices.ts +41 -0
- package/src/notices/types.ts +14 -0
- package/src/outbox/build-backoff-ms.ts +14 -0
- package/src/outbox/build-initial-sender-state.ts +14 -0
- package/src/outbox/build-outbox-status.ts +43 -0
- package/src/outbox/constants.ts +15 -0
- package/src/outbox/measure-wire-bytes.ts +31 -0
- package/src/outbox/pick-sender-move.ts +37 -0
- package/src/outbox/run-sender-once.ts +174 -0
- package/src/outbox/take-batch.ts +35 -0
- package/src/outbox/types.ts +76 -0
- package/src/pull-requests/build-link-change.ts +95 -0
- package/src/pull-requests/build-state-fact.ts +39 -0
- package/src/pull-requests/collect-attempt-trailers.ts +20 -0
- package/src/pull-requests/collect-seen-state.ts +19 -0
- package/src/pull-requests/constants.ts +5 -0
- package/src/pull-requests/link-pull-request.ts +119 -0
- package/src/pull-requests/parse-pull-request-url.ts +30 -0
- package/src/pull-requests/types.ts +63 -0
- package/src/pull-requests/watch-pull-requests.ts +308 -0
- package/src/readings/act-on-reading.ts +318 -0
- package/src/readings/find-waiting-since.ts +46 -0
- package/src/readings/pick-reading-action.ts +315 -0
- package/src/readings/types.ts +98 -0
- package/src/sessions/build-keep-writes.ts +55 -0
- package/src/sessions/build-kept-clear.ts +12 -0
- package/src/sessions/forget-sessions.ts +106 -0
- package/src/sessions/is-kept-due.ts +27 -0
- package/src/sessions/resume-kept-session.ts +25 -0
- package/src/sessions/types.ts +39 -0
- package/src/test-utils/apply-memory-change.ts +252 -0
- package/src/test-utils/build-memory-reader.ts +364 -0
- package/src/test-utils/build-mock-bind-change.ts +18 -11
- package/src/test-utils/build-mock-claim-change.ts +18 -8
- package/src/test-utils/build-mock-file-item-change.ts +3 -1
- package/src/test-utils/build-mock-new-id.ts +12 -0
- package/src/test-utils/build-mock-note-change.ts +18 -0
- package/src/test-utils/build-mock-pause-change.ts +2 -10
- package/src/test-utils/build-mock-pull-request-change.ts +19 -9
- package/src/test-utils/{build-mock-link-change.ts → build-mock-relation-change.ts} +6 -6
- package/src/test-utils/build-mock-running-reading.ts +19 -0
- package/src/test-utils/build-mock-settle-change.ts +18 -6
- package/src/test-utils/build-mock-start-change.ts +13 -6
- package/src/test-utils/claim-store-attempt-reader-cases.ts +163 -133
- package/src/test-utils/claim-store-claim-cases.ts +168 -85
- package/src/test-utils/claim-store-close-cases.ts +95 -0
- package/src/test-utils/claim-store-contract.ts +12 -2
- package/src/test-utils/claim-store-copy-cases.ts +100 -0
- package/src/test-utils/claim-store-exclusive-cases.ts +65 -19
- package/src/test-utils/claim-store-guard-cases.ts +92 -82
- package/src/test-utils/claim-store-item-reader-cases.ts +291 -77
- package/src/test-utils/claim-store-outbox-cases.ts +281 -0
- package/src/test-utils/claim-store-race-cases.ts +150 -0
- package/src/test-utils/claim-store-rollback-cases.ts +50 -50
- package/src/test-utils/claim-store-seat-cases.ts +270 -0
- package/src/test-utils/claim-store-session-cases.ts +289 -0
- package/src/test-utils/collect-memory-limit-fills.ts +15 -0
- package/src/test-utils/compare-text.ts +8 -0
- package/src/test-utils/create-fake-backoff.ts +16 -0
- package/src/test-utils/create-fake-clock.ts +20 -0
- package/src/test-utils/create-fake-fact-sink.ts +74 -0
- package/src/test-utils/create-fake-forge.ts +117 -0
- package/src/test-utils/create-fake-worker.ts +303 -0
- package/src/test-utils/create-memory-claim-store.ts +73 -484
- package/src/test-utils/create-test-dispatch.ts +597 -0
- package/src/test-utils/forge-contract.ts +171 -0
- package/src/test-utils/is-same-held-seat.ts +11 -0
- package/src/test-utils/types.ts +14 -2
- package/src/test-utils/worker-contract.ts +192 -0
- package/src/timeouts.ts +17 -0
- package/src/types.ts +32 -0
- package/dist/test-utils/claim-store-pool-cases.d.ts +0 -2
- package/src/test-utils/claim-store-pool-cases.ts +0 -178
|
@@ -1,66 +1,126 @@
|
|
|
1
1
|
import { expect } from 'bun:test';
|
|
2
2
|
import { brandSchemas } from '@boxxy/model';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { buildMockItemRules } from '@boxxy/model/test-utils/build-mock-item-rules';
|
|
4
|
+
import { buildMockV1AttemptRow } from '@boxxy/model/test-utils/build-mock-v1-attempt-row';
|
|
5
|
+
import { buildMockV1ItemRow } from '@boxxy/model/test-utils/build-mock-v1-item-row';
|
|
6
|
+
import { buildMockV1LeverRow } from '@boxxy/model/test-utils/build-mock-v1-lever-row';
|
|
5
7
|
import { buildMockClaimChange } from './build-mock-claim-change.ts';
|
|
6
8
|
import { buildMockFileItemChange } from './build-mock-file-item-change.ts';
|
|
7
|
-
import {
|
|
9
|
+
import { buildMockLeverChange } from './build-mock-lever-change.ts';
|
|
10
|
+
import { buildMockNoteChange } from './build-mock-note-change.ts';
|
|
8
11
|
import { buildMockPullRequestChange } from './build-mock-pull-request-change.ts';
|
|
12
|
+
import { buildMockRelationChange } from './build-mock-relation-change.ts';
|
|
9
13
|
import { buildMockSettleChange } from './build-mock-settle-change.ts';
|
|
10
14
|
import type { ClaimStoreCase } from './types.ts';
|
|
11
15
|
|
|
12
16
|
export const claimStoreItemReaderCases: readonly ClaimStoreCase[] = [
|
|
13
17
|
[
|
|
14
|
-
'#readSnapshot holds the open items, the store version and the
|
|
18
|
+
'#readSnapshot holds the open items, the store version and the limits',
|
|
15
19
|
async (store) => {
|
|
16
|
-
const open =
|
|
17
|
-
const archived =
|
|
20
|
+
const open = buildMockV1ItemRow();
|
|
21
|
+
const archived = buildMockV1ItemRow({ closedAt: brandSchemas.instant.parse(1500) });
|
|
18
22
|
|
|
19
23
|
await store.exclusive(async (transaction) => {
|
|
20
|
-
await transaction.
|
|
24
|
+
await transaction.syncLimits(
|
|
25
|
+
[{ name: brandSchemas.limitName.parse('workers'), max: 2, counts: {} }],
|
|
26
|
+
brandSchemas.instant.parse(500),
|
|
27
|
+
);
|
|
28
|
+
|
|
21
29
|
await transaction.applyChange(buildMockFileItemChange(open));
|
|
22
30
|
await transaction.applyChange(buildMockFileItemChange(archived));
|
|
23
31
|
});
|
|
24
32
|
|
|
25
33
|
const snapshot: unknown = await store.read((transaction) =>
|
|
26
|
-
transaction.readSnapshot(brandSchemas.instant.parse(5000),
|
|
34
|
+
transaction.readSnapshot(brandSchemas.instant.parse(5000), buildMockItemRules()),
|
|
27
35
|
);
|
|
28
36
|
|
|
29
37
|
return {
|
|
30
38
|
received: snapshot,
|
|
31
39
|
expected: {
|
|
32
40
|
storeVersion: 2,
|
|
33
|
-
items: [
|
|
34
|
-
|
|
41
|
+
items: [
|
|
42
|
+
{
|
|
43
|
+
...open,
|
|
44
|
+
derived: { state: 'ready' },
|
|
45
|
+
position: { kind: 'phase', phase: 'build', round: 1 },
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
relations: [],
|
|
35
49
|
levers: [],
|
|
36
|
-
|
|
50
|
+
limits: [{ name: 'workers', max: 2, counts: {}, held: 0 }],
|
|
51
|
+
wakes: [],
|
|
37
52
|
},
|
|
38
53
|
};
|
|
39
54
|
},
|
|
40
55
|
],
|
|
56
|
+
[
|
|
57
|
+
'#readSnapshot lists the sleeping attempts asked to wake, oldest request first',
|
|
58
|
+
async (store) => {
|
|
59
|
+
const later = buildMockV1AttemptRow({
|
|
60
|
+
state: 'sleeping',
|
|
61
|
+
wakeRequestedAt: brandSchemas.instant.parse(4000),
|
|
62
|
+
fields: { designMode: ['attended'] },
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const earlier = buildMockV1AttemptRow({
|
|
66
|
+
state: 'sleeping',
|
|
67
|
+
wakeRequestedAt: brandSchemas.instant.parse(3000),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const unasked = buildMockV1AttemptRow({ state: 'sleeping' });
|
|
71
|
+
|
|
72
|
+
await store.exclusive(async (transaction) => {
|
|
73
|
+
for (const attempt of [later, earlier, unasked]) {
|
|
74
|
+
await transaction.applyChange(
|
|
75
|
+
buildMockFileItemChange(buildMockV1ItemRow({ id: attempt.item })),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
await transaction.applyChange(buildMockClaimChange(attempt));
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const snapshot = await store.read((transaction) =>
|
|
83
|
+
transaction.readSnapshot(brandSchemas.instant.parse(5000), buildMockItemRules()),
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
received: snapshot.wakes,
|
|
88
|
+
expected: [
|
|
89
|
+
{
|
|
90
|
+
attempt: earlier.id,
|
|
91
|
+
item: earlier.item,
|
|
92
|
+
phase: 'build',
|
|
93
|
+
pool: 'main',
|
|
94
|
+
fields: {},
|
|
95
|
+
requestedAt: 3000,
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
attempt: later.id,
|
|
99
|
+
item: later.item,
|
|
100
|
+
phase: 'build',
|
|
101
|
+
pool: 'main',
|
|
102
|
+
fields: { designMode: ['attended'] },
|
|
103
|
+
requestedAt: 4000,
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
};
|
|
107
|
+
},
|
|
108
|
+
],
|
|
41
109
|
[
|
|
42
110
|
'#readSnapshot drops a done item',
|
|
43
111
|
async (store) => {
|
|
44
|
-
const item =
|
|
45
|
-
const attempt =
|
|
112
|
+
const item = buildMockV1ItemRow();
|
|
113
|
+
const attempt = buildMockV1AttemptRow({ item: item.id, state: 'starting' });
|
|
46
114
|
|
|
47
115
|
await store.exclusive(async (transaction) => {
|
|
48
|
-
await transaction.syncPoolSlots([{ name: attempt.pool, slots: 1 }]);
|
|
49
116
|
await transaction.applyChange(buildMockFileItemChange(item));
|
|
50
117
|
await transaction.applyChange(buildMockClaimChange(attempt));
|
|
51
|
-
|
|
52
|
-
await transaction.applyChange(
|
|
53
|
-
buildMockSettleChange({
|
|
54
|
-
attempt: { ...attempt, slot: 1, slotGen: 1 },
|
|
55
|
-
state: 'succeeded',
|
|
56
|
-
}),
|
|
57
|
-
);
|
|
58
|
-
|
|
118
|
+
await transaction.applyChange(buildMockSettleChange({ attempt, state: 'succeeded' }));
|
|
59
119
|
await transaction.applyChange(buildMockPullRequestChange({ attempt, state: 'merged' }));
|
|
60
120
|
});
|
|
61
121
|
|
|
62
122
|
const snapshot = await store.read((transaction) =>
|
|
63
|
-
transaction.readSnapshot(brandSchemas.instant.parse(5000),
|
|
123
|
+
transaction.readSnapshot(brandSchemas.instant.parse(5000), buildMockItemRules()),
|
|
64
124
|
);
|
|
65
125
|
|
|
66
126
|
return { received: snapshot.items, expected: [] };
|
|
@@ -70,85 +130,157 @@ export const claimStoreItemReaderCases: readonly ClaimStoreCase[] = [
|
|
|
70
130
|
'#readItem returns null for an unknown item',
|
|
71
131
|
async (store) => {
|
|
72
132
|
const read = await store.read((transaction) =>
|
|
73
|
-
transaction.readItem(
|
|
133
|
+
transaction.readItem(
|
|
134
|
+
buildMockV1ItemRow().id,
|
|
135
|
+
brandSchemas.instant.parse(5000),
|
|
136
|
+
buildMockItemRules(),
|
|
137
|
+
),
|
|
74
138
|
);
|
|
75
139
|
|
|
76
140
|
return { received: read, expected: null };
|
|
77
141
|
},
|
|
78
142
|
],
|
|
79
143
|
[
|
|
80
|
-
'#readItem derives blocked for the target of a live
|
|
144
|
+
'#readItem derives blocked for the target of a live relation from a ready item',
|
|
81
145
|
async (store) => {
|
|
82
|
-
const source =
|
|
83
|
-
const target =
|
|
146
|
+
const source = buildMockV1ItemRow();
|
|
147
|
+
const target = buildMockV1ItemRow();
|
|
84
148
|
|
|
85
149
|
await store.exclusive(async (transaction) => {
|
|
86
150
|
await transaction.applyChange(buildMockFileItemChange(source));
|
|
87
151
|
await transaction.applyChange(buildMockFileItemChange(target));
|
|
88
152
|
|
|
89
153
|
await transaction.applyChange(
|
|
90
|
-
|
|
154
|
+
buildMockRelationChange({ source: source.id, target: target.id }),
|
|
91
155
|
);
|
|
92
156
|
});
|
|
93
157
|
|
|
94
158
|
const read = await store.read((transaction) =>
|
|
95
|
-
transaction.readItem(target.id, brandSchemas.instant.parse(5000),
|
|
159
|
+
transaction.readItem(target.id, brandSchemas.instant.parse(5000), buildMockItemRules()),
|
|
96
160
|
);
|
|
97
161
|
|
|
98
162
|
return { received: read?.derived, expected: { state: 'blocked' } };
|
|
99
163
|
},
|
|
100
164
|
],
|
|
101
165
|
[
|
|
102
|
-
'#readItem derives ready for the target of a
|
|
166
|
+
'#readItem derives ready for the target of a relation from an archived item',
|
|
103
167
|
async (store) => {
|
|
104
|
-
const source =
|
|
105
|
-
const target =
|
|
168
|
+
const source = buildMockV1ItemRow({ closedAt: brandSchemas.instant.parse(1500) });
|
|
169
|
+
const target = buildMockV1ItemRow();
|
|
106
170
|
|
|
107
171
|
await store.exclusive(async (transaction) => {
|
|
108
172
|
await transaction.applyChange(buildMockFileItemChange(source));
|
|
109
173
|
await transaction.applyChange(buildMockFileItemChange(target));
|
|
110
174
|
|
|
111
175
|
await transaction.applyChange(
|
|
112
|
-
|
|
176
|
+
buildMockRelationChange({ source: source.id, target: target.id }),
|
|
113
177
|
);
|
|
114
178
|
});
|
|
115
179
|
|
|
116
180
|
const read = await store.read((transaction) =>
|
|
117
|
-
transaction.readItem(target.id, brandSchemas.instant.parse(5000),
|
|
181
|
+
transaction.readItem(target.id, brandSchemas.instant.parse(5000), buildMockItemRules()),
|
|
118
182
|
);
|
|
119
183
|
|
|
120
184
|
return { received: read?.derived, expected: { state: 'ready' } };
|
|
121
185
|
},
|
|
122
186
|
],
|
|
123
187
|
[
|
|
124
|
-
'#readItem
|
|
188
|
+
'#readItem holds an item whose phase lost its attempts in a row',
|
|
125
189
|
async (store) => {
|
|
126
|
-
const item =
|
|
127
|
-
const
|
|
190
|
+
const item = buildMockV1ItemRow();
|
|
191
|
+
const first = buildMockV1AttemptRow({ item: item.id, state: 'starting' });
|
|
192
|
+
|
|
193
|
+
const second = buildMockV1AttemptRow({
|
|
194
|
+
item: item.id,
|
|
195
|
+
state: 'starting',
|
|
196
|
+
number: 2,
|
|
197
|
+
leaseGen: 2,
|
|
198
|
+
});
|
|
128
199
|
|
|
129
|
-
|
|
200
|
+
await store.exclusive(async (transaction) => {
|
|
201
|
+
await transaction.applyChange(buildMockFileItemChange(item));
|
|
202
|
+
|
|
203
|
+
for (const attempt of [first, second]) {
|
|
204
|
+
await transaction.applyChange(buildMockClaimChange(attempt));
|
|
205
|
+
await transaction.applyChange(buildMockSettleChange({ attempt, state: 'failed' }));
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const read = await store.read((transaction) =>
|
|
210
|
+
transaction.readItem(item.id, brandSchemas.instant.parse(5000), buildMockItemRules()),
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
received: { derived: read?.derived, position: read?.position.kind },
|
|
215
|
+
expected: { derived: { state: 'waiting', reason: 'attempts used up' }, position: 'hold' },
|
|
216
|
+
};
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
[
|
|
220
|
+
'#readItem returns a held item to its phase after a retry lever',
|
|
221
|
+
async (store) => {
|
|
222
|
+
const item = buildMockV1ItemRow();
|
|
223
|
+
const first = buildMockV1AttemptRow({ item: item.id, state: 'starting' });
|
|
224
|
+
|
|
225
|
+
const second = buildMockV1AttemptRow({
|
|
226
|
+
item: item.id,
|
|
227
|
+
state: 'starting',
|
|
228
|
+
number: 2,
|
|
229
|
+
leaseGen: 2,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const retry = buildMockV1LeverRow({
|
|
233
|
+
item: item.id,
|
|
234
|
+
kind: 'item.retry',
|
|
235
|
+
at: brandSchemas.instant.parse(4000),
|
|
236
|
+
});
|
|
130
237
|
|
|
131
238
|
await store.exclusive(async (transaction) => {
|
|
132
|
-
await transaction.syncPoolSlots([{ name: attempt.pool, slots: 1 }]);
|
|
133
239
|
await transaction.applyChange(buildMockFileItemChange(item));
|
|
134
|
-
await transaction.applyChange(buildMockClaimChange(attempt));
|
|
135
240
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
241
|
+
for (const attempt of [first, second]) {
|
|
242
|
+
await transaction.applyChange(buildMockClaimChange(attempt));
|
|
243
|
+
await transaction.applyChange(buildMockSettleChange({ attempt, state: 'failed' }));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
await transaction.applyChange(buildMockLeverChange(retry));
|
|
139
247
|
});
|
|
140
248
|
|
|
141
249
|
const read = await store.read((transaction) =>
|
|
142
|
-
transaction.readItem(
|
|
143
|
-
item.id,
|
|
144
|
-
brandSchemas.instant.parse(5000),
|
|
145
|
-
new Map([[item.kind, phases]]),
|
|
146
|
-
),
|
|
250
|
+
transaction.readItem(item.id, brandSchemas.instant.parse(5000), buildMockItemRules()),
|
|
147
251
|
);
|
|
148
252
|
|
|
149
253
|
return {
|
|
150
|
-
received: read?.derived,
|
|
151
|
-
expected: {
|
|
254
|
+
received: { derived: read?.derived, position: read?.position },
|
|
255
|
+
expected: {
|
|
256
|
+
derived: { state: 'ready' },
|
|
257
|
+
position: { kind: 'phase', phase: 'build', round: 1 },
|
|
258
|
+
},
|
|
259
|
+
};
|
|
260
|
+
},
|
|
261
|
+
],
|
|
262
|
+
[
|
|
263
|
+
'#readItem ends an item whose last phase of the pipeline succeeded',
|
|
264
|
+
async (store) => {
|
|
265
|
+
const item = buildMockV1ItemRow();
|
|
266
|
+
const attempt = buildMockV1AttemptRow({ item: item.id, state: 'starting' });
|
|
267
|
+
|
|
268
|
+
await store.exclusive(async (transaction) => {
|
|
269
|
+
await transaction.applyChange(buildMockFileItemChange(item));
|
|
270
|
+
await transaction.applyChange(buildMockClaimChange(attempt));
|
|
271
|
+
await transaction.applyChange(buildMockSettleChange({ attempt, state: 'succeeded' }));
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
const read = await store.read((transaction) =>
|
|
275
|
+
transaction.readItem(item.id, brandSchemas.instant.parse(5000), buildMockItemRules()),
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
received: { derived: read?.derived, position: read?.position },
|
|
280
|
+
expected: {
|
|
281
|
+
derived: { state: 'waiting', reason: 'no pull request linked' },
|
|
282
|
+
position: { kind: 'end', reason: 'pipeline-done' },
|
|
283
|
+
},
|
|
152
284
|
};
|
|
153
285
|
},
|
|
154
286
|
],
|
|
@@ -156,10 +288,11 @@ export const claimStoreItemReaderCases: readonly ClaimStoreCase[] = [
|
|
|
156
288
|
'#listItems keeps the items of one state and repo, oldest first',
|
|
157
289
|
async (store) => {
|
|
158
290
|
const repo = brandSchemas.repoName.parse('acme/lamps');
|
|
159
|
-
const older =
|
|
160
|
-
const newer =
|
|
161
|
-
const idea =
|
|
162
|
-
const elsewhere =
|
|
291
|
+
const older = buildMockV1ItemRow({ repo, filedAt: brandSchemas.instant.parse(1000) });
|
|
292
|
+
const newer = buildMockV1ItemRow({ repo, filedAt: brandSchemas.instant.parse(2000) });
|
|
293
|
+
const idea = buildMockV1ItemRow({ repo, acceptance: [] });
|
|
294
|
+
const elsewhere = buildMockV1ItemRow({ repo: brandSchemas.repoName.parse('acme/fans') });
|
|
295
|
+
const build = brandSchemas.phaseName.parse('build');
|
|
163
296
|
|
|
164
297
|
await store.exclusive(async (transaction) => {
|
|
165
298
|
await transaction.applyChange(buildMockFileItemChange(newer));
|
|
@@ -172,7 +305,7 @@ export const claimStoreItemReaderCases: readonly ClaimStoreCase[] = [
|
|
|
172
305
|
transaction.listItems(
|
|
173
306
|
{ state: 'ready', repo },
|
|
174
307
|
brandSchemas.instant.parse(5000),
|
|
175
|
-
new Map(),
|
|
308
|
+
buildMockItemRules({ phases: new Map([[build, { needsAcceptance: true }]]) }),
|
|
176
309
|
),
|
|
177
310
|
);
|
|
178
311
|
|
|
@@ -183,59 +316,81 @@ export const claimStoreItemReaderCases: readonly ClaimStoreCase[] = [
|
|
|
183
316
|
'#listOpenIssues returns the open core.issue items of one repo',
|
|
184
317
|
async (store) => {
|
|
185
318
|
const repo = brandSchemas.repoName.parse('acme/lamps');
|
|
186
|
-
const open =
|
|
187
|
-
const closed =
|
|
188
|
-
const elsewhere =
|
|
319
|
+
const open = buildMockV1ItemRow({ repo });
|
|
320
|
+
const closed = buildMockV1ItemRow({ repo, closedAt: brandSchemas.instant.parse(1500) });
|
|
321
|
+
const elsewhere = buildMockV1ItemRow({ repo: brandSchemas.repoName.parse('acme/fans') });
|
|
322
|
+
const task = buildMockV1ItemRow({ repo, kind: brandSchemas.itemKindName.parse('core.task') });
|
|
189
323
|
|
|
190
324
|
await store.exclusive(async (transaction) => {
|
|
191
325
|
await transaction.applyChange(buildMockFileItemChange(open));
|
|
192
326
|
await transaction.applyChange(buildMockFileItemChange(closed));
|
|
193
327
|
await transaction.applyChange(buildMockFileItemChange(elsewhere));
|
|
328
|
+
await transaction.applyChange(buildMockFileItemChange(task));
|
|
194
329
|
});
|
|
195
330
|
|
|
196
331
|
const listed: unknown = await store.read((transaction) =>
|
|
197
|
-
transaction.listOpenIssues(repo, brandSchemas.instant.parse(5000),
|
|
332
|
+
transaction.listOpenIssues(repo, brandSchemas.instant.parse(5000), buildMockItemRules()),
|
|
198
333
|
);
|
|
199
334
|
|
|
200
|
-
return {
|
|
335
|
+
return {
|
|
336
|
+
received: listed,
|
|
337
|
+
expected: [
|
|
338
|
+
{
|
|
339
|
+
...open,
|
|
340
|
+
derived: { state: 'ready' },
|
|
341
|
+
position: { kind: 'phase', phase: 'build', round: 1 },
|
|
342
|
+
},
|
|
343
|
+
],
|
|
344
|
+
};
|
|
201
345
|
},
|
|
202
346
|
],
|
|
203
347
|
[
|
|
204
|
-
'#readItemDetail returns the item with its attempts,
|
|
348
|
+
'#readItemDetail returns the item with its attempts, relations, evidence, pull requests and notes',
|
|
205
349
|
async (store) => {
|
|
206
|
-
const item =
|
|
207
|
-
const blocker =
|
|
208
|
-
const attempt =
|
|
350
|
+
const item = buildMockV1ItemRow();
|
|
351
|
+
const blocker = buildMockV1ItemRow();
|
|
352
|
+
const attempt = buildMockV1AttemptRow({ item: item.id, state: 'starting' });
|
|
353
|
+
|
|
354
|
+
const note = {
|
|
355
|
+
item: item.id,
|
|
356
|
+
seq: 1,
|
|
357
|
+
text: 'The lamp hums when dimmed.',
|
|
358
|
+
by: 'boxxy:owner:local',
|
|
359
|
+
at: brandSchemas.instant.parse(4500),
|
|
360
|
+
} as const;
|
|
209
361
|
|
|
210
362
|
await store.exclusive(async (transaction) => {
|
|
211
|
-
await transaction.syncPoolSlots([{ name: attempt.pool, slots: 1 }]);
|
|
212
363
|
await transaction.applyChange(buildMockFileItemChange(item));
|
|
213
364
|
await transaction.applyChange(buildMockFileItemChange(blocker));
|
|
214
365
|
await transaction.applyChange(buildMockClaimChange(attempt));
|
|
366
|
+
await transaction.applyChange(buildMockSettleChange({ attempt, state: 'succeeded' }));
|
|
367
|
+
await transaction.applyChange(buildMockPullRequestChange({ attempt, state: 'open' }));
|
|
215
368
|
|
|
216
369
|
await transaction.applyChange(
|
|
217
|
-
|
|
218
|
-
attempt: { ...attempt, slot: 1, slotGen: 1 },
|
|
219
|
-
state: 'succeeded',
|
|
220
|
-
}),
|
|
370
|
+
buildMockRelationChange({ source: blocker.id, target: item.id }),
|
|
221
371
|
);
|
|
222
372
|
|
|
223
|
-
await transaction.applyChange(
|
|
224
|
-
await transaction.applyChange(buildMockLinkChange({ source: blocker.id, target: item.id }));
|
|
373
|
+
await transaction.applyChange(buildMockNoteChange(note));
|
|
225
374
|
});
|
|
226
375
|
|
|
227
376
|
const detail: unknown = await store.read((transaction) =>
|
|
228
|
-
transaction.readItemDetail(item.id, brandSchemas.instant.parse(5000),
|
|
377
|
+
transaction.readItemDetail(item.id, brandSchemas.instant.parse(5000), buildMockItemRules()),
|
|
229
378
|
);
|
|
230
379
|
|
|
231
380
|
return {
|
|
232
381
|
received: detail,
|
|
233
382
|
expected: {
|
|
234
|
-
item: {
|
|
383
|
+
item: {
|
|
384
|
+
...item,
|
|
385
|
+
derived: { state: 'waiting', reason: 'pull request open' },
|
|
386
|
+
position: { kind: 'end', reason: 'pipeline-done' },
|
|
387
|
+
levers: [],
|
|
388
|
+
},
|
|
235
389
|
attempts: [expect.objectContaining({ id: attempt.id, state: 'succeeded' })],
|
|
236
|
-
|
|
237
|
-
evidence: [expect.objectContaining({ attempt: attempt.id, kind: '
|
|
390
|
+
relations: [expect.objectContaining({ source: blocker.id, target: item.id })],
|
|
391
|
+
evidence: [expect.objectContaining({ attempt: attempt.id, kind: 'pull_request' })],
|
|
238
392
|
pullRequests: [expect.objectContaining({ attempt: attempt.id, state: 'open' })],
|
|
393
|
+
notes: [note],
|
|
239
394
|
},
|
|
240
395
|
};
|
|
241
396
|
},
|
|
@@ -245,13 +400,72 @@ export const claimStoreItemReaderCases: readonly ClaimStoreCase[] = [
|
|
|
245
400
|
async (store) => {
|
|
246
401
|
const detail = await store.read((transaction) =>
|
|
247
402
|
transaction.readItemDetail(
|
|
248
|
-
|
|
403
|
+
buildMockV1ItemRow().id,
|
|
249
404
|
brandSchemas.instant.parse(5000),
|
|
250
|
-
|
|
405
|
+
buildMockItemRules(),
|
|
251
406
|
),
|
|
252
407
|
);
|
|
253
408
|
|
|
254
409
|
return { received: detail, expected: null };
|
|
255
410
|
},
|
|
256
411
|
],
|
|
412
|
+
[
|
|
413
|
+
'#listItemNotes returns the notes of one item by seq',
|
|
414
|
+
async (store) => {
|
|
415
|
+
const item = buildMockV1ItemRow();
|
|
416
|
+
const other = buildMockV1ItemRow();
|
|
417
|
+
|
|
418
|
+
const note = (id: typeof item.id, seq: number, text: string) =>
|
|
419
|
+
buildMockNoteChange({
|
|
420
|
+
item: id,
|
|
421
|
+
seq,
|
|
422
|
+
text,
|
|
423
|
+
by: 'boxxy:owner:local',
|
|
424
|
+
at: brandSchemas.instant.parse(4000 + seq),
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
await store.exclusive(async (transaction) => {
|
|
428
|
+
await transaction.applyChange(buildMockFileItemChange(item));
|
|
429
|
+
await transaction.applyChange(buildMockFileItemChange(other));
|
|
430
|
+
await transaction.applyChange(note(item.id, 2, 'The switch sticks.'));
|
|
431
|
+
await transaction.applyChange(note(other.id, 1, 'The cord frays.'));
|
|
432
|
+
await transaction.applyChange(note(item.id, 1, 'The bulb flickers.'));
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
const notes = await store.read((transaction) => transaction.listItemNotes(item.id));
|
|
436
|
+
|
|
437
|
+
return {
|
|
438
|
+
received: notes.map((row) => row.text),
|
|
439
|
+
expected: ['The bulb flickers.', 'The switch sticks.'],
|
|
440
|
+
};
|
|
441
|
+
},
|
|
442
|
+
],
|
|
443
|
+
[
|
|
444
|
+
'#applyChange throws on a second note with the same seq on one item',
|
|
445
|
+
async (store) => {
|
|
446
|
+
const item = buildMockV1ItemRow();
|
|
447
|
+
|
|
448
|
+
const note = {
|
|
449
|
+
item: item.id,
|
|
450
|
+
seq: 1,
|
|
451
|
+
text: 'The bulb flickers.',
|
|
452
|
+
by: 'boxxy:owner:local',
|
|
453
|
+
at: brandSchemas.instant.parse(4500),
|
|
454
|
+
} as const;
|
|
455
|
+
|
|
456
|
+
await store.exclusive(async (transaction) => {
|
|
457
|
+
await transaction.applyChange(buildMockFileItemChange(item));
|
|
458
|
+
await transaction.applyChange(buildMockNoteChange(note));
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
const settled = await store
|
|
462
|
+
.exclusive((transaction) => transaction.applyChange(buildMockNoteChange(note)))
|
|
463
|
+
.then(
|
|
464
|
+
() => 'applied',
|
|
465
|
+
() => 'thrown',
|
|
466
|
+
);
|
|
467
|
+
|
|
468
|
+
return { received: settled, expected: 'thrown' };
|
|
469
|
+
},
|
|
470
|
+
],
|
|
257
471
|
];
|