@elaraai/e3-core 0.0.2-beta.8 → 1.0.0
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/LICENSE.md +4 -0
- package/README.md +74 -35
- package/dist/src/dataflow/api-compat.d.ts +90 -0
- package/dist/src/dataflow/api-compat.d.ts.map +1 -0
- package/dist/src/dataflow/api-compat.js +139 -0
- package/dist/src/dataflow/api-compat.js.map +1 -0
- package/dist/src/dataflow/api-compat.spec.d.ts +6 -0
- package/dist/src/dataflow/api-compat.spec.d.ts.map +1 -0
- package/dist/src/dataflow/api-compat.spec.js +182 -0
- package/dist/src/dataflow/api-compat.spec.js.map +1 -0
- package/dist/src/dataflow/index.d.ts +18 -0
- package/dist/src/dataflow/index.d.ts.map +1 -0
- package/dist/src/dataflow/index.js +23 -0
- package/dist/src/dataflow/index.js.map +1 -0
- package/dist/src/dataflow/orchestrator/LocalOrchestrator.d.ts +76 -0
- package/dist/src/dataflow/orchestrator/LocalOrchestrator.d.ts.map +1 -0
- package/dist/src/dataflow/orchestrator/LocalOrchestrator.js +729 -0
- package/dist/src/dataflow/orchestrator/LocalOrchestrator.js.map +1 -0
- package/dist/src/dataflow/orchestrator/index.d.ts +12 -0
- package/dist/src/dataflow/orchestrator/index.d.ts.map +1 -0
- package/dist/src/dataflow/orchestrator/index.js +12 -0
- package/dist/src/dataflow/orchestrator/index.js.map +1 -0
- package/dist/src/dataflow/orchestrator/interfaces.d.ts +163 -0
- package/dist/src/dataflow/orchestrator/interfaces.d.ts.map +1 -0
- package/dist/src/dataflow/orchestrator/interfaces.js +52 -0
- package/dist/src/dataflow/orchestrator/interfaces.js.map +1 -0
- package/dist/src/dataflow/state-store/FileStateStore.d.ts +67 -0
- package/dist/src/dataflow/state-store/FileStateStore.d.ts.map +1 -0
- package/dist/src/dataflow/state-store/FileStateStore.js +300 -0
- package/dist/src/dataflow/state-store/FileStateStore.js.map +1 -0
- package/dist/src/dataflow/state-store/InMemoryStateStore.d.ts +42 -0
- package/dist/src/dataflow/state-store/InMemoryStateStore.d.ts.map +1 -0
- package/dist/src/dataflow/state-store/InMemoryStateStore.js +229 -0
- package/dist/src/dataflow/state-store/InMemoryStateStore.js.map +1 -0
- package/dist/src/dataflow/state-store/InMemoryStateStore.spec.d.ts +6 -0
- package/dist/src/dataflow/state-store/InMemoryStateStore.spec.d.ts.map +1 -0
- package/dist/src/dataflow/state-store/InMemoryStateStore.spec.js +114 -0
- package/dist/src/dataflow/state-store/InMemoryStateStore.spec.js.map +1 -0
- package/dist/src/dataflow/state-store/index.d.ts +13 -0
- package/dist/src/dataflow/state-store/index.d.ts.map +1 -0
- package/dist/src/dataflow/state-store/index.js +13 -0
- package/dist/src/dataflow/state-store/index.js.map +1 -0
- package/dist/src/dataflow/state-store/interfaces.d.ts +159 -0
- package/dist/src/dataflow/state-store/interfaces.d.ts.map +1 -0
- package/dist/src/dataflow/state-store/interfaces.js +6 -0
- package/dist/src/dataflow/state-store/interfaces.js.map +1 -0
- package/dist/src/dataflow/steps.d.ts +222 -0
- package/dist/src/dataflow/steps.d.ts.map +1 -0
- package/dist/src/dataflow/steps.js +707 -0
- package/dist/src/dataflow/steps.js.map +1 -0
- package/dist/src/dataflow/steps.spec.d.ts +6 -0
- package/dist/src/dataflow/steps.spec.d.ts.map +1 -0
- package/dist/src/dataflow/steps.spec.js +343 -0
- package/dist/src/dataflow/steps.spec.js.map +1 -0
- package/dist/src/dataflow/types.d.ts +127 -0
- package/dist/src/dataflow/types.d.ts.map +1 -0
- package/dist/src/dataflow/types.js +7 -0
- package/dist/src/dataflow/types.js.map +1 -0
- package/dist/src/dataflow-orchestration.spec.d.ts +6 -0
- package/dist/src/dataflow-orchestration.spec.d.ts.map +1 -0
- package/dist/src/dataflow-orchestration.spec.js +1025 -0
- package/dist/src/dataflow-orchestration.spec.js.map +1 -0
- package/dist/src/dataflow.d.ts +113 -38
- package/dist/src/dataflow.d.ts.map +1 -1
- package/dist/src/dataflow.js +269 -416
- package/dist/src/dataflow.js.map +1 -1
- package/dist/src/dataflow.spec.d.ts +6 -0
- package/dist/src/dataflow.spec.d.ts.map +1 -0
- package/dist/src/dataflow.spec.js +663 -0
- package/dist/src/dataflow.spec.js.map +1 -0
- package/dist/src/dataset-refs.d.ts +124 -0
- package/dist/src/dataset-refs.d.ts.map +1 -0
- package/dist/src/dataset-refs.js +319 -0
- package/dist/src/dataset-refs.js.map +1 -0
- package/dist/src/errors.d.ts +39 -9
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +51 -8
- package/dist/src/errors.js.map +1 -1
- package/dist/src/errors.spec.d.ts +6 -0
- package/dist/src/errors.spec.d.ts.map +1 -0
- package/dist/src/errors.spec.js +276 -0
- package/dist/src/errors.spec.js.map +1 -0
- package/dist/src/execution/LocalTaskRunner.d.ts +73 -0
- package/dist/src/execution/LocalTaskRunner.d.ts.map +1 -0
- package/dist/src/execution/LocalTaskRunner.js +399 -0
- package/dist/src/execution/LocalTaskRunner.js.map +1 -0
- package/dist/src/execution/MockTaskRunner.d.ts +49 -0
- package/dist/src/execution/MockTaskRunner.d.ts.map +1 -0
- package/dist/src/execution/MockTaskRunner.js +54 -0
- package/dist/src/execution/MockTaskRunner.js.map +1 -0
- package/dist/src/execution/index.d.ts +16 -0
- package/dist/src/execution/index.d.ts.map +1 -0
- package/dist/src/execution/index.js +8 -0
- package/dist/src/execution/index.js.map +1 -0
- package/dist/src/execution/interfaces.d.ts +246 -0
- package/dist/src/execution/interfaces.d.ts.map +1 -0
- package/dist/src/execution/interfaces.js +6 -0
- package/dist/src/execution/interfaces.js.map +1 -0
- package/dist/src/execution/processHelpers.d.ts +20 -0
- package/dist/src/execution/processHelpers.d.ts.map +1 -0
- package/dist/src/execution/processHelpers.js +62 -0
- package/dist/src/execution/processHelpers.js.map +1 -0
- package/dist/src/executions.d.ts +71 -104
- package/dist/src/executions.d.ts.map +1 -1
- package/dist/src/executions.js +113 -481
- package/dist/src/executions.js.map +1 -1
- package/dist/src/executions.spec.d.ts +6 -0
- package/dist/src/executions.spec.d.ts.map +1 -0
- package/dist/src/executions.spec.js +387 -0
- package/dist/src/executions.spec.js.map +1 -0
- package/dist/src/formats.d.ts +18 -2
- package/dist/src/formats.d.ts.map +1 -1
- package/dist/src/formats.js +34 -2
- package/dist/src/formats.js.map +1 -1
- package/dist/src/gc.spec.d.ts +6 -0
- package/dist/src/gc.spec.d.ts.map +1 -0
- package/dist/src/gc.spec.js +512 -0
- package/dist/src/gc.spec.js.map +1 -0
- package/dist/src/index.d.ts +20 -10
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +48 -18
- package/dist/src/index.js.map +1 -1
- package/dist/src/objects.d.ts +7 -53
- package/dist/src/objects.d.ts.map +1 -1
- package/dist/src/objects.js +13 -232
- package/dist/src/objects.js.map +1 -1
- package/dist/src/objects.spec.d.ts +6 -0
- package/dist/src/objects.spec.d.ts.map +1 -0
- package/dist/src/objects.spec.js +247 -0
- package/dist/src/objects.spec.js.map +1 -0
- package/dist/src/packages.d.ts +41 -14
- package/dist/src/packages.d.ts.map +1 -1
- package/dist/src/packages.js +151 -89
- package/dist/src/packages.js.map +1 -1
- package/dist/src/packages.spec.d.ts +6 -0
- package/dist/src/packages.spec.d.ts.map +1 -0
- package/dist/src/packages.spec.js +324 -0
- package/dist/src/packages.spec.js.map +1 -0
- package/dist/src/storage/in-memory/InMemoryRepoStore.d.ts +35 -0
- package/dist/src/storage/in-memory/InMemoryRepoStore.d.ts.map +1 -0
- package/dist/src/storage/in-memory/InMemoryRepoStore.js +107 -0
- package/dist/src/storage/in-memory/InMemoryRepoStore.js.map +1 -0
- package/dist/src/storage/in-memory/InMemoryRepoStore.spec.d.ts +6 -0
- package/dist/src/storage/in-memory/InMemoryRepoStore.spec.d.ts.map +1 -0
- package/dist/src/storage/in-memory/InMemoryRepoStore.spec.js +187 -0
- package/dist/src/storage/in-memory/InMemoryRepoStore.spec.js.map +1 -0
- package/dist/src/storage/in-memory/InMemoryStorage.d.ts +139 -0
- package/dist/src/storage/in-memory/InMemoryStorage.d.ts.map +1 -0
- package/dist/src/storage/in-memory/InMemoryStorage.js +439 -0
- package/dist/src/storage/in-memory/InMemoryStorage.js.map +1 -0
- package/dist/src/storage/in-memory/index.d.ts +12 -0
- package/dist/src/storage/in-memory/index.d.ts.map +1 -0
- package/dist/src/storage/in-memory/index.js +12 -0
- package/dist/src/storage/in-memory/index.js.map +1 -0
- package/dist/src/storage/index.d.ts +18 -0
- package/dist/src/storage/index.d.ts.map +1 -0
- package/dist/src/storage/index.js +10 -0
- package/dist/src/storage/index.js.map +1 -0
- package/dist/src/storage/interfaces.d.ts +581 -0
- package/dist/src/storage/interfaces.d.ts.map +1 -0
- package/dist/src/storage/interfaces.js +6 -0
- package/dist/src/storage/interfaces.js.map +1 -0
- package/dist/src/storage/local/LocalBackend.d.ts +56 -0
- package/dist/src/storage/local/LocalBackend.d.ts.map +1 -0
- package/dist/src/storage/local/LocalBackend.js +145 -0
- package/dist/src/storage/local/LocalBackend.js.map +1 -0
- package/dist/src/storage/local/LocalDatasetRefStore.d.ts +22 -0
- package/dist/src/storage/local/LocalDatasetRefStore.d.ts.map +1 -0
- package/dist/src/storage/local/LocalDatasetRefStore.js +118 -0
- package/dist/src/storage/local/LocalDatasetRefStore.js.map +1 -0
- package/dist/src/storage/local/LocalLockService.d.ts +111 -0
- package/dist/src/storage/local/LocalLockService.d.ts.map +1 -0
- package/dist/src/storage/local/LocalLockService.js +364 -0
- package/dist/src/storage/local/LocalLockService.js.map +1 -0
- package/dist/src/storage/local/LocalLockService.spec.d.ts +6 -0
- package/dist/src/storage/local/LocalLockService.spec.d.ts.map +1 -0
- package/dist/src/storage/local/LocalLockService.spec.js +148 -0
- package/dist/src/storage/local/LocalLockService.spec.js.map +1 -0
- package/dist/src/storage/local/LocalLogStore.d.ts +23 -0
- package/dist/src/storage/local/LocalLogStore.d.ts.map +1 -0
- package/dist/src/storage/local/LocalLogStore.js +66 -0
- package/dist/src/storage/local/LocalLogStore.js.map +1 -0
- package/dist/src/storage/local/LocalObjectStore.d.ts +55 -0
- package/dist/src/storage/local/LocalObjectStore.d.ts.map +1 -0
- package/dist/src/storage/local/LocalObjectStore.js +300 -0
- package/dist/src/storage/local/LocalObjectStore.js.map +1 -0
- package/dist/src/storage/local/LocalRefStore.d.ts +50 -0
- package/dist/src/storage/local/LocalRefStore.d.ts.map +1 -0
- package/dist/src/storage/local/LocalRefStore.js +337 -0
- package/dist/src/storage/local/LocalRefStore.js.map +1 -0
- package/dist/src/storage/local/LocalRepoStore.d.ts +55 -0
- package/dist/src/storage/local/LocalRepoStore.d.ts.map +1 -0
- package/dist/src/storage/local/LocalRepoStore.js +365 -0
- package/dist/src/storage/local/LocalRepoStore.js.map +1 -0
- package/dist/src/storage/local/LocalRepoStore.spec.d.ts +6 -0
- package/dist/src/storage/local/LocalRepoStore.spec.d.ts.map +1 -0
- package/dist/src/storage/local/LocalRepoStore.spec.js +255 -0
- package/dist/src/storage/local/LocalRepoStore.spec.js.map +1 -0
- package/dist/src/storage/local/gc.d.ts +92 -0
- package/dist/src/storage/local/gc.d.ts.map +1 -0
- package/dist/src/storage/local/gc.js +377 -0
- package/dist/src/storage/local/gc.js.map +1 -0
- package/dist/src/storage/local/index.d.ts +18 -0
- package/dist/src/storage/local/index.d.ts.map +1 -0
- package/dist/src/storage/local/index.js +18 -0
- package/dist/src/storage/local/index.js.map +1 -0
- package/dist/src/storage/local/localHelpers.d.ts +25 -0
- package/dist/src/storage/local/localHelpers.d.ts.map +1 -0
- package/dist/src/storage/local/localHelpers.js +69 -0
- package/dist/src/storage/local/localHelpers.js.map +1 -0
- package/dist/src/{repository.d.ts → storage/local/repository.d.ts} +8 -4
- package/dist/src/storage/local/repository.d.ts.map +1 -0
- package/dist/src/{repository.js → storage/local/repository.js} +31 -29
- package/dist/src/storage/local/repository.js.map +1 -0
- package/dist/src/storage/local/repository.spec.d.ts +6 -0
- package/dist/src/storage/local/repository.spec.d.ts.map +1 -0
- package/dist/src/storage/local/repository.spec.js +186 -0
- package/dist/src/storage/local/repository.spec.js.map +1 -0
- package/dist/src/tasks.d.ts +16 -10
- package/dist/src/tasks.d.ts.map +1 -1
- package/dist/src/tasks.js +35 -41
- package/dist/src/tasks.js.map +1 -1
- package/dist/src/tasks.spec.d.ts +6 -0
- package/dist/src/tasks.spec.d.ts.map +1 -0
- package/dist/src/tasks.spec.js +105 -0
- package/dist/src/tasks.spec.js.map +1 -0
- package/dist/src/test-helpers.d.ts +5 -4
- package/dist/src/test-helpers.d.ts.map +1 -1
- package/dist/src/test-helpers.js +9 -21
- package/dist/src/test-helpers.js.map +1 -1
- package/dist/src/transfer/InMemoryTransferBackend.d.ts +75 -0
- package/dist/src/transfer/InMemoryTransferBackend.d.ts.map +1 -0
- package/dist/src/transfer/InMemoryTransferBackend.js +211 -0
- package/dist/src/transfer/InMemoryTransferBackend.js.map +1 -0
- package/dist/src/transfer/index.d.ts +9 -0
- package/dist/src/transfer/index.d.ts.map +1 -0
- package/dist/src/transfer/index.js +11 -0
- package/dist/src/transfer/index.js.map +1 -0
- package/dist/src/transfer/interfaces.d.ts +103 -0
- package/dist/src/transfer/interfaces.d.ts.map +1 -0
- package/dist/src/transfer/interfaces.js +6 -0
- package/dist/src/transfer/interfaces.js.map +1 -0
- package/dist/src/transfer/process.d.ts +55 -0
- package/dist/src/transfer/process.d.ts.map +1 -0
- package/dist/src/transfer/process.js +144 -0
- package/dist/src/transfer/process.js.map +1 -0
- package/dist/src/transfer/types.d.ts +106 -0
- package/dist/src/transfer/types.d.ts.map +1 -0
- package/dist/src/transfer/types.js +61 -0
- package/dist/src/transfer/types.js.map +1 -0
- package/dist/src/trees.d.ts +102 -63
- package/dist/src/trees.d.ts.map +1 -1
- package/dist/src/trees.js +319 -479
- package/dist/src/trees.js.map +1 -1
- package/dist/src/trees.spec.d.ts +6 -0
- package/dist/src/trees.spec.d.ts.map +1 -0
- package/dist/src/trees.spec.js +635 -0
- package/dist/src/trees.spec.js.map +1 -0
- package/dist/src/uuid.d.ts +26 -0
- package/dist/src/uuid.d.ts.map +1 -0
- package/dist/src/uuid.js +80 -0
- package/dist/src/uuid.js.map +1 -0
- package/dist/src/workspaceStatus.d.ts +6 -4
- package/dist/src/workspaceStatus.d.ts.map +1 -1
- package/dist/src/workspaceStatus.js +46 -60
- package/dist/src/workspaceStatus.js.map +1 -1
- package/dist/src/workspaces.d.ts +46 -47
- package/dist/src/workspaces.d.ts.map +1 -1
- package/dist/src/workspaces.js +281 -221
- package/dist/src/workspaces.js.map +1 -1
- package/dist/src/workspaces.spec.d.ts +6 -0
- package/dist/src/workspaces.spec.d.ts.map +1 -0
- package/dist/src/workspaces.spec.js +273 -0
- package/dist/src/workspaces.spec.js.map +1 -0
- package/package.json +15 -15
- package/dist/src/gc.d.ts +0 -54
- package/dist/src/gc.d.ts.map +0 -1
- package/dist/src/gc.js +0 -233
- package/dist/src/gc.js.map +0 -1
- package/dist/src/repository.d.ts.map +0 -1
- package/dist/src/repository.js.map +0 -1
- package/dist/src/workspaceLock.d.ts +0 -67
- package/dist/src/workspaceLock.d.ts.map +0 -1
- package/dist/src/workspaceLock.js +0 -217
- package/dist/src/workspaceLock.js.map +0 -1
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Tests for trees.ts - low-level tree and dataset operations
|
|
7
|
+
*/
|
|
8
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
9
|
+
import assert from 'node:assert';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
import { variant, StringType, IntegerType, StructType, ArrayType, East } from '@elaraai/east';
|
|
12
|
+
import e3 from '@elaraai/e3';
|
|
13
|
+
import { treeRead, treeWrite, datasetRead, datasetWrite, packageListTree, workspaceListTree, workspaceGetDataset, workspaceGetDatasetStatus, workspaceSetDataset } from './trees.js';
|
|
14
|
+
import { packageImport } from './packages.js';
|
|
15
|
+
import { workspaceCreate, workspaceDeploy } from './workspaces.js';
|
|
16
|
+
import { WorkspaceNotFoundError, WorkspaceNotDeployedError } from './errors.js';
|
|
17
|
+
import { createTestRepo, removeTestRepo, createTempDir, removeTempDir } from './test-helpers.js';
|
|
18
|
+
import { LocalStorage } from './storage/local/index.js';
|
|
19
|
+
describe('trees', () => {
|
|
20
|
+
let testRepo;
|
|
21
|
+
let tempDir;
|
|
22
|
+
let storage;
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
testRepo = createTestRepo();
|
|
25
|
+
tempDir = createTempDir();
|
|
26
|
+
storage = new LocalStorage();
|
|
27
|
+
});
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
removeTestRepo(testRepo);
|
|
30
|
+
removeTempDir(tempDir);
|
|
31
|
+
});
|
|
32
|
+
// Helper to create a struct structure with given field names
|
|
33
|
+
function structStructure(fields) {
|
|
34
|
+
return variant('struct', new Map(Object.entries(fields)));
|
|
35
|
+
}
|
|
36
|
+
// Helper to create a value structure (dataset leaf)
|
|
37
|
+
function valueStructure(type) {
|
|
38
|
+
return variant('value', { type, writable: true });
|
|
39
|
+
}
|
|
40
|
+
describe('treeWrite and treeRead', () => {
|
|
41
|
+
it('writes and reads empty tree', async () => {
|
|
42
|
+
const structure = structStructure({});
|
|
43
|
+
const tree = {};
|
|
44
|
+
const hash = await treeWrite(storage, testRepo, tree, structure);
|
|
45
|
+
const loaded = await treeRead(storage, testRepo, hash, structure);
|
|
46
|
+
assert.deepStrictEqual(loaded, {});
|
|
47
|
+
});
|
|
48
|
+
it('writes and reads tree with value refs', async () => {
|
|
49
|
+
const structure = structStructure({
|
|
50
|
+
field1: valueStructure(StringType),
|
|
51
|
+
field2: valueStructure(StringType),
|
|
52
|
+
});
|
|
53
|
+
const tree = {
|
|
54
|
+
field1: variant('value', 'abc123def456'.padEnd(64, '0')),
|
|
55
|
+
field2: variant('value', '789xyz012345'.padEnd(64, '0')),
|
|
56
|
+
};
|
|
57
|
+
const hash = await treeWrite(storage, testRepo, tree, structure);
|
|
58
|
+
const loaded = await treeRead(storage, testRepo, hash, structure);
|
|
59
|
+
assert.deepStrictEqual(loaded.field1, tree.field1);
|
|
60
|
+
assert.deepStrictEqual(loaded.field2, tree.field2);
|
|
61
|
+
});
|
|
62
|
+
it('writes and reads tree with tree refs', async () => {
|
|
63
|
+
const structure = structStructure({
|
|
64
|
+
subtree: structStructure({}),
|
|
65
|
+
});
|
|
66
|
+
const tree = {
|
|
67
|
+
subtree: variant('tree', 'subtreehash'.padEnd(64, '0')),
|
|
68
|
+
};
|
|
69
|
+
const hash = await treeWrite(storage, testRepo, tree, structure);
|
|
70
|
+
const loaded = await treeRead(storage, testRepo, hash, structure);
|
|
71
|
+
assert.ok(loaded.subtree);
|
|
72
|
+
assert.strictEqual(loaded.subtree.type, 'tree');
|
|
73
|
+
assert.strictEqual(loaded.subtree.value, 'subtreehash'.padEnd(64, '0'));
|
|
74
|
+
});
|
|
75
|
+
it('writes and reads tree with unassigned refs', async () => {
|
|
76
|
+
const structure = structStructure({
|
|
77
|
+
pending: valueStructure(StringType),
|
|
78
|
+
});
|
|
79
|
+
const tree = {
|
|
80
|
+
pending: variant('unassigned', null),
|
|
81
|
+
};
|
|
82
|
+
const hash = await treeWrite(storage, testRepo, tree, structure);
|
|
83
|
+
const loaded = await treeRead(storage, testRepo, hash, structure);
|
|
84
|
+
assert.ok(loaded.pending);
|
|
85
|
+
assert.strictEqual(loaded.pending.type, 'unassigned');
|
|
86
|
+
});
|
|
87
|
+
it('writes and reads tree with null refs', async () => {
|
|
88
|
+
const structure = structStructure({
|
|
89
|
+
nullValue: valueStructure(StringType),
|
|
90
|
+
});
|
|
91
|
+
const tree = {
|
|
92
|
+
nullValue: variant('null', null),
|
|
93
|
+
};
|
|
94
|
+
const hash = await treeWrite(storage, testRepo, tree, structure);
|
|
95
|
+
const loaded = await treeRead(storage, testRepo, hash, structure);
|
|
96
|
+
assert.ok(loaded.nullValue);
|
|
97
|
+
assert.strictEqual(loaded.nullValue.type, 'null');
|
|
98
|
+
});
|
|
99
|
+
it('writes and reads tree with mixed ref types', async () => {
|
|
100
|
+
const structure = structStructure({
|
|
101
|
+
value: valueStructure(StringType),
|
|
102
|
+
tree: structStructure({}),
|
|
103
|
+
unassigned: valueStructure(IntegerType),
|
|
104
|
+
null: valueStructure(StringType),
|
|
105
|
+
});
|
|
106
|
+
const tree = {
|
|
107
|
+
value: variant('value', 'valuehash'.padEnd(64, '0')),
|
|
108
|
+
tree: variant('tree', 'treehash'.padEnd(64, '0')),
|
|
109
|
+
unassigned: variant('unassigned', null),
|
|
110
|
+
null: variant('null', null),
|
|
111
|
+
};
|
|
112
|
+
const hash = await treeWrite(storage, testRepo, tree, structure);
|
|
113
|
+
const loaded = await treeRead(storage, testRepo, hash, structure);
|
|
114
|
+
assert.strictEqual(loaded.value?.type, 'value');
|
|
115
|
+
assert.strictEqual(loaded.tree?.type, 'tree');
|
|
116
|
+
assert.strictEqual(loaded.unassigned?.type, 'unassigned');
|
|
117
|
+
assert.strictEqual(loaded.null?.type, 'null');
|
|
118
|
+
});
|
|
119
|
+
it('produces same hash for same content', async () => {
|
|
120
|
+
const structure = structStructure({
|
|
121
|
+
a: valueStructure(StringType),
|
|
122
|
+
});
|
|
123
|
+
const tree1 = {
|
|
124
|
+
a: variant('value', 'hash'.padEnd(64, '0')),
|
|
125
|
+
};
|
|
126
|
+
const tree2 = {
|
|
127
|
+
a: variant('value', 'hash'.padEnd(64, '0')),
|
|
128
|
+
};
|
|
129
|
+
const hash1 = await treeWrite(storage, testRepo, tree1, structure);
|
|
130
|
+
const hash2 = await treeWrite(storage, testRepo, tree2, structure);
|
|
131
|
+
assert.strictEqual(hash1, hash2);
|
|
132
|
+
});
|
|
133
|
+
it('produces different hash for different content', async () => {
|
|
134
|
+
const structure = structStructure({
|
|
135
|
+
a: valueStructure(StringType),
|
|
136
|
+
});
|
|
137
|
+
const tree1 = {
|
|
138
|
+
a: variant('value', 'hash1'.padEnd(64, '0')),
|
|
139
|
+
};
|
|
140
|
+
const tree2 = {
|
|
141
|
+
a: variant('value', 'hash2'.padEnd(64, '0')),
|
|
142
|
+
};
|
|
143
|
+
const hash1 = await treeWrite(storage, testRepo, tree1, structure);
|
|
144
|
+
const hash2 = await treeWrite(storage, testRepo, tree2, structure);
|
|
145
|
+
assert.notStrictEqual(hash1, hash2);
|
|
146
|
+
});
|
|
147
|
+
it('throws for non-existent hash', async () => {
|
|
148
|
+
const structure = structStructure({});
|
|
149
|
+
const fakeHash = 'nonexistent'.padEnd(64, '0');
|
|
150
|
+
await assert.rejects(async () => await treeRead(storage, testRepo, fakeHash, structure), /not found/);
|
|
151
|
+
});
|
|
152
|
+
it('throws when structure is a value (not a tree)', async () => {
|
|
153
|
+
const structure = valueStructure(StringType);
|
|
154
|
+
await assert.rejects(async () => await treeWrite(storage, testRepo, {}, structure), /dataset, not a tree/);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
describe('datasetWrite and datasetRead', () => {
|
|
158
|
+
it('writes and reads string value', async () => {
|
|
159
|
+
const value = 'hello world';
|
|
160
|
+
const hash = await datasetWrite(storage, testRepo, value, StringType);
|
|
161
|
+
const result = await datasetRead(storage, testRepo, hash);
|
|
162
|
+
assert.strictEqual(result.value, value);
|
|
163
|
+
assert.strictEqual(result.type.type, 'String');
|
|
164
|
+
});
|
|
165
|
+
it('writes and reads integer value', async () => {
|
|
166
|
+
const value = 42n;
|
|
167
|
+
const hash = await datasetWrite(storage, testRepo, value, IntegerType);
|
|
168
|
+
const result = await datasetRead(storage, testRepo, hash);
|
|
169
|
+
assert.strictEqual(result.value, value);
|
|
170
|
+
assert.strictEqual(result.type.type, 'Integer');
|
|
171
|
+
});
|
|
172
|
+
it('writes and reads struct value', async () => {
|
|
173
|
+
const PersonType = StructType({
|
|
174
|
+
name: StringType,
|
|
175
|
+
age: IntegerType,
|
|
176
|
+
});
|
|
177
|
+
const value = { name: 'Alice', age: 30n };
|
|
178
|
+
const hash = await datasetWrite(storage, testRepo, value, PersonType);
|
|
179
|
+
const result = await datasetRead(storage, testRepo, hash);
|
|
180
|
+
assert.deepStrictEqual(result.value, value);
|
|
181
|
+
assert.strictEqual(result.type.type, 'Struct');
|
|
182
|
+
});
|
|
183
|
+
it('writes and reads array value', async () => {
|
|
184
|
+
const NumbersType = ArrayType(IntegerType);
|
|
185
|
+
const value = [1n, 2n, 3n, 4n, 5n];
|
|
186
|
+
const hash = await datasetWrite(storage, testRepo, value, NumbersType);
|
|
187
|
+
const result = await datasetRead(storage, testRepo, hash);
|
|
188
|
+
assert.deepStrictEqual(result.value, value);
|
|
189
|
+
assert.strictEqual(result.type.type, 'Array');
|
|
190
|
+
});
|
|
191
|
+
it('produces same hash for same content', async () => {
|
|
192
|
+
const hash1 = await datasetWrite(storage, testRepo, 'test', StringType);
|
|
193
|
+
const hash2 = await datasetWrite(storage, testRepo, 'test', StringType);
|
|
194
|
+
assert.strictEqual(hash1, hash2);
|
|
195
|
+
});
|
|
196
|
+
it('produces different hash for different content', async () => {
|
|
197
|
+
const hash1 = await datasetWrite(storage, testRepo, 'test1', StringType);
|
|
198
|
+
const hash2 = await datasetWrite(storage, testRepo, 'test2', StringType);
|
|
199
|
+
assert.notStrictEqual(hash1, hash2);
|
|
200
|
+
});
|
|
201
|
+
it('throws for non-existent hash', async () => {
|
|
202
|
+
const fakeHash = 'nonexistent'.padEnd(64, '0');
|
|
203
|
+
await assert.rejects(async () => await datasetRead(storage, testRepo, fakeHash), /not found/);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
describe('nested trees', () => {
|
|
207
|
+
it('can build and traverse nested tree structure', async () => {
|
|
208
|
+
// Structure: { inputs: { sales: ArrayType(IntegerType) } }
|
|
209
|
+
const salesStructure = valueStructure(ArrayType(IntegerType));
|
|
210
|
+
const inputsStructure = structStructure({ sales: salesStructure });
|
|
211
|
+
const rootStructure = structStructure({ inputs: inputsStructure });
|
|
212
|
+
// Create a leaf dataset
|
|
213
|
+
const salesData = [100n, 200n, 300n];
|
|
214
|
+
const salesHash = await datasetWrite(storage, testRepo, salesData, ArrayType(IntegerType));
|
|
215
|
+
// Create an inputs subtree
|
|
216
|
+
const inputsTree = {
|
|
217
|
+
sales: variant('value', salesHash),
|
|
218
|
+
};
|
|
219
|
+
const inputsHash = await treeWrite(storage, testRepo, inputsTree, inputsStructure);
|
|
220
|
+
// Create root tree
|
|
221
|
+
const rootTree = {
|
|
222
|
+
inputs: variant('tree', inputsHash),
|
|
223
|
+
};
|
|
224
|
+
const rootHash = await treeWrite(storage, testRepo, rootTree, rootStructure);
|
|
225
|
+
// Traverse: root -> inputs -> sales
|
|
226
|
+
const loadedRoot = await treeRead(storage, testRepo, rootHash, rootStructure);
|
|
227
|
+
const inputsRef = loadedRoot.inputs;
|
|
228
|
+
assert.ok(inputsRef);
|
|
229
|
+
assert.strictEqual(inputsRef.type, 'tree');
|
|
230
|
+
const loadedInputs = await treeRead(storage, testRepo, inputsRef.value, inputsStructure);
|
|
231
|
+
const salesRef = loadedInputs.sales;
|
|
232
|
+
assert.ok(salesRef);
|
|
233
|
+
assert.strictEqual(salesRef.type, 'value');
|
|
234
|
+
const loadedSales = await datasetRead(storage, testRepo, salesRef.value);
|
|
235
|
+
assert.deepStrictEqual(loadedSales.value, salesData);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
describe('packageListTree', () => {
|
|
239
|
+
it('lists root tree fields', async () => {
|
|
240
|
+
// Create and import a package with inputs
|
|
241
|
+
const myInput = e3.input('greeting', StringType, 'hello');
|
|
242
|
+
const pkg = e3.package('list-test', '1.0.0', myInput);
|
|
243
|
+
const zipPath = join(tempDir, 'list-test.zip');
|
|
244
|
+
await e3.export(pkg, zipPath);
|
|
245
|
+
await packageImport(storage, testRepo, zipPath);
|
|
246
|
+
// List root
|
|
247
|
+
const fields = await packageListTree(storage, testRepo, 'list-test', '1.0.0', []);
|
|
248
|
+
assert.ok(fields.includes('inputs'));
|
|
249
|
+
});
|
|
250
|
+
it('lists nested tree fields', async () => {
|
|
251
|
+
// Create and import a package with multiple inputs
|
|
252
|
+
const input1 = e3.input('sales', IntegerType, 100n);
|
|
253
|
+
const input2 = e3.input('costs', IntegerType, 50n);
|
|
254
|
+
const pkg = e3.package('nested-list', '1.0.0', input1, input2);
|
|
255
|
+
const zipPath = join(tempDir, 'nested-list.zip');
|
|
256
|
+
await e3.export(pkg, zipPath);
|
|
257
|
+
await packageImport(storage, testRepo, zipPath);
|
|
258
|
+
// List inputs subtree
|
|
259
|
+
const fields = await packageListTree(storage, testRepo, 'nested-list', '1.0.0', [
|
|
260
|
+
variant('field', 'inputs'),
|
|
261
|
+
]);
|
|
262
|
+
assert.ok(fields.includes('sales'));
|
|
263
|
+
assert.ok(fields.includes('costs'));
|
|
264
|
+
assert.strictEqual(fields.length, 2);
|
|
265
|
+
});
|
|
266
|
+
it('throws for non-existent package', async () => {
|
|
267
|
+
await assert.rejects(async () => await packageListTree(storage, testRepo, 'nonexistent', '1.0.0', []), /not found|ENOENT/);
|
|
268
|
+
});
|
|
269
|
+
it('throws for invalid path', async () => {
|
|
270
|
+
const myInput = e3.input('value', StringType, 'test');
|
|
271
|
+
const pkg = e3.package('path-test', '1.0.0', myInput);
|
|
272
|
+
const zipPath = join(tempDir, 'path-test.zip');
|
|
273
|
+
await e3.export(pkg, zipPath);
|
|
274
|
+
await packageImport(storage, testRepo, zipPath);
|
|
275
|
+
await assert.rejects(async () => await packageListTree(storage, testRepo, 'path-test', '1.0.0', [
|
|
276
|
+
variant('field', 'nonexistent'),
|
|
277
|
+
]), /not found/);
|
|
278
|
+
});
|
|
279
|
+
it('throws when path points to dataset', async () => {
|
|
280
|
+
const myInput = e3.input('value', StringType, 'test');
|
|
281
|
+
const pkg = e3.package('dataset-path', '1.0.0', myInput);
|
|
282
|
+
const zipPath = join(tempDir, 'dataset-path.zip');
|
|
283
|
+
await e3.export(pkg, zipPath);
|
|
284
|
+
await packageImport(storage, testRepo, zipPath);
|
|
285
|
+
await assert.rejects(async () => await packageListTree(storage, testRepo, 'dataset-path', '1.0.0', [
|
|
286
|
+
variant('field', 'inputs'),
|
|
287
|
+
variant('field', 'value'),
|
|
288
|
+
]), /dataset, not a tree/);
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
// packageGetDataset was removed — packages no longer have tree objects.
|
|
292
|
+
// Dataset values are stored as per-dataset ref files.
|
|
293
|
+
describe('workspaceListTree', () => {
|
|
294
|
+
it('lists root tree fields', async () => {
|
|
295
|
+
const myInput = e3.input('greeting', StringType, 'hello');
|
|
296
|
+
const pkg = e3.package('ws-list-test', '1.0.0', myInput);
|
|
297
|
+
const zipPath = join(tempDir, 'ws-list-test.zip');
|
|
298
|
+
await e3.export(pkg, zipPath);
|
|
299
|
+
await packageImport(storage, testRepo, zipPath);
|
|
300
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'ws-list-test', '1.0.0');
|
|
301
|
+
const fields = await workspaceListTree(storage, testRepo, 'myws', []);
|
|
302
|
+
assert.ok(fields.includes('inputs'));
|
|
303
|
+
});
|
|
304
|
+
it('lists nested tree fields', async () => {
|
|
305
|
+
const input1 = e3.input('sales', IntegerType, 100n);
|
|
306
|
+
const input2 = e3.input('costs', IntegerType, 50n);
|
|
307
|
+
const pkg = e3.package('ws-nested-list', '1.0.0', input1, input2);
|
|
308
|
+
const zipPath = join(tempDir, 'ws-nested-list.zip');
|
|
309
|
+
await e3.export(pkg, zipPath);
|
|
310
|
+
await packageImport(storage, testRepo, zipPath);
|
|
311
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'ws-nested-list', '1.0.0');
|
|
312
|
+
const fields = await workspaceListTree(storage, testRepo, 'myws', [
|
|
313
|
+
variant('field', 'inputs'),
|
|
314
|
+
]);
|
|
315
|
+
assert.ok(fields.includes('sales'));
|
|
316
|
+
assert.ok(fields.includes('costs'));
|
|
317
|
+
assert.strictEqual(fields.length, 2);
|
|
318
|
+
});
|
|
319
|
+
it('throws for non-existent workspace', async () => {
|
|
320
|
+
await assert.rejects(async () => await workspaceListTree(storage, testRepo, 'nonexistent', []), WorkspaceNotFoundError);
|
|
321
|
+
});
|
|
322
|
+
it('throws for undeployed workspace', async () => {
|
|
323
|
+
await workspaceCreate(storage, testRepo, 'empty');
|
|
324
|
+
await assert.rejects(async () => await workspaceListTree(storage, testRepo, 'empty', []), WorkspaceNotDeployedError);
|
|
325
|
+
});
|
|
326
|
+
it('throws when path points to dataset', async () => {
|
|
327
|
+
const myInput = e3.input('value', StringType, 'test');
|
|
328
|
+
const pkg = e3.package('ws-dataset-path', '1.0.0', myInput);
|
|
329
|
+
const zipPath = join(tempDir, 'ws-dataset-path.zip');
|
|
330
|
+
await e3.export(pkg, zipPath);
|
|
331
|
+
await packageImport(storage, testRepo, zipPath);
|
|
332
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'ws-dataset-path', '1.0.0');
|
|
333
|
+
await assert.rejects(async () => await workspaceListTree(storage, testRepo, 'myws', [
|
|
334
|
+
variant('field', 'inputs'),
|
|
335
|
+
variant('field', 'value'),
|
|
336
|
+
]), /dataset, not a tree/);
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
describe('workspaceGetDataset', () => {
|
|
340
|
+
it('reads dataset value at path', async () => {
|
|
341
|
+
const myInput = e3.input('greeting', StringType, 'hello world');
|
|
342
|
+
const pkg = e3.package('ws-get-test', '1.0.0', myInput);
|
|
343
|
+
const zipPath = join(tempDir, 'ws-get-test.zip');
|
|
344
|
+
await e3.export(pkg, zipPath);
|
|
345
|
+
await packageImport(storage, testRepo, zipPath);
|
|
346
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'ws-get-test', '1.0.0');
|
|
347
|
+
const value = await workspaceGetDataset(storage, testRepo, 'myws', [
|
|
348
|
+
variant('field', 'inputs'),
|
|
349
|
+
variant('field', 'greeting'),
|
|
350
|
+
]);
|
|
351
|
+
assert.strictEqual(value, 'hello world');
|
|
352
|
+
});
|
|
353
|
+
it('reads integer dataset', async () => {
|
|
354
|
+
const myInput = e3.input('count', IntegerType, 42n);
|
|
355
|
+
const pkg = e3.package('ws-int-test', '1.0.0', myInput);
|
|
356
|
+
const zipPath = join(tempDir, 'ws-int-test.zip');
|
|
357
|
+
await e3.export(pkg, zipPath);
|
|
358
|
+
await packageImport(storage, testRepo, zipPath);
|
|
359
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'ws-int-test', '1.0.0');
|
|
360
|
+
const value = await workspaceGetDataset(storage, testRepo, 'myws', [
|
|
361
|
+
variant('field', 'inputs'),
|
|
362
|
+
variant('field', 'count'),
|
|
363
|
+
]);
|
|
364
|
+
assert.strictEqual(value, 42n);
|
|
365
|
+
});
|
|
366
|
+
it('throws for empty path', async () => {
|
|
367
|
+
const myInput = e3.input('value', StringType, 'test');
|
|
368
|
+
const pkg = e3.package('ws-empty-path', '1.0.0', myInput);
|
|
369
|
+
const zipPath = join(tempDir, 'ws-empty-path.zip');
|
|
370
|
+
await e3.export(pkg, zipPath);
|
|
371
|
+
await packageImport(storage, testRepo, zipPath);
|
|
372
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'ws-empty-path', '1.0.0');
|
|
373
|
+
await assert.rejects(async () => await workspaceGetDataset(storage, testRepo, 'myws', []), /root.*tree/);
|
|
374
|
+
});
|
|
375
|
+
it('throws when path points to tree', async () => {
|
|
376
|
+
const myInput = e3.input('value', StringType, 'test');
|
|
377
|
+
const pkg = e3.package('ws-tree-path', '1.0.0', myInput);
|
|
378
|
+
const zipPath = join(tempDir, 'ws-tree-path.zip');
|
|
379
|
+
await e3.export(pkg, zipPath);
|
|
380
|
+
await packageImport(storage, testRepo, zipPath);
|
|
381
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'ws-tree-path', '1.0.0');
|
|
382
|
+
await assert.rejects(async () => await workspaceGetDataset(storage, testRepo, 'myws', [
|
|
383
|
+
variant('field', 'inputs'),
|
|
384
|
+
]), /tree, not a dataset/);
|
|
385
|
+
});
|
|
386
|
+
it('throws for non-existent workspace', async () => {
|
|
387
|
+
await assert.rejects(async () => await workspaceGetDataset(storage, testRepo, 'nonexistent', [
|
|
388
|
+
variant('field', 'inputs'),
|
|
389
|
+
]), WorkspaceNotFoundError);
|
|
390
|
+
});
|
|
391
|
+
it('throws for undeployed workspace', async () => {
|
|
392
|
+
await workspaceCreate(storage, testRepo, 'empty');
|
|
393
|
+
await assert.rejects(async () => await workspaceGetDataset(storage, testRepo, 'empty', [
|
|
394
|
+
variant('field', 'inputs'),
|
|
395
|
+
]), WorkspaceNotDeployedError);
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
describe('workspaceSetDataset', () => {
|
|
399
|
+
it('updates dataset value at path', async () => {
|
|
400
|
+
const myInput = e3.input('greeting', StringType, 'hello');
|
|
401
|
+
const pkg = e3.package('ws-set-test', '1.0.0', myInput);
|
|
402
|
+
const zipPath = join(tempDir, 'ws-set-test.zip');
|
|
403
|
+
await e3.export(pkg, zipPath);
|
|
404
|
+
await packageImport(storage, testRepo, zipPath);
|
|
405
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'ws-set-test', '1.0.0');
|
|
406
|
+
// Verify initial value
|
|
407
|
+
const initial = await workspaceGetDataset(storage, testRepo, 'myws', [
|
|
408
|
+
variant('field', 'inputs'),
|
|
409
|
+
variant('field', 'greeting'),
|
|
410
|
+
]);
|
|
411
|
+
assert.strictEqual(initial, 'hello');
|
|
412
|
+
// Update the value
|
|
413
|
+
await workspaceSetDataset(storage, testRepo, 'myws', [
|
|
414
|
+
variant('field', 'inputs'),
|
|
415
|
+
variant('field', 'greeting'),
|
|
416
|
+
], 'goodbye', StringType);
|
|
417
|
+
// Verify updated value
|
|
418
|
+
const updated = await workspaceGetDataset(storage, testRepo, 'myws', [
|
|
419
|
+
variant('field', 'inputs'),
|
|
420
|
+
variant('field', 'greeting'),
|
|
421
|
+
]);
|
|
422
|
+
assert.strictEqual(updated, 'goodbye');
|
|
423
|
+
});
|
|
424
|
+
it('updates integer dataset', async () => {
|
|
425
|
+
const myInput = e3.input('count', IntegerType, 100n);
|
|
426
|
+
const pkg = e3.package('ws-set-int', '1.0.0', myInput);
|
|
427
|
+
const zipPath = join(tempDir, 'ws-set-int.zip');
|
|
428
|
+
await e3.export(pkg, zipPath);
|
|
429
|
+
await packageImport(storage, testRepo, zipPath);
|
|
430
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'ws-set-int', '1.0.0');
|
|
431
|
+
await workspaceSetDataset(storage, testRepo, 'myws', [
|
|
432
|
+
variant('field', 'inputs'),
|
|
433
|
+
variant('field', 'count'),
|
|
434
|
+
], 200n, IntegerType);
|
|
435
|
+
const value = await workspaceGetDataset(storage, testRepo, 'myws', [
|
|
436
|
+
variant('field', 'inputs'),
|
|
437
|
+
variant('field', 'count'),
|
|
438
|
+
]);
|
|
439
|
+
assert.strictEqual(value, 200n);
|
|
440
|
+
});
|
|
441
|
+
it('preserves other fields in tree (structural sharing)', async () => {
|
|
442
|
+
const input1 = e3.input('a', StringType, 'alpha');
|
|
443
|
+
const input2 = e3.input('b', StringType, 'beta');
|
|
444
|
+
const pkg = e3.package('ws-share-test', '1.0.0', input1, input2);
|
|
445
|
+
const zipPath = join(tempDir, 'ws-share-test.zip');
|
|
446
|
+
await e3.export(pkg, zipPath);
|
|
447
|
+
await packageImport(storage, testRepo, zipPath);
|
|
448
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'ws-share-test', '1.0.0');
|
|
449
|
+
// Update only 'a'
|
|
450
|
+
await workspaceSetDataset(storage, testRepo, 'myws', [
|
|
451
|
+
variant('field', 'inputs'),
|
|
452
|
+
variant('field', 'a'),
|
|
453
|
+
], 'updated-alpha', StringType);
|
|
454
|
+
// Verify 'a' was updated
|
|
455
|
+
const valueA = await workspaceGetDataset(storage, testRepo, 'myws', [
|
|
456
|
+
variant('field', 'inputs'),
|
|
457
|
+
variant('field', 'a'),
|
|
458
|
+
]);
|
|
459
|
+
assert.strictEqual(valueA, 'updated-alpha');
|
|
460
|
+
// Verify 'b' is unchanged
|
|
461
|
+
const valueB = await workspaceGetDataset(storage, testRepo, 'myws', [
|
|
462
|
+
variant('field', 'inputs'),
|
|
463
|
+
variant('field', 'b'),
|
|
464
|
+
]);
|
|
465
|
+
assert.strictEqual(valueB, 'beta');
|
|
466
|
+
});
|
|
467
|
+
it('throws for empty path', async () => {
|
|
468
|
+
const myInput = e3.input('value', StringType, 'test');
|
|
469
|
+
const pkg = e3.package('ws-set-empty', '1.0.0', myInput);
|
|
470
|
+
const zipPath = join(tempDir, 'ws-set-empty.zip');
|
|
471
|
+
await e3.export(pkg, zipPath);
|
|
472
|
+
await packageImport(storage, testRepo, zipPath);
|
|
473
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'ws-set-empty', '1.0.0');
|
|
474
|
+
await assert.rejects(async () => await workspaceSetDataset(storage, testRepo, 'myws', [], 'value', StringType), /root.*tree/);
|
|
475
|
+
});
|
|
476
|
+
it('throws when path points to tree', async () => {
|
|
477
|
+
const myInput = e3.input('value', StringType, 'test');
|
|
478
|
+
const pkg = e3.package('ws-set-tree', '1.0.0', myInput);
|
|
479
|
+
const zipPath = join(tempDir, 'ws-set-tree.zip');
|
|
480
|
+
await e3.export(pkg, zipPath);
|
|
481
|
+
await packageImport(storage, testRepo, zipPath);
|
|
482
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'ws-set-tree', '1.0.0');
|
|
483
|
+
await assert.rejects(async () => await workspaceSetDataset(storage, testRepo, 'myws', [
|
|
484
|
+
variant('field', 'inputs'),
|
|
485
|
+
], 'value', StringType), /tree, not a dataset/);
|
|
486
|
+
});
|
|
487
|
+
it('throws for non-existent path', async () => {
|
|
488
|
+
const myInput = e3.input('value', StringType, 'test');
|
|
489
|
+
const pkg = e3.package('ws-set-bad', '1.0.0', myInput);
|
|
490
|
+
const zipPath = join(tempDir, 'ws-set-bad.zip');
|
|
491
|
+
await e3.export(pkg, zipPath);
|
|
492
|
+
await packageImport(storage, testRepo, zipPath);
|
|
493
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'ws-set-bad', '1.0.0');
|
|
494
|
+
await assert.rejects(async () => await workspaceSetDataset(storage, testRepo, 'myws', [
|
|
495
|
+
variant('field', 'inputs'),
|
|
496
|
+
variant('field', 'nonexistent'),
|
|
497
|
+
], 'value', StringType), /not found/);
|
|
498
|
+
});
|
|
499
|
+
it('throws for non-existent workspace', async () => {
|
|
500
|
+
await assert.rejects(async () => await workspaceSetDataset(storage, testRepo, 'nonexistent', [
|
|
501
|
+
variant('field', 'inputs'),
|
|
502
|
+
], 'value', StringType), WorkspaceNotFoundError);
|
|
503
|
+
});
|
|
504
|
+
it('throws for undeployed workspace', async () => {
|
|
505
|
+
await workspaceCreate(storage, testRepo, 'empty');
|
|
506
|
+
await assert.rejects(async () => await workspaceSetDataset(storage, testRepo, 'empty', [
|
|
507
|
+
variant('field', 'inputs'),
|
|
508
|
+
], 'value', StringType), WorkspaceNotDeployedError);
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
describe('workspaceGetDatasetStatus', () => {
|
|
512
|
+
it('returns status for value ref (input with default)', async () => {
|
|
513
|
+
const myInput = e3.input('count', IntegerType, 42n);
|
|
514
|
+
const pkg = e3.package('status-value', '1.0.0', myInput);
|
|
515
|
+
const zipPath = join(tempDir, 'status-value.zip');
|
|
516
|
+
await e3.export(pkg, zipPath);
|
|
517
|
+
await packageImport(storage, testRepo, zipPath);
|
|
518
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'status-value', '1.0.0');
|
|
519
|
+
const result = await workspaceGetDatasetStatus(storage, testRepo, 'myws', [
|
|
520
|
+
variant('field', 'inputs'),
|
|
521
|
+
variant('field', 'count'),
|
|
522
|
+
]);
|
|
523
|
+
assert.strictEqual(result.refType, 'value');
|
|
524
|
+
assert.ok(result.hash !== null, 'hash should be present');
|
|
525
|
+
assert.strictEqual(result.hash.length, 64, 'hash should be 64-char hex');
|
|
526
|
+
assert.ok(result.size !== null, 'size should be present');
|
|
527
|
+
assert.ok(result.size > 0, 'size should be positive');
|
|
528
|
+
// datasetType should represent Integer
|
|
529
|
+
assert.ok(result.datasetType, 'datasetType should be present');
|
|
530
|
+
});
|
|
531
|
+
it('returns status for unassigned ref (task output)', async () => {
|
|
532
|
+
const myInput = e3.input('x', IntegerType, 10n);
|
|
533
|
+
const task = e3.task('double', [myInput], East.function([IntegerType], IntegerType, ($, x) => x.multiply(2n)));
|
|
534
|
+
const pkg = e3.package('status-unassigned', '1.0.0', task);
|
|
535
|
+
const zipPath = join(tempDir, 'status-unassigned.zip');
|
|
536
|
+
await e3.export(pkg, zipPath);
|
|
537
|
+
await packageImport(storage, testRepo, zipPath);
|
|
538
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'status-unassigned', '1.0.0');
|
|
539
|
+
const result = await workspaceGetDatasetStatus(storage, testRepo, 'myws', [
|
|
540
|
+
variant('field', 'tasks'),
|
|
541
|
+
variant('field', 'double'),
|
|
542
|
+
variant('field', 'output'),
|
|
543
|
+
]);
|
|
544
|
+
assert.strictEqual(result.refType, 'unassigned');
|
|
545
|
+
assert.strictEqual(result.hash, null);
|
|
546
|
+
assert.strictEqual(result.size, null);
|
|
547
|
+
assert.ok(result.datasetType, 'datasetType should be present');
|
|
548
|
+
});
|
|
549
|
+
it('returns status for null ref', async () => {
|
|
550
|
+
// Deploy a package, then manually write a null ref
|
|
551
|
+
const myInput = e3.input('value', IntegerType, 10n);
|
|
552
|
+
const pkg = e3.package('status-null', '1.0.0', myInput);
|
|
553
|
+
const zipPath = join(tempDir, 'status-null.zip');
|
|
554
|
+
await e3.export(pkg, zipPath);
|
|
555
|
+
await packageImport(storage, testRepo, zipPath);
|
|
556
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'status-null', '1.0.0');
|
|
557
|
+
// Write a null ref for the dataset
|
|
558
|
+
await storage.datasets.write(testRepo, 'myws', 'inputs/value', variant('null', { versions: new Map() }));
|
|
559
|
+
// Now query the status of the null ref dataset
|
|
560
|
+
const result = await workspaceGetDatasetStatus(storage, testRepo, 'myws', [
|
|
561
|
+
variant('field', 'inputs'),
|
|
562
|
+
variant('field', 'value'),
|
|
563
|
+
]);
|
|
564
|
+
assert.strictEqual(result.refType, 'null');
|
|
565
|
+
assert.strictEqual(result.hash, null);
|
|
566
|
+
assert.strictEqual(result.size, 0);
|
|
567
|
+
assert.ok(result.datasetType, 'datasetType should be present');
|
|
568
|
+
});
|
|
569
|
+
it('returns updated status after set', async () => {
|
|
570
|
+
const myInput = e3.input('value', IntegerType, 10n);
|
|
571
|
+
const pkg = e3.package('status-update', '1.0.0', myInput);
|
|
572
|
+
const zipPath = join(tempDir, 'status-update.zip');
|
|
573
|
+
await e3.export(pkg, zipPath);
|
|
574
|
+
await packageImport(storage, testRepo, zipPath);
|
|
575
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'status-update', '1.0.0');
|
|
576
|
+
const path = [variant('field', 'inputs'), variant('field', 'value')];
|
|
577
|
+
// Get initial status
|
|
578
|
+
const before = await workspaceGetDatasetStatus(storage, testRepo, 'myws', path);
|
|
579
|
+
assert.strictEqual(before.refType, 'value');
|
|
580
|
+
const originalHash = before.hash;
|
|
581
|
+
// Set a new value
|
|
582
|
+
await workspaceSetDataset(storage, testRepo, 'myws', path, 99n, IntegerType);
|
|
583
|
+
// Get updated status
|
|
584
|
+
const after = await workspaceGetDatasetStatus(storage, testRepo, 'myws', path);
|
|
585
|
+
assert.strictEqual(after.refType, 'value');
|
|
586
|
+
assert.ok(after.hash !== null);
|
|
587
|
+
assert.notStrictEqual(after.hash, originalHash, 'hash should change after set');
|
|
588
|
+
assert.ok(after.size !== null && after.size > 0);
|
|
589
|
+
});
|
|
590
|
+
it('throws for empty path', async () => {
|
|
591
|
+
const myInput = e3.input('value', StringType, 'test');
|
|
592
|
+
const pkg = e3.package('status-empty', '1.0.0', myInput);
|
|
593
|
+
const zipPath = join(tempDir, 'status-empty.zip');
|
|
594
|
+
await e3.export(pkg, zipPath);
|
|
595
|
+
await packageImport(storage, testRepo, zipPath);
|
|
596
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'status-empty', '1.0.0');
|
|
597
|
+
await assert.rejects(async () => await workspaceGetDatasetStatus(storage, testRepo, 'myws', []), /root.*tree/);
|
|
598
|
+
});
|
|
599
|
+
it('throws when path points to tree', async () => {
|
|
600
|
+
const myInput = e3.input('value', StringType, 'test');
|
|
601
|
+
const pkg = e3.package('status-tree', '1.0.0', myInput);
|
|
602
|
+
const zipPath = join(tempDir, 'status-tree.zip');
|
|
603
|
+
await e3.export(pkg, zipPath);
|
|
604
|
+
await packageImport(storage, testRepo, zipPath);
|
|
605
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'status-tree', '1.0.0');
|
|
606
|
+
await assert.rejects(async () => await workspaceGetDatasetStatus(storage, testRepo, 'myws', [
|
|
607
|
+
variant('field', 'inputs'),
|
|
608
|
+
]), /tree, not a dataset/);
|
|
609
|
+
});
|
|
610
|
+
it('throws for non-existent field', async () => {
|
|
611
|
+
const myInput = e3.input('value', StringType, 'test');
|
|
612
|
+
const pkg = e3.package('status-nofield', '1.0.0', myInput);
|
|
613
|
+
const zipPath = join(tempDir, 'status-nofield.zip');
|
|
614
|
+
await e3.export(pkg, zipPath);
|
|
615
|
+
await packageImport(storage, testRepo, zipPath);
|
|
616
|
+
await workspaceDeploy(storage, testRepo, 'myws', 'status-nofield', '1.0.0');
|
|
617
|
+
await assert.rejects(async () => await workspaceGetDatasetStatus(storage, testRepo, 'myws', [
|
|
618
|
+
variant('field', 'inputs'),
|
|
619
|
+
variant('field', 'nonexistent'),
|
|
620
|
+
]), /not found/);
|
|
621
|
+
});
|
|
622
|
+
it('throws for non-existent workspace', async () => {
|
|
623
|
+
await assert.rejects(async () => await workspaceGetDatasetStatus(storage, testRepo, 'nonexistent', [
|
|
624
|
+
variant('field', 'inputs'),
|
|
625
|
+
]), WorkspaceNotFoundError);
|
|
626
|
+
});
|
|
627
|
+
it('throws for undeployed workspace', async () => {
|
|
628
|
+
await workspaceCreate(storage, testRepo, 'empty');
|
|
629
|
+
await assert.rejects(async () => await workspaceGetDatasetStatus(storage, testRepo, 'empty', [
|
|
630
|
+
variant('field', 'inputs'),
|
|
631
|
+
]), WorkspaceNotDeployedError);
|
|
632
|
+
});
|
|
633
|
+
});
|
|
634
|
+
});
|
|
635
|
+
//# sourceMappingURL=trees.spec.js.map
|