@skillsmith/core 0.11.0 → 0.11.1
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/CHANGELOG.md +5 -0
- package/README.md +7 -5
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/services/skill-installation.helpers.d.ts +13 -1
- package/dist/src/services/skill-installation.helpers.d.ts.map +1 -1
- package/dist/src/services/skill-installation.helpers.js +14 -1
- package/dist/src/services/skill-installation.helpers.js.map +1 -1
- package/dist/src/sync/BackgroundSyncService.d.ts +10 -2
- package/dist/src/sync/BackgroundSyncService.d.ts.map +1 -1
- package/dist/src/sync/BackgroundSyncService.js +46 -4
- package/dist/src/sync/BackgroundSyncService.js.map +1 -1
- package/dist/src/sync/SyncEngine.d.ts +9 -0
- package/dist/src/sync/SyncEngine.d.ts.map +1 -1
- package/dist/src/sync/SyncEngine.js +23 -4
- package/dist/src/sync/SyncEngine.js.map +1 -1
- package/dist/tests/sync/BackgroundSyncService.abort.test.d.ts +17 -0
- package/dist/tests/sync/BackgroundSyncService.abort.test.d.ts.map +1 -0
- package/dist/tests/sync/BackgroundSyncService.abort.test.js +182 -0
- package/dist/tests/sync/BackgroundSyncService.abort.test.js.map +1 -0
- package/dist/tests/sync/BackgroundSyncService.test.d.ts +9 -1
- package/dist/tests/sync/BackgroundSyncService.test.d.ts.map +1 -1
- package/dist/tests/sync/BackgroundSyncService.test.js +8 -3
- package/dist/tests/sync/BackgroundSyncService.test.js.map +1 -1
- package/dist/tests/sync/SyncEngine.abort.test.d.ts +15 -0
- package/dist/tests/sync/SyncEngine.abort.test.d.ts.map +1 -0
- package/dist/tests/sync/SyncEngine.abort.test.js +100 -0
- package/dist/tests/sync/SyncEngine.abort.test.js.map +1 -0
- package/dist/tests/sync/SyncEngine.status.test.d.ts +10 -0
- package/dist/tests/sync/SyncEngine.status.test.d.ts.map +1 -0
- package/dist/tests/sync/SyncEngine.status.test.js +97 -0
- package/dist/tests/sync/SyncEngine.status.test.js.map +1 -0
- package/dist/tests/sync/SyncEngine.test.d.ts +22 -1
- package/dist/tests/sync/SyncEngine.test.d.ts.map +1 -1
- package/dist/tests/sync/SyncEngine.test.js +3 -69
- package/dist/tests/sync/SyncEngine.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-5649: BackgroundSyncService — abort + awaitable stop(), and the new
|
|
3
|
+
* logs-by-default onSyncError.
|
|
4
|
+
*
|
|
5
|
+
* Split from BackgroundSyncService.test.ts to stay under the 500-LOC
|
|
6
|
+
* file-size gate. Reuses that file's mock factories (createMockSyncEngine,
|
|
7
|
+
* createMockConfigRepo, createMockSyncResult — exported there for this
|
|
8
|
+
* purpose).
|
|
9
|
+
*
|
|
10
|
+
* The shutdown coordinator relies on `stop()` resolving only once any
|
|
11
|
+
* in-flight sync has settled, and on the `AbortSignal` it threads into
|
|
12
|
+
* `syncEngine.sync()` actually being aborted synchronously by `stop()` (so
|
|
13
|
+
* `SyncEngine`'s abort checkpoints see it before the process ever gets to
|
|
14
|
+
* `db.close()`).
|
|
15
|
+
*/
|
|
16
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
17
|
+
// SMI-5649: BackgroundSyncService.ts builds its default `onSyncError` logger
|
|
18
|
+
// via `createLogger('mcp')` (`../logging/index.js`, relative from
|
|
19
|
+
// `packages/core/src/sync/`) ONCE at module load, so asserting what it logs
|
|
20
|
+
// requires mocking the factory before the module under test is imported.
|
|
21
|
+
// `vi.mock` is hoisted above all imports (including the one below), so this
|
|
22
|
+
// works regardless of declaration order. Mirrors the identical pattern in
|
|
23
|
+
// `packages/mcp-server/src/shutdown.test.ts`.
|
|
24
|
+
const { mockLogger } = vi.hoisted(() => ({
|
|
25
|
+
mockLogger: {
|
|
26
|
+
error: vi.fn(),
|
|
27
|
+
warn: vi.fn(),
|
|
28
|
+
info: vi.fn(),
|
|
29
|
+
debug: vi.fn(),
|
|
30
|
+
},
|
|
31
|
+
}));
|
|
32
|
+
vi.mock('../../src/logging/index.js', () => ({
|
|
33
|
+
createLogger: vi.fn(() => mockLogger),
|
|
34
|
+
}));
|
|
35
|
+
import { BackgroundSyncService } from '../../src/sync/BackgroundSyncService.js';
|
|
36
|
+
import { createMockSyncResult, createMockSyncEngine, createMockConfigRepo, } from './BackgroundSyncService.test.js';
|
|
37
|
+
/**
|
|
38
|
+
* SMI-5649: abort + awaitable stop(). The shutdown coordinator relies on
|
|
39
|
+
* `stop()` resolving only once any in-flight sync has settled, and on the
|
|
40
|
+
* `AbortSignal` it threads into `syncEngine.sync()` actually being aborted
|
|
41
|
+
* synchronously by `stop()` (so `SyncEngine`'s abort checkpoints see it
|
|
42
|
+
* before the process ever gets to `db.close()`).
|
|
43
|
+
*/
|
|
44
|
+
describe('stop() — abort + awaitable settlement (SMI-5649)', () => {
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
vi.useRealTimers();
|
|
47
|
+
});
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
vi.useFakeTimers();
|
|
50
|
+
});
|
|
51
|
+
it('passes an AbortSignal into syncEngine.sync()', async () => {
|
|
52
|
+
// start() is what creates the abortController (design doc §2.2) — the
|
|
53
|
+
// production path always calls start() before any sync can occur
|
|
54
|
+
// (createToolContextAsync calls `backgroundSync.start()` immediately
|
|
55
|
+
// after construction), so tests exercising the abort-signal plumbing
|
|
56
|
+
// must too.
|
|
57
|
+
const engine = createMockSyncEngine();
|
|
58
|
+
const service = new BackgroundSyncService(engine, createMockConfigRepo(), {
|
|
59
|
+
syncOnStart: false,
|
|
60
|
+
});
|
|
61
|
+
service.start();
|
|
62
|
+
await service.manualSync();
|
|
63
|
+
expect(engine.sync).toHaveBeenCalledWith(expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
|
64
|
+
await service.stop();
|
|
65
|
+
});
|
|
66
|
+
it('stop() returns a Promise and resolves only after an in-flight sync settles', async () => {
|
|
67
|
+
let resolveSync;
|
|
68
|
+
const engine = {
|
|
69
|
+
sync: vi.fn().mockReturnValue(new Promise((resolve) => {
|
|
70
|
+
resolveSync = () => resolve(createMockSyncResult());
|
|
71
|
+
})),
|
|
72
|
+
};
|
|
73
|
+
const service = new BackgroundSyncService(engine, createMockConfigRepo(), {
|
|
74
|
+
syncOnStart: false,
|
|
75
|
+
});
|
|
76
|
+
service.start();
|
|
77
|
+
const inFlight = service.manualSync();
|
|
78
|
+
let stopSettled = false;
|
|
79
|
+
const stopPromise = service.stop().then(() => {
|
|
80
|
+
stopSettled = true;
|
|
81
|
+
});
|
|
82
|
+
// Give the microtask queue a chance to run — stop() must NOT resolve
|
|
83
|
+
// while the sync is still pending.
|
|
84
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
85
|
+
expect(stopSettled).toBe(false);
|
|
86
|
+
resolveSync();
|
|
87
|
+
await stopPromise;
|
|
88
|
+
expect(stopSettled).toBe(true);
|
|
89
|
+
await inFlight.catch(() => { });
|
|
90
|
+
});
|
|
91
|
+
it("aborts the in-flight sync's AbortSignal when stop() is called", async () => {
|
|
92
|
+
let capturedSignal;
|
|
93
|
+
let resolveSync;
|
|
94
|
+
const engine = {
|
|
95
|
+
sync: vi.fn().mockImplementation(({ signal }) => {
|
|
96
|
+
capturedSignal = signal;
|
|
97
|
+
return new Promise((resolve) => {
|
|
98
|
+
resolveSync = () => resolve(createMockSyncResult());
|
|
99
|
+
});
|
|
100
|
+
}),
|
|
101
|
+
};
|
|
102
|
+
const service = new BackgroundSyncService(engine, createMockConfigRepo(), {
|
|
103
|
+
syncOnStart: false,
|
|
104
|
+
});
|
|
105
|
+
service.start();
|
|
106
|
+
const inFlight = service.manualSync();
|
|
107
|
+
expect(capturedSignal?.aborted).toBe(false);
|
|
108
|
+
const stopPromise = service.stop();
|
|
109
|
+
expect(capturedSignal?.aborted).toBe(true);
|
|
110
|
+
resolveSync();
|
|
111
|
+
await stopPromise;
|
|
112
|
+
await inFlight.catch(() => { });
|
|
113
|
+
});
|
|
114
|
+
it('stop() still clears the timer and flips isStarted synchronously for non-awaiting callers', () => {
|
|
115
|
+
vi.useFakeTimers();
|
|
116
|
+
const service = new BackgroundSyncService(createMockSyncEngine(), createMockConfigRepo(), {
|
|
117
|
+
syncOnStart: false,
|
|
118
|
+
});
|
|
119
|
+
service.start();
|
|
120
|
+
expect(service.isServiceStarted()).toBe(true);
|
|
121
|
+
// Fire-and-forget — the original callers of stop() never awaited it.
|
|
122
|
+
void service.stop();
|
|
123
|
+
expect(service.isServiceStarted()).toBe(false);
|
|
124
|
+
vi.useRealTimers();
|
|
125
|
+
});
|
|
126
|
+
it('stop() resolves cleanly (no unhandled rejection) even when the in-flight sync rejects', async () => {
|
|
127
|
+
let rejectSync;
|
|
128
|
+
const engine = {
|
|
129
|
+
sync: vi.fn().mockReturnValue(new Promise((_resolve, reject) => {
|
|
130
|
+
rejectSync = reject;
|
|
131
|
+
})),
|
|
132
|
+
};
|
|
133
|
+
const service = new BackgroundSyncService(engine, createMockConfigRepo(), {
|
|
134
|
+
syncOnStart: false,
|
|
135
|
+
onSyncError: () => { },
|
|
136
|
+
});
|
|
137
|
+
const inFlight = service.manualSync().catch(() => { });
|
|
138
|
+
const stopPromise = service.stop();
|
|
139
|
+
rejectSync(new Error('network exploded'));
|
|
140
|
+
await expect(stopPromise).resolves.toBeUndefined();
|
|
141
|
+
await inFlight;
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
/**
|
|
145
|
+
* SMI-5649: sync errors were previously invisible by default (a no-op
|
|
146
|
+
* `onSyncError`) — this asserts the new default logs via the shared
|
|
147
|
+
* logger at error level, mirroring `closeDbOnShutdown`'s SMI-5615
|
|
148
|
+
* stderr-visibility rationale.
|
|
149
|
+
*/
|
|
150
|
+
describe('default onSyncError logs by default (SMI-5649)', () => {
|
|
151
|
+
beforeEach(() => {
|
|
152
|
+
vi.useRealTimers();
|
|
153
|
+
mockLogger.error.mockClear();
|
|
154
|
+
});
|
|
155
|
+
afterEach(() => {
|
|
156
|
+
vi.useFakeTimers();
|
|
157
|
+
});
|
|
158
|
+
it('logs via logger.error when no onSyncError override is provided', async () => {
|
|
159
|
+
const engine = {
|
|
160
|
+
sync: vi.fn().mockRejectedValue(new Error('Network timeout')),
|
|
161
|
+
};
|
|
162
|
+
const service = new BackgroundSyncService(engine, createMockConfigRepo(), {
|
|
163
|
+
syncOnStart: false,
|
|
164
|
+
});
|
|
165
|
+
await service.manualSync().catch(() => { });
|
|
166
|
+
expect(mockLogger.error).toHaveBeenCalledWith(expect.stringContaining('Background sync failed'), expect.objectContaining({ err: expect.any(Error) }));
|
|
167
|
+
});
|
|
168
|
+
it('does not log via the default when a caller-provided onSyncError override is given', async () => {
|
|
169
|
+
const onError = vi.fn();
|
|
170
|
+
const engine = {
|
|
171
|
+
sync: vi.fn().mockRejectedValue(new Error('Network timeout')),
|
|
172
|
+
};
|
|
173
|
+
const service = new BackgroundSyncService(engine, createMockConfigRepo(), {
|
|
174
|
+
syncOnStart: false,
|
|
175
|
+
onSyncError: onError,
|
|
176
|
+
});
|
|
177
|
+
await service.manualSync().catch(() => { });
|
|
178
|
+
expect(onError).toHaveBeenCalled();
|
|
179
|
+
expect(mockLogger.error).not.toHaveBeenCalled();
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
//# sourceMappingURL=BackgroundSyncService.abort.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BackgroundSyncService.abort.test.js","sourceRoot":"","sources":["../../../tests/sync/BackgroundSyncService.abort.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,5 +9,13 @@
|
|
|
9
9
|
* - Manual sync
|
|
10
10
|
* - Error handling and callbacks
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
import type { SyncEngine, SyncResult } from '../../src/sync/SyncEngine.js';
|
|
13
|
+
import type { SyncConfigRepository } from '../../src/repositories/SyncConfigRepository.js';
|
|
14
|
+
export declare function createMockSyncResult(overrides?: Partial<SyncResult>): SyncResult;
|
|
15
|
+
export declare function createMockSyncEngine(result?: SyncResult): SyncEngine;
|
|
16
|
+
export declare function createMockConfigRepo(overrides?: {
|
|
17
|
+
enabled?: boolean;
|
|
18
|
+
lastSyncAt?: string | null;
|
|
19
|
+
isSyncDue?: boolean;
|
|
20
|
+
}): SyncConfigRepository;
|
|
13
21
|
//# sourceMappingURL=BackgroundSyncService.test.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BackgroundSyncService.test.d.ts","sourceRoot":"","sources":["../../../tests/sync/BackgroundSyncService.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
1
|
+
{"version":3,"file":"BackgroundSyncService.test.d.ts","sourceRoot":"","sources":["../../../tests/sync/BackgroundSyncService.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AAC1E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAA;AAqB1F,wBAAgB,oBAAoB,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU,CAYhF;AAED,wBAAgB,oBAAoB,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,UAAU,CAIpE;AAED,wBAAgB,oBAAoB,CAAC,SAAS,CAAC,EAAE;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,GAAG,oBAAoB,CAcvB"}
|
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
13
13
|
import { BackgroundSyncService, createBackgroundSyncService, } from '../../src/sync/BackgroundSyncService.js';
|
|
14
|
+
// SMI-5649: BackgroundSyncService.abort.test.ts covers the new
|
|
15
|
+
// abort/awaitable-stop() behavior and the default onSyncError logging
|
|
16
|
+
// (which requires mocking `createLogger` before module load — split there
|
|
17
|
+
// to avoid an unused mock in this file, and to stay under the 500-LOC
|
|
18
|
+
// file-size gate).
|
|
14
19
|
/** Flush microtask queue so fire-and-forget promises resolve */
|
|
15
20
|
function flushPromises() {
|
|
16
21
|
return new Promise((resolve) => setImmediate(resolve));
|
|
@@ -18,7 +23,7 @@ function flushPromises() {
|
|
|
18
23
|
// ============================================================================
|
|
19
24
|
// Mock Factories
|
|
20
25
|
// ============================================================================
|
|
21
|
-
function createMockSyncResult(overrides) {
|
|
26
|
+
export function createMockSyncResult(overrides) {
|
|
22
27
|
return {
|
|
23
28
|
success: true,
|
|
24
29
|
skillsAdded: 2,
|
|
@@ -31,12 +36,12 @@ function createMockSyncResult(overrides) {
|
|
|
31
36
|
...overrides,
|
|
32
37
|
};
|
|
33
38
|
}
|
|
34
|
-
function createMockSyncEngine(result) {
|
|
39
|
+
export function createMockSyncEngine(result) {
|
|
35
40
|
return {
|
|
36
41
|
sync: vi.fn().mockResolvedValue(result ?? createMockSyncResult()),
|
|
37
42
|
};
|
|
38
43
|
}
|
|
39
|
-
function createMockConfigRepo(overrides) {
|
|
44
|
+
export function createMockConfigRepo(overrides) {
|
|
40
45
|
const enabled = overrides?.enabled ?? true;
|
|
41
46
|
const lastSyncAt = overrides?.lastSyncAt ?? '2026-03-16T00:00:00Z';
|
|
42
47
|
const isSyncDue = overrides?.isSyncDue ?? false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BackgroundSyncService.test.js","sourceRoot":"","sources":["../../../tests/sync/BackgroundSyncService.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"BackgroundSyncService.test.js","sourceRoot":"","sources":["../../../tests/sync/BackgroundSyncService.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAGxE,OAAO,EACL,qBAAqB,EACrB,2BAA2B,GAC5B,MAAM,yCAAyC,CAAA;AAEhD,+DAA+D;AAC/D,sEAAsE;AACtE,0EAA0E;AAC1E,sEAAsE;AACtE,mBAAmB;AAEnB,gEAAgE;AAChE,SAAS,aAAa;IACpB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAA;AACxD,CAAC;AAED,+EAA+E;AAC/E,iBAAiB;AACjB,+EAA+E;AAE/E,MAAM,UAAU,oBAAoB,CAAC,SAA+B;IAClE,OAAO;QACL,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,CAAC;QACd,aAAa,EAAE,CAAC;QAChB,eAAe,EAAE,EAAE;QACnB,cAAc,EAAE,EAAE;QAClB,UAAU,EAAE,GAAG;QACf,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,KAAK;QACb,GAAG,SAAS;KACb,CAAA;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAmB;IACtD,OAAO;QACL,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,MAAM,IAAI,oBAAoB,EAAE,CAAC;KACzC,CAAA;AAC5B,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,SAIpC;IACC,MAAM,OAAO,GAAG,SAAS,EAAE,OAAO,IAAI,IAAI,CAAA;IAC1C,MAAM,UAAU,GAAG,SAAS,EAAE,UAAU,IAAI,sBAAsB,CAAA;IAClE,MAAM,SAAS,GAAG,SAAS,EAAE,SAAS,IAAI,KAAK,CAAA;IAE/C,OAAO;QACL,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC;YACjC,OAAO;YACP,SAAS,EAAE,OAAO;YAClB,UAAU,EAAE,QAAQ;YACpB,UAAU;SACX,CAAC;QACF,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,SAAS,CAAC;KACX,CAAA;AACtC,CAAC;AAED,+EAA+E;AAC/E,QAAQ;AACR,+EAA+E;AAE/E,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAA;IACpB,CAAC,CAAC,CAAA;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,aAAa,EAAE,CAAA;IACpB,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;QACpC,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;YAC3C,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC,oBAAoB,EAAE,EAAE,oBAAoB,EAAE,EAAE;gBACxF,WAAW,EAAE,KAAK;aACnB,CAAC,CAAA;YAEF,OAAO,CAAC,KAAK,EAAE,CAAA;YACf,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAE7C,OAAO,CAAC,IAAI,EAAE,CAAA;YACd,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAChD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,OAAO,GAAG,IAAI,qBAAqB,CACvC,oBAAoB,EAAE,EACtB,oBAAoB,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EACxC,EAAE,WAAW,EAAE,KAAK,EAAE,CACvB,CAAA;YAED,OAAO,CAAC,KAAK,EAAE,CAAA;YACf,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAChD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC,oBAAoB,EAAE,EAAE,oBAAoB,EAAE,EAAE;gBACxF,WAAW,EAAE,KAAK;aACnB,CAAC,CAAA;YAEF,OAAO,CAAC,KAAK,EAAE,CAAA;YACf,OAAO,CAAC,KAAK,EAAE,CAAA,CAAC,mBAAmB;YACnC,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAE7C,OAAO,CAAC,IAAI,EAAE,CAAA;QAChB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,mEAAmE;QACnE,oDAAoD;QACpD,UAAU,CAAC,GAAG,EAAE;YACd,EAAE,CAAC,aAAa,EAAE,CAAA;QACpB,CAAC,CAAC,CAAA;QACF,SAAS,CAAC,GAAG,EAAE;YACb,EAAE,CAAC,aAAa,EAAE,CAAA;QACpB,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;YAC/D,MAAM,MAAM,GAAG,oBAAoB,EAAE,CAAA;YACrC,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC,MAAM,EAAE,oBAAoB,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE;gBAC3F,WAAW,EAAE,IAAI;aAClB,CAAC,CAAA;YAEF,OAAO,CAAC,KAAK,EAAE,CAAA;YACf,MAAM,aAAa,EAAE,CAAA;YAErB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,oBAAoB,EAAE,CAAA;YAC1C,OAAO,CAAC,IAAI,EAAE,CAAA;QAChB,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YAC3D,MAAM,MAAM,GAAG,oBAAoB,EAAE,CAAA;YACrC,MAAM,OAAO,GAAG,IAAI,qBAAqB,CACvC,MAAM,EACN,oBAAoB,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,EAC1C,EAAE,WAAW,EAAE,IAAI,EAAE,CACtB,CAAA;YAED,OAAO,CAAC,KAAK,EAAE,CAAA;YACf,MAAM,aAAa,EAAE,CAAA;YAErB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAA;YAC1C,OAAO,CAAC,IAAI,EAAE,CAAA;QAChB,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;YACrE,kEAAkE;YAClE,0EAA0E;YAC1E,MAAM,MAAM,GAAG,oBAAoB,EAAE,CAAA;YACrC,MAAM,OAAO,GAAG,IAAI,qBAAqB,CACvC,MAAM,EACN,oBAAoB,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,EAC1C,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,2CAA2C;aACnE,CAAA;YAED,oEAAoE;YACpE,MAAM,WAAW,GAAG,OAAO,CAAC,UAAU,EAAE,CAAA;YACxC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,oBAAoB,EAAE,CAAA;YAC1C,OAAO,WAAW,CAAA;QACpB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC/B,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;YACjD,MAAM,MAAM,GAAG,oBAAoB,EAAE,CAAA;YACrC,MAAM,UAAU,GAAG,oBAAoB,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAA;YAC7D,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC,MAAM,EAAE,UAAU,EAAE;gBAC5D,WAAW,EAAE,KAAK;gBAClB,eAAe,EAAE,IAAI;aACtB,CAAC,CAAA;YAEF,OAAO,CAAC,KAAK,EAAE,CAAA;YAEf,2BAA2B;YAC3B,MAAM,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAA;YACvC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAGzC;YAAC,UAAU,CAAC,SAAsC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;YAEzE,MAAM,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAA;YACvC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,oBAAoB,EAAE,CAAA;YAE1C,OAAO,CAAC,IAAI,EAAE,CAAA;QAChB,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;YAC1C,MAAM,MAAM,GAAG,oBAAoB,EAAE,CAAA;YACrC,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC,MAAM,EAAE,oBAAoB,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE;gBAC3F,WAAW,EAAE,KAAK;gBAClB,eAAe,EAAE,IAAI;aACtB,CAAC,CAAA;YAEF,OAAO,CAAC,KAAK,EAAE,CAAA;YACf,OAAO,CAAC,IAAI,EAAE,CAAA;YAEd,MAAM,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAA;YACvC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAA;QAC5C,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,UAAU,CAAC,GAAG,EAAE;YACd,EAAE,CAAC,aAAa,EAAE,CAAA;QACpB,CAAC,CAAC,CAAA;QACF,SAAS,CAAC,GAAG,EAAE;YACb,EAAE,CAAC,aAAa,EAAE,CAAA;QACpB,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;YACrD,MAAM,UAAU,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;YAC1B,MAAM,MAAM,GAAG,oBAAoB,EAAE,CAAA;YACrC,MAAM,OAAO,GAAG,IAAI,qBAAqB,CACvC,oBAAoB,CAAC,MAAM,CAAC,EAC5B,oBAAoB,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EACzC,EAAE,WAAW,EAAE,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE,CAClD,CAAA;YAED,OAAO,CAAC,KAAK,EAAE,CAAA;YACf,MAAM,aAAa,EAAE,CAAA;YAErB,MAAM,CAAC,UAAU,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAA;YAC/C,OAAO,CAAC,IAAI,EAAE,CAAA;QAChB,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;YACvB,MAAM,MAAM,GAAG;gBACb,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;aACrC,CAAA;YAE1B,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC,MAAM,EAAE,oBAAoB,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE;gBAC3F,WAAW,EAAE,IAAI;gBACjB,WAAW,EAAE,OAAO;aACrB,CAAC,CAAA;YAEF,OAAO,CAAC,KAAK,EAAE,CAAA;YACf,MAAM,aAAa,EAAE,CAAA;YAErB,MAAM,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAA;YAC7F,OAAO,CAAC,IAAI,EAAE,CAAA;QAChB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;QAC1B,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;YACrD,MAAM,MAAM,GAAG,oBAAoB,EAAE,CAAA;YACrC,MAAM,OAAO,GAAG,IAAI,qBAAqB,CACvC,oBAAoB,CAAC,MAAM,CAAC,EAC5B,oBAAoB,EAAE,EACtB,EAAE,WAAW,EAAE,KAAK,EAAE,CACvB,CAAA;YAED,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,UAAU,EAAE,CAAA;YAC7C,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;QACpC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;YACxD,IAAI,WAAuB,CAAA;YAC3B,MAAM,MAAM,GAAG;gBACb,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAC3B,IAAI,OAAO,CAAa,CAAC,OAAO,EAAE,EAAE;oBAClC,WAAW,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAA;gBACrD,CAAC,CAAC,CACH;aACuB,CAAA;YAE1B,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC,MAAM,EAAE,oBAAoB,EAAE,EAAE;gBACxE,WAAW,EAAE,KAAK;aACnB,CAAC,CAAA;YAEF,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,EAAE,CAAA;YACtC,MAAM,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAA;YAE9E,WAAY,EAAE,CAAA;YACd,MAAM,SAAS,CAAA;QACjB,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;YAC5C,MAAM,MAAM,GAAG;gBACb,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC;aAC/B,CAAA;YAE1B,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC,MAAM,EAAE,oBAAoB,EAAE,EAAE;gBACxE,WAAW,EAAE,KAAK;aACnB,CAAC,CAAA;YAEF,MAAM,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;QACjE,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;YAC/D,MAAM,OAAO,GAAG,IAAI,qBAAqB,CACvC,oBAAoB,EAAE,EACtB,oBAAoB,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EACzC,EAAE,WAAW,EAAE,KAAK,EAAE,eAAe,EAAE,GAAG,EAAE,CAC7C,CAAA;YAED,OAAO,CAAC,KAAK,EAAE,CAAA;YAEf,MAAM,EAAE,CAAC,wBAAwB,CAAC,GAAG,CAAC,CAAA;YACtC,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAA;YAChC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACrC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YAEpC,OAAO,CAAC,IAAI,EAAE,CAAA;QAChB,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,MAAM,GAAG,oBAAoB,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAAA;YACvD,MAAM,OAAO,GAAG,IAAI,qBAAqB,CACvC,oBAAoB,CAAC,MAAM,CAAC,EAC5B,oBAAoB,EAAE,EACtB,EAAE,WAAW,EAAE,KAAK,EAAE,CACvB,CAAA;YAED,MAAM,OAAO,CAAC,UAAU,EAAE,CAAA;YAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAA;YAChC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;YACxC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAA;QACpC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;YACxD,MAAM,MAAM,GAAG;gBACb,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC;aAC1B,CAAA;YAE1B,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC,MAAM,EAAE,oBAAoB,EAAE,EAAE;gBACxE,WAAW,EAAE,KAAK;aACnB,CAAC,CAAA;YAEF,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YAC1C,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAA;YAChC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC/C,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,qCAAqC,EAAE,GAAG,EAAE;QACnD,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,OAAO,GAAG,2BAA2B,CAAC,oBAAoB,EAAE,EAAE,oBAAoB,EAAE,EAAE;gBAC1F,WAAW,EAAE,KAAK;aACnB,CAAC,CAAA;YAEF,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC7C,OAAO,CAAC,IAAI,EAAE,CAAA;QAChB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SyncEngine Tests — abort-signal threading (SMI-5649)
|
|
3
|
+
*
|
|
4
|
+
* Split from SyncEngine.test.ts to stay under the 500-LOC file-size gate.
|
|
5
|
+
* Reuses that file's mock factories (createMockSkill, createMockApiClient,
|
|
6
|
+
* createMockSkillVersionRepo — exported there for this purpose).
|
|
7
|
+
*
|
|
8
|
+
* The load-bearing safety property under test: once `signal.aborted` is
|
|
9
|
+
* true, NO NEW db write ever begins — checked at loop/write boundaries
|
|
10
|
+
* (search-query loop, pagination loop, pre-upsert, per-skill upsert loop).
|
|
11
|
+
* Every write already issued before the abort checkpoint is a real,
|
|
12
|
+
* committed write; nothing already in flight is rolled back.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=SyncEngine.abort.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SyncEngine.abort.test.d.ts","sourceRoot":"","sources":["../../../tests/sync/SyncEngine.abort.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SyncEngine Tests — abort-signal threading (SMI-5649)
|
|
3
|
+
*
|
|
4
|
+
* Split from SyncEngine.test.ts to stay under the 500-LOC file-size gate.
|
|
5
|
+
* Reuses that file's mock factories (createMockSkill, createMockApiClient,
|
|
6
|
+
* createMockSkillVersionRepo — exported there for this purpose).
|
|
7
|
+
*
|
|
8
|
+
* The load-bearing safety property under test: once `signal.aborted` is
|
|
9
|
+
* true, NO NEW db write ever begins — checked at loop/write boundaries
|
|
10
|
+
* (search-query loop, pagination loop, pre-upsert, per-skill upsert loop).
|
|
11
|
+
* Every write already issued before the abort checkpoint is a real,
|
|
12
|
+
* committed write; nothing already in flight is rolled back.
|
|
13
|
+
*/
|
|
14
|
+
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
|
|
15
|
+
import { createDatabase, closeDatabase } from '../../src/db/schema.js';
|
|
16
|
+
import { SyncConfigRepository } from '../../src/repositories/SyncConfigRepository.js';
|
|
17
|
+
import { SyncHistoryRepository } from '../../src/repositories/SyncHistoryRepository.js';
|
|
18
|
+
import { SkillRepository } from '../../src/repositories/SkillRepository.js';
|
|
19
|
+
import { SyncEngine } from '../../src/sync/SyncEngine.js';
|
|
20
|
+
import { createMockSkillVersionRepo, createMockSkill, createMockApiClient, } from './SyncEngine.test.js';
|
|
21
|
+
describe('SyncEngine - abort signal (SMI-5649)', () => {
|
|
22
|
+
let db;
|
|
23
|
+
let syncConfigRepo;
|
|
24
|
+
let syncHistoryRepo;
|
|
25
|
+
let skillRepo;
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
db = createDatabase(':memory:');
|
|
28
|
+
syncConfigRepo = new SyncConfigRepository(db);
|
|
29
|
+
syncHistoryRepo = new SyncHistoryRepository(db);
|
|
30
|
+
skillRepo = new SkillRepository(db);
|
|
31
|
+
});
|
|
32
|
+
afterEach(() => {
|
|
33
|
+
closeDatabase(db);
|
|
34
|
+
});
|
|
35
|
+
it('performs no writes and returns a clean result when the signal is already aborted', async () => {
|
|
36
|
+
const skills = [createMockSkill('test/skill-1'), createMockSkill('test/skill-2')];
|
|
37
|
+
const apiClient = createMockApiClient({ skills });
|
|
38
|
+
const engine = new SyncEngine(apiClient, skillRepo, syncConfigRepo, syncHistoryRepo, createMockSkillVersionRepo());
|
|
39
|
+
const controller = new AbortController();
|
|
40
|
+
controller.abort();
|
|
41
|
+
const result = await engine.sync({ signal: controller.signal });
|
|
42
|
+
// Never throws — an abort surfaces as a clean, successful-shaped
|
|
43
|
+
// result, not an error (design doc §2.1).
|
|
44
|
+
expect(result.success).toBe(true);
|
|
45
|
+
expect(result.skillsAdded).toBe(0);
|
|
46
|
+
expect(result.skillsUpdated).toBe(0);
|
|
47
|
+
expect(skillRepo.findById('test/skill-1')).toBeNull();
|
|
48
|
+
expect(skillRepo.findById('test/skill-2')).toBeNull();
|
|
49
|
+
});
|
|
50
|
+
it('stops issuing new skillRepo writes once aborted mid-upsert, keeping already-committed writes', async () => {
|
|
51
|
+
const skills = [
|
|
52
|
+
createMockSkill('test/skill-1'),
|
|
53
|
+
createMockSkill('test/skill-2'),
|
|
54
|
+
createMockSkill('test/skill-3'),
|
|
55
|
+
];
|
|
56
|
+
const apiClient = createMockApiClient({ skills });
|
|
57
|
+
const engine = new SyncEngine(apiClient, skillRepo, syncConfigRepo, syncHistoryRepo, createMockSkillVersionRepo());
|
|
58
|
+
const controller = new AbortController();
|
|
59
|
+
let createCount = 0;
|
|
60
|
+
const originalCreate = skillRepo.create.bind(skillRepo);
|
|
61
|
+
vi.spyOn(skillRepo, 'create').mockImplementation((...args) => {
|
|
62
|
+
createCount++;
|
|
63
|
+
const result = originalCreate(...args);
|
|
64
|
+
if (createCount === 1) {
|
|
65
|
+
// Abort right after the first skill commits — the per-skill loop's
|
|
66
|
+
// abort checkpoint must stop before issuing a second create().
|
|
67
|
+
controller.abort();
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
});
|
|
71
|
+
const result = await engine.sync({ signal: controller.signal });
|
|
72
|
+
expect(createCount).toBe(1);
|
|
73
|
+
expect(skillRepo.findById('test/skill-1')).not.toBeNull();
|
|
74
|
+
expect(skillRepo.findById('test/skill-2')).toBeNull();
|
|
75
|
+
expect(skillRepo.findById('test/skill-3')).toBeNull();
|
|
76
|
+
expect(result.success).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
it('stops fetching new pages once aborted mid-fetch', async () => {
|
|
79
|
+
const skills = Array.from({ length: 150 }, (_, i) => createMockSkill(`test/skill-${i}`));
|
|
80
|
+
const apiClient = createMockApiClient({ skills });
|
|
81
|
+
const engine = new SyncEngine(apiClient, skillRepo, syncConfigRepo, syncHistoryRepo, createMockSkillVersionRepo());
|
|
82
|
+
const controller = new AbortController();
|
|
83
|
+
let searchCallCount = 0;
|
|
84
|
+
const searchMock = apiClient.search;
|
|
85
|
+
const originalImpl = searchMock.getMockImplementation();
|
|
86
|
+
searchMock.mockImplementation((opts) => {
|
|
87
|
+
searchCallCount++;
|
|
88
|
+
if (searchCallCount === 3) {
|
|
89
|
+
controller.abort();
|
|
90
|
+
}
|
|
91
|
+
return originalImpl(opts);
|
|
92
|
+
});
|
|
93
|
+
await engine.sync({ signal: controller.signal, pageSize: 100 });
|
|
94
|
+
// Unaborted, this fixture makes 16 search calls (8 queries x 2 pages
|
|
95
|
+
// each — see the pagination test in SyncEngine.test.ts). Aborting on
|
|
96
|
+
// the 3rd call must stop the loop well short of that.
|
|
97
|
+
expect(searchCallCount).toBeLessThan(16);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
//# sourceMappingURL=SyncEngine.abort.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SyncEngine.abort.test.js","sourceRoot":"","sources":["../../../tests/sync/SyncEngine.abort.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AACxE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAA;AACrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,iDAAiD,CAAA;AACvF,OAAO,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAA;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AAGzD,OAAO,EACL,0BAA0B,EAC1B,eAAe,EACf,mBAAmB,GACpB,MAAM,sBAAsB,CAAA;AAE7B,QAAQ,CAAC,sCAAsC,EAAE,GAAG,EAAE;IACpD,IAAI,EAAgB,CAAA;IACpB,IAAI,cAAoC,CAAA;IACxC,IAAI,eAAsC,CAAA;IAC1C,IAAI,SAA0B,CAAA;IAE9B,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,GAAG,cAAc,CAAC,UAAU,CAAC,CAAA;QAC/B,cAAc,GAAG,IAAI,oBAAoB,CAAC,EAAE,CAAC,CAAA;QAC7C,eAAe,GAAG,IAAI,qBAAqB,CAAC,EAAE,CAAC,CAAA;QAC/C,SAAS,GAAG,IAAI,eAAe,CAAC,EAAE,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,aAAa,CAAC,EAAE,CAAC,CAAA;IACnB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kFAAkF,EAAE,KAAK,IAAI,EAAE;QAChG,MAAM,MAAM,GAAG,CAAC,eAAe,CAAC,cAAc,CAAC,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC,CAAA;QACjF,MAAM,SAAS,GAAG,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;QACjD,MAAM,MAAM,GAAG,IAAI,UAAU,CAC3B,SAAS,EACT,SAAS,EACT,cAAc,EACd,eAAe,EACf,0BAA0B,EAAE,CAC7B,CAAA;QAED,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QACxC,UAAU,CAAC,KAAK,EAAE,CAAA;QAElB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAA;QAE/D,iEAAiE;QACjE,0CAA0C;QAC1C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAClC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACpC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QACrD,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;IACvD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8FAA8F,EAAE,KAAK,IAAI,EAAE;QAC5G,MAAM,MAAM,GAAG;YACb,eAAe,CAAC,cAAc,CAAC;YAC/B,eAAe,CAAC,cAAc,CAAC;YAC/B,eAAe,CAAC,cAAc,CAAC;SAChC,CAAA;QACD,MAAM,SAAS,GAAG,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;QACjD,MAAM,MAAM,GAAG,IAAI,UAAU,CAC3B,SAAS,EACT,SAAS,EACT,cAAc,EACd,eAAe,EACf,0BAA0B,EAAE,CAC7B,CAAA;QAED,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QACxC,IAAI,WAAW,GAAG,CAAC,CAAA;QACnB,MAAM,cAAc,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACvD,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,kBAAkB,CAC9C,CAAC,GAAG,IAAyC,EAAE,EAAE;YAC/C,WAAW,EAAE,CAAA;YACb,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,IAAI,CAAC,CAAA;YACtC,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;gBACtB,mEAAmE;gBACnE,+DAA+D;gBAC/D,UAAU,CAAC,KAAK,EAAE,CAAA;YACpB,CAAC;YACD,OAAO,MAAM,CAAA;QACf,CAAC,CACF,CAAA;QAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAA;QAE/D,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAC3B,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;QACzD,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QACrD,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QACrD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAA;QACxF,MAAM,SAAS,GAAG,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;QACjD,MAAM,MAAM,GAAG,IAAI,UAAU,CAC3B,SAAS,EACT,SAAS,EACT,cAAc,EACd,eAAe,EACf,0BAA0B,EAAE,CAC7B,CAAA;QAED,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QACxC,IAAI,eAAe,GAAG,CAAC,CAAA;QACvB,MAAM,UAAU,GAAG,SAAS,CAAC,MAAkC,CAAA;QAC/D,MAAM,YAAY,GAAG,UAAU,CAAC,qBAAqB,EAEP,CAAA;QAC9C,UAAU,CAAC,kBAAkB,CAAC,CAAC,IAAkD,EAAE,EAAE;YACnF,eAAe,EAAE,CAAA;YACjB,IAAI,eAAe,KAAK,CAAC,EAAE,CAAC;gBAC1B,UAAU,CAAC,KAAK,EAAE,CAAA;YACpB,CAAC;YACD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAA;QAC3B,CAAC,CAAC,CAAA;QAEF,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAA;QAE/D,qEAAqE;QACrE,qEAAqE;QACrE,sDAAsD;QACtD,MAAM,CAAC,eAAe,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;IAC1C,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SyncEngine Tests — history tracking + getStatus
|
|
3
|
+
*
|
|
4
|
+
* Split from SyncEngine.test.ts (pre-existing at 508 lines, over the
|
|
5
|
+
* 500-LOC file-size gate, before any SMI-5649 changes) to bring both files
|
|
6
|
+
* under the limit. Reuses that file's mock factories (createMockSkill,
|
|
7
|
+
* createMockApiClient, createMockSkillVersionRepo — exported there).
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=SyncEngine.status.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SyncEngine.status.test.d.ts","sourceRoot":"","sources":["../../../tests/sync/SyncEngine.status.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SyncEngine Tests — history tracking + getStatus
|
|
3
|
+
*
|
|
4
|
+
* Split from SyncEngine.test.ts (pre-existing at 508 lines, over the
|
|
5
|
+
* 500-LOC file-size gate, before any SMI-5649 changes) to bring both files
|
|
6
|
+
* under the limit. Reuses that file's mock factories (createMockSkill,
|
|
7
|
+
* createMockApiClient, createMockSkillVersionRepo — exported there).
|
|
8
|
+
*/
|
|
9
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
10
|
+
import { createDatabase, closeDatabase } from '../../src/db/schema.js';
|
|
11
|
+
import { SyncConfigRepository } from '../../src/repositories/SyncConfigRepository.js';
|
|
12
|
+
import { SyncHistoryRepository } from '../../src/repositories/SyncHistoryRepository.js';
|
|
13
|
+
import { SkillRepository } from '../../src/repositories/SkillRepository.js';
|
|
14
|
+
import { SyncEngine } from '../../src/sync/SyncEngine.js';
|
|
15
|
+
import { createMockSkillVersionRepo, createMockSkill, createMockApiClient, } from './SyncEngine.test.js';
|
|
16
|
+
describe('SyncEngine - history tracking + getStatus', () => {
|
|
17
|
+
let db;
|
|
18
|
+
let syncConfigRepo;
|
|
19
|
+
let syncHistoryRepo;
|
|
20
|
+
let skillRepo;
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
db = createDatabase(':memory:');
|
|
23
|
+
syncConfigRepo = new SyncConfigRepository(db);
|
|
24
|
+
syncHistoryRepo = new SyncHistoryRepository(db);
|
|
25
|
+
skillRepo = new SkillRepository(db);
|
|
26
|
+
});
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
closeDatabase(db);
|
|
29
|
+
});
|
|
30
|
+
describe('sync - history tracking', () => {
|
|
31
|
+
it('should record sync history on success', async () => {
|
|
32
|
+
const skills = [createMockSkill('test/skill-1')];
|
|
33
|
+
const apiClient = createMockApiClient({ skills });
|
|
34
|
+
const engine = new SyncEngine(apiClient, skillRepo, syncConfigRepo, syncHistoryRepo, createMockSkillVersionRepo());
|
|
35
|
+
await engine.sync();
|
|
36
|
+
const history = syncHistoryRepo.getHistory();
|
|
37
|
+
expect(history).toHaveLength(1);
|
|
38
|
+
expect(history[0].status).toBe('success');
|
|
39
|
+
expect(history[0].skillsAdded).toBe(1);
|
|
40
|
+
});
|
|
41
|
+
it('should record sync history on failure', async () => {
|
|
42
|
+
const apiClient = createMockApiClient({
|
|
43
|
+
throwOnSearch: new Error('Network failure'),
|
|
44
|
+
});
|
|
45
|
+
const engine = new SyncEngine(apiClient, skillRepo, syncConfigRepo, syncHistoryRepo, createMockSkillVersionRepo());
|
|
46
|
+
await engine.sync();
|
|
47
|
+
const history = syncHistoryRepo.getHistory();
|
|
48
|
+
expect(history).toHaveLength(1);
|
|
49
|
+
expect(history[0].status).toBe('failed');
|
|
50
|
+
expect(history[0].errorMessage).toContain('Network failure');
|
|
51
|
+
});
|
|
52
|
+
it('should update sync config on success', async () => {
|
|
53
|
+
const skills = [createMockSkill('test/skill-1')];
|
|
54
|
+
const apiClient = createMockApiClient({ skills });
|
|
55
|
+
const engine = new SyncEngine(apiClient, skillRepo, syncConfigRepo, syncHistoryRepo, createMockSkillVersionRepo());
|
|
56
|
+
await engine.sync();
|
|
57
|
+
const config = syncConfigRepo.getConfig();
|
|
58
|
+
expect(config.lastSyncAt).not.toBeNull();
|
|
59
|
+
expect(config.lastSyncCount).toBe(1);
|
|
60
|
+
expect(config.lastSyncError).toBeNull();
|
|
61
|
+
});
|
|
62
|
+
it('should set error in config on failure', async () => {
|
|
63
|
+
const apiClient = createMockApiClient({ offline: true });
|
|
64
|
+
const engine = new SyncEngine(apiClient, skillRepo, syncConfigRepo, syncHistoryRepo, createMockSkillVersionRepo());
|
|
65
|
+
await engine.sync();
|
|
66
|
+
const config = syncConfigRepo.getConfig();
|
|
67
|
+
expect(config.lastSyncError).toBe('API client is in offline mode. Cannot sync.');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe('getStatus', () => {
|
|
71
|
+
it('should return sync status summary', () => {
|
|
72
|
+
const apiClient = createMockApiClient();
|
|
73
|
+
const engine = new SyncEngine(apiClient, skillRepo, syncConfigRepo, syncHistoryRepo, createMockSkillVersionRepo());
|
|
74
|
+
const status = engine.getStatus();
|
|
75
|
+
expect(status).toHaveProperty('config');
|
|
76
|
+
expect(status).toHaveProperty('lastRun');
|
|
77
|
+
expect(status).toHaveProperty('isRunning');
|
|
78
|
+
expect(status).toHaveProperty('isDue');
|
|
79
|
+
});
|
|
80
|
+
it('should show sync is due when never synced', () => {
|
|
81
|
+
const apiClient = createMockApiClient();
|
|
82
|
+
const engine = new SyncEngine(apiClient, skillRepo, syncConfigRepo, syncHistoryRepo, createMockSkillVersionRepo());
|
|
83
|
+
const status = engine.getStatus();
|
|
84
|
+
expect(status.isDue).toBe(true);
|
|
85
|
+
expect(status.lastRun).toBeNull();
|
|
86
|
+
});
|
|
87
|
+
it('should reflect running state', async () => {
|
|
88
|
+
const apiClient = createMockApiClient();
|
|
89
|
+
const engine = new SyncEngine(apiClient, skillRepo, syncConfigRepo, syncHistoryRepo, createMockSkillVersionRepo());
|
|
90
|
+
// Start a run manually
|
|
91
|
+
syncHistoryRepo.startRun();
|
|
92
|
+
const status = engine.getStatus();
|
|
93
|
+
expect(status.isRunning).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=SyncEngine.status.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SyncEngine.status.test.js","sourceRoot":"","sources":["../../../tests/sync/SyncEngine.status.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,5 +3,26 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Tests for the core sync engine with mocked dependencies.
|
|
5
5
|
*/
|
|
6
|
-
|
|
6
|
+
import type { SkillVersionRepository } from '../../src/repositories/SkillVersionRepository.js';
|
|
7
|
+
import type { SkillsmithApiClient, ApiSearchResult } from '../../src/api/client.js';
|
|
8
|
+
/**
|
|
9
|
+
* Create a mock SkillVersionRepository for testing.
|
|
10
|
+
* All methods return resolved promises so SyncEngine can call recordVersion
|
|
11
|
+
* after each upsert without errors.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createMockSkillVersionRepo(): SkillVersionRepository;
|
|
14
|
+
/**
|
|
15
|
+
* Create a mock skill for testing
|
|
16
|
+
* Note: quality_score must be between 0 and 1 (database constraint)
|
|
17
|
+
*/
|
|
18
|
+
export declare function createMockSkill(id: string, updatedAt?: string): ApiSearchResult;
|
|
19
|
+
/**
|
|
20
|
+
* Create a mock API client with customizable behavior
|
|
21
|
+
*/
|
|
22
|
+
export declare function createMockApiClient(config?: {
|
|
23
|
+
offline?: boolean;
|
|
24
|
+
healthStatus?: 'healthy' | 'degraded' | 'unhealthy';
|
|
25
|
+
skills?: ApiSearchResult[];
|
|
26
|
+
throwOnSearch?: Error;
|
|
27
|
+
}): SkillsmithApiClient;
|
|
7
28
|
//# sourceMappingURL=SyncEngine.test.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SyncEngine.test.d.ts","sourceRoot":"","sources":["../../../tests/sync/SyncEngine.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
1
|
+
{"version":3,"file":"SyncEngine.test.d.ts","sourceRoot":"","sources":["../../../tests/sync/SyncEngine.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kDAAkD,CAAA;AAE9F,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAEnF;;;;GAIG;AACH,wBAAgB,0BAA0B,IAAI,sBAAsB,CAQnE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,MAAM,EACV,SAAS,GAAE,MAAiC,GAC3C,eAAe,CAejB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,GAAE;IACN,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,YAAY,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,CAAA;IACnD,MAAM,CAAC,EAAE,eAAe,EAAE,CAAA;IAC1B,aAAa,CAAC,EAAE,KAAK,CAAA;CACjB,GACL,mBAAmB,CAuBrB"}
|