@streetjs/storage 1.0.0 → 1.0.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/dist/drivers/local.d.ts +8 -0
- package/dist/drivers/local.d.ts.map +1 -1
- package/dist/drivers/local.js +18 -3
- package/dist/drivers/local.js.map +1 -1
- package/package.json +12 -6
- package/dist/tests/access.test.d.ts +0 -2
- package/dist/tests/access.test.d.ts.map +0 -1
- package/dist/tests/access.test.js +0 -270
- package/dist/tests/access.test.js.map +0 -1
- package/dist/tests/azure-driver.test.d.ts +0 -2
- package/dist/tests/azure-driver.test.d.ts.map +0 -1
- package/dist/tests/azure-driver.test.js +0 -183
- package/dist/tests/azure-driver.test.js.map +0 -1
- package/dist/tests/backblaze-driver.test.d.ts +0 -2
- package/dist/tests/backblaze-driver.test.d.ts.map +0 -1
- package/dist/tests/backblaze-driver.test.js +0 -185
- package/dist/tests/backblaze-driver.test.js.map +0 -1
- package/dist/tests/bridge-degradation.test.d.ts +0 -2
- package/dist/tests/bridge-degradation.test.d.ts.map +0 -1
- package/dist/tests/bridge-degradation.test.js +0 -138
- package/dist/tests/bridge-degradation.test.js.map +0 -1
- package/dist/tests/cli.test.d.ts +0 -2
- package/dist/tests/cli.test.d.ts.map +0 -1
- package/dist/tests/cli.test.js +0 -127
- package/dist/tests/cli.test.js.map +0 -1
- package/dist/tests/contract.d.ts +0 -131
- package/dist/tests/contract.d.ts.map +0 -1
- package/dist/tests/contract.js +0 -222
- package/dist/tests/contract.js.map +0 -1
- package/dist/tests/contract.test.d.ts +0 -2
- package/dist/tests/contract.test.d.ts.map +0 -1
- package/dist/tests/contract.test.js +0 -110
- package/dist/tests/contract.test.js.map +0 -1
- package/dist/tests/directory.test.d.ts +0 -2
- package/dist/tests/directory.test.d.ts.map +0 -1
- package/dist/tests/directory.test.js +0 -125
- package/dist/tests/directory.test.js.map +0 -1
- package/dist/tests/errors.test.d.ts +0 -2
- package/dist/tests/errors.test.d.ts.map +0 -1
- package/dist/tests/errors.test.js +0 -93
- package/dist/tests/errors.test.js.map +0 -1
- package/dist/tests/events-bridge.test.d.ts +0 -2
- package/dist/tests/events-bridge.test.d.ts.map +0 -1
- package/dist/tests/events-bridge.test.js +0 -228
- package/dist/tests/events-bridge.test.js.map +0 -1
- package/dist/tests/example-smoke.test.d.ts +0 -2
- package/dist/tests/example-smoke.test.d.ts.map +0 -1
- package/dist/tests/example-smoke.test.js +0 -34
- package/dist/tests/example-smoke.test.js.map +0 -1
- package/dist/tests/gcs-driver.test.d.ts +0 -2
- package/dist/tests/gcs-driver.test.d.ts.map +0 -1
- package/dist/tests/gcs-driver.test.js +0 -197
- package/dist/tests/gcs-driver.test.js.map +0 -1
- package/dist/tests/image.test.d.ts +0 -2
- package/dist/tests/image.test.d.ts.map +0 -1
- package/dist/tests/image.test.js +0 -102
- package/dist/tests/image.test.js.map +0 -1
- package/dist/tests/lifecycle.test.d.ts +0 -2
- package/dist/tests/lifecycle.test.d.ts.map +0 -1
- package/dist/tests/lifecycle.test.js +0 -171
- package/dist/tests/lifecycle.test.js.map +0 -1
- package/dist/tests/local-driver.test.d.ts +0 -2
- package/dist/tests/local-driver.test.d.ts.map +0 -1
- package/dist/tests/local-driver.test.js +0 -153
- package/dist/tests/local-driver.test.js.map +0 -1
- package/dist/tests/local-streaming.test.d.ts +0 -2
- package/dist/tests/local-streaming.test.d.ts.map +0 -1
- package/dist/tests/local-streaming.test.js +0 -121
- package/dist/tests/local-streaming.test.js.map +0 -1
- package/dist/tests/memory-driver.test.d.ts +0 -2
- package/dist/tests/memory-driver.test.d.ts.map +0 -1
- package/dist/tests/memory-driver.test.js +0 -180
- package/dist/tests/memory-driver.test.js.map +0 -1
- package/dist/tests/memory-streaming.test.d.ts +0 -2
- package/dist/tests/memory-streaming.test.d.ts.map +0 -1
- package/dist/tests/memory-streaming.test.js +0 -92
- package/dist/tests/memory-streaming.test.js.map +0 -1
- package/dist/tests/minio-driver.test.d.ts +0 -2
- package/dist/tests/minio-driver.test.d.ts.map +0 -1
- package/dist/tests/minio-driver.test.js +0 -146
- package/dist/tests/minio-driver.test.js.map +0 -1
- package/dist/tests/non-s3-integration.test.d.ts +0 -2
- package/dist/tests/non-s3-integration.test.d.ts.map +0 -1
- package/dist/tests/non-s3-integration.test.js +0 -201
- package/dist/tests/non-s3-integration.test.js.map +0 -1
- package/dist/tests/observability.registration.test.d.ts +0 -2
- package/dist/tests/observability.registration.test.d.ts.map +0 -1
- package/dist/tests/observability.registration.test.js +0 -103
- package/dist/tests/observability.registration.test.js.map +0 -1
- package/dist/tests/observability.test.d.ts +0 -2
- package/dist/tests/observability.test.d.ts.map +0 -1
- package/dist/tests/observability.test.js +0 -240
- package/dist/tests/observability.test.js.map +0 -1
- package/dist/tests/plugin.test.d.ts +0 -2
- package/dist/tests/plugin.test.d.ts.map +0 -1
- package/dist/tests/plugin.test.js +0 -112
- package/dist/tests/plugin.test.js.map +0 -1
- package/dist/tests/prop-concurrent.test.d.ts +0 -2
- package/dist/tests/prop-concurrent.test.d.ts.map +0 -1
- package/dist/tests/prop-concurrent.test.js +0 -59
- package/dist/tests/prop-concurrent.test.js.map +0 -1
- package/dist/tests/prop-copy.test.d.ts +0 -2
- package/dist/tests/prop-copy.test.d.ts.map +0 -1
- package/dist/tests/prop-copy.test.js +0 -63
- package/dist/tests/prop-copy.test.js.map +0 -1
- package/dist/tests/prop-delete.test.d.ts +0 -2
- package/dist/tests/prop-delete.test.d.ts.map +0 -1
- package/dist/tests/prop-delete.test.js +0 -35
- package/dist/tests/prop-delete.test.js.map +0 -1
- package/dist/tests/prop-directory.test.d.ts +0 -2
- package/dist/tests/prop-directory.test.d.ts.map +0 -1
- package/dist/tests/prop-directory.test.js +0 -118
- package/dist/tests/prop-directory.test.js.map +0 -1
- package/dist/tests/prop-driver-conformance.test.d.ts +0 -2
- package/dist/tests/prop-driver-conformance.test.d.ts.map +0 -1
- package/dist/tests/prop-driver-conformance.test.js +0 -110
- package/dist/tests/prop-driver-conformance.test.js.map +0 -1
- package/dist/tests/prop-driver-equivalence.test.d.ts +0 -2
- package/dist/tests/prop-driver-equivalence.test.d.ts.map +0 -1
- package/dist/tests/prop-driver-equivalence.test.js +0 -163
- package/dist/tests/prop-driver-equivalence.test.js.map +0 -1
- package/dist/tests/prop-lifecycle.test.d.ts +0 -2
- package/dist/tests/prop-lifecycle.test.d.ts.map +0 -1
- package/dist/tests/prop-lifecycle.test.js +0 -83
- package/dist/tests/prop-lifecycle.test.js.map +0 -1
- package/dist/tests/prop-list.test.d.ts +0 -2
- package/dist/tests/prop-list.test.d.ts.map +0 -1
- package/dist/tests/prop-list.test.js +0 -53
- package/dist/tests/prop-list.test.js.map +0 -1
- package/dist/tests/prop-metadata.test.d.ts +0 -2
- package/dist/tests/prop-metadata.test.d.ts.map +0 -1
- package/dist/tests/prop-metadata.test.js +0 -87
- package/dist/tests/prop-metadata.test.js.map +0 -1
- package/dist/tests/prop-move.test.d.ts +0 -2
- package/dist/tests/prop-move.test.d.ts.map +0 -1
- package/dist/tests/prop-move.test.js +0 -67
- package/dist/tests/prop-move.test.js.map +0 -1
- package/dist/tests/prop-multipart-abort.test.d.ts +0 -2
- package/dist/tests/prop-multipart-abort.test.d.ts.map +0 -1
- package/dist/tests/prop-multipart-abort.test.js +0 -48
- package/dist/tests/prop-multipart-abort.test.js.map +0 -1
- package/dist/tests/prop-multipart.test.d.ts +0 -2
- package/dist/tests/prop-multipart.test.d.ts.map +0 -1
- package/dist/tests/prop-multipart.test.js +0 -65
- package/dist/tests/prop-multipart.test.js.map +0 -1
- package/dist/tests/prop-resumable.test.d.ts +0 -2
- package/dist/tests/prop-resumable.test.d.ts.map +0 -1
- package/dist/tests/prop-resumable.test.js +0 -78
- package/dist/tests/prop-resumable.test.js.map +0 -1
- package/dist/tests/prop-search.test.d.ts +0 -2
- package/dist/tests/prop-search.test.d.ts.map +0 -1
- package/dist/tests/prop-search.test.js +0 -120
- package/dist/tests/prop-search.test.js.map +0 -1
- package/dist/tests/prop-signed-url.test.d.ts +0 -2
- package/dist/tests/prop-signed-url.test.d.ts.map +0 -1
- package/dist/tests/prop-signed-url.test.js +0 -74
- package/dist/tests/prop-signed-url.test.js.map +0 -1
- package/dist/tests/prop-streaming.test.d.ts +0 -2
- package/dist/tests/prop-streaming.test.d.ts.map +0 -1
- package/dist/tests/prop-streaming.test.js +0 -34
- package/dist/tests/prop-streaming.test.js.map +0 -1
- package/dist/tests/prop-upload-download.test.d.ts +0 -2
- package/dist/tests/prop-upload-download.test.d.ts.map +0 -1
- package/dist/tests/prop-upload-download.test.js +0 -30
- package/dist/tests/prop-upload-download.test.js.map +0 -1
- package/dist/tests/prop-validation.test.d.ts +0 -2
- package/dist/tests/prop-validation.test.d.ts.map +0 -1
- package/dist/tests/prop-validation.test.js +0 -50
- package/dist/tests/prop-validation.test.js.map +0 -1
- package/dist/tests/prop-versioning.test.d.ts +0 -2
- package/dist/tests/prop-versioning.test.d.ts.map +0 -1
- package/dist/tests/prop-versioning.test.js +0 -74
- package/dist/tests/prop-versioning.test.js.map +0 -1
- package/dist/tests/queue-bridge.test.d.ts +0 -2
- package/dist/tests/queue-bridge.test.d.ts.map +0 -1
- package/dist/tests/queue-bridge.test.js +0 -111
- package/dist/tests/queue-bridge.test.js.map +0 -1
- package/dist/tests/r2-driver.test.d.ts +0 -2
- package/dist/tests/r2-driver.test.d.ts.map +0 -1
- package/dist/tests/r2-driver.test.js +0 -143
- package/dist/tests/r2-driver.test.js.map +0 -1
- package/dist/tests/realtime-bridge.test.d.ts +0 -2
- package/dist/tests/realtime-bridge.test.d.ts.map +0 -1
- package/dist/tests/realtime-bridge.test.js +0 -106
- package/dist/tests/realtime-bridge.test.js.map +0 -1
- package/dist/tests/resumable.test.d.ts +0 -2
- package/dist/tests/resumable.test.d.ts.map +0 -1
- package/dist/tests/resumable.test.js +0 -104
- package/dist/tests/resumable.test.js.map +0 -1
- package/dist/tests/s3-base.test.d.ts +0 -2
- package/dist/tests/s3-base.test.d.ts.map +0 -1
- package/dist/tests/s3-base.test.js +0 -289
- package/dist/tests/s3-base.test.js.map +0 -1
- package/dist/tests/s3-integration.test.d.ts +0 -2
- package/dist/tests/s3-integration.test.d.ts.map +0 -1
- package/dist/tests/s3-integration.test.js +0 -270
- package/dist/tests/s3-integration.test.js.map +0 -1
- package/dist/tests/s3.test.d.ts +0 -2
- package/dist/tests/s3.test.d.ts.map +0 -1
- package/dist/tests/s3.test.js +0 -203
- package/dist/tests/s3.test.js.map +0 -1
- package/dist/tests/scaffold.test.d.ts +0 -2
- package/dist/tests/scaffold.test.d.ts.map +0 -1
- package/dist/tests/scaffold.test.js +0 -13
- package/dist/tests/scaffold.test.js.map +0 -1
- package/dist/tests/search.test.d.ts +0 -2
- package/dist/tests/search.test.d.ts.map +0 -1
- package/dist/tests/search.test.js +0 -106
- package/dist/tests/search.test.js.map +0 -1
- package/dist/tests/supabase-driver.test.d.ts +0 -2
- package/dist/tests/supabase-driver.test.d.ts.map +0 -1
- package/dist/tests/supabase-driver.test.js +0 -196
- package/dist/tests/supabase-driver.test.js.map +0 -1
- package/dist/tests/testing-utilities.test.d.ts +0 -2
- package/dist/tests/testing-utilities.test.d.ts.map +0 -1
- package/dist/tests/testing-utilities.test.js +0 -138
- package/dist/tests/testing-utilities.test.js.map +0 -1
- package/dist/tests/validation.test.d.ts +0 -2
- package/dist/tests/validation.test.d.ts.map +0 -1
- package/dist/tests/validation.test.js +0 -135
- package/dist/tests/validation.test.js.map +0 -1
- package/dist/tests/versioning.test.d.ts +0 -2
- package/dist/tests/versioning.test.d.ts.map +0 -1
- package/dist/tests/versioning.test.js +0 -128
- package/dist/tests/versioning.test.js.map +0 -1
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
// Property-based test for the storage facade metadata round-trip guarantee.
|
|
2
|
-
//
|
|
3
|
-
// Feature: unified-storage-framework, Property 5: Metadata round-trips through
|
|
4
|
-
// write and read.
|
|
5
|
-
//
|
|
6
|
-
// For arbitrary keys, byte contents, and write-time metadata (contentType,
|
|
7
|
-
// owner, tenant, accessLevel, and custom fields), after `put(key, bytes,
|
|
8
|
-
// options)` followed by `stat(key)` (and `get(key)`):
|
|
9
|
-
// - the write-supplied fields on the returned metadata equal what was written
|
|
10
|
-
// (owner/tenant/custom exactly; contentType/accessLevel fall back to the
|
|
11
|
-
// canonical defaults when the write omits them), and
|
|
12
|
-
// - the computed fields (size, checksum, etag, createdAt, updatedAt) are all
|
|
13
|
-
// present and consistent with the persisted content.
|
|
14
|
-
//
|
|
15
|
-
// Uses the Node.js built-in test runner (node:test) and fast-check at
|
|
16
|
-
// `{ numRuns: 100 }`, exercising the public facade via
|
|
17
|
-
// `createStorage({ provider: 'memory' })` with a fixed clock so timestamps are
|
|
18
|
-
// deterministic. Executed via `node --test dist/tests/*.test.js`.
|
|
19
|
-
//
|
|
20
|
-
// Validates: Requirements 10.2, 26.4
|
|
21
|
-
import test from "node:test";
|
|
22
|
-
import assert from "node:assert/strict";
|
|
23
|
-
import fc from "fast-check";
|
|
24
|
-
import { createStorage } from "../facade.js";
|
|
25
|
-
import { DEFAULT_ACCESS_LEVEL, DEFAULT_CONTENT_TYPE } from "../metadata.js";
|
|
26
|
-
/** A fixed clock so object timestamps are deterministic across runs. */
|
|
27
|
-
const fixedClock = () => 1_700_000_000_000;
|
|
28
|
-
/** The valid AccessLevel values (Requirement 11.1). */
|
|
29
|
-
const ACCESS_LEVELS = [
|
|
30
|
-
"public",
|
|
31
|
-
"private",
|
|
32
|
-
"signed",
|
|
33
|
-
"authenticated",
|
|
34
|
-
"role-based",
|
|
35
|
-
"tenant-aware",
|
|
36
|
-
];
|
|
37
|
-
/** Arbitrary object content (including empty), persisted as a Uint8Array. */
|
|
38
|
-
const contentArb = fc.uint8Array({ minLength: 0, maxLength: 256 });
|
|
39
|
-
/** Non-empty object keys. */
|
|
40
|
-
const keyArb = fc.string({ minLength: 1, maxLength: 40 });
|
|
41
|
-
/**
|
|
42
|
-
* Arbitrary custom metadata map with comparable JSON-ish values so it can be
|
|
43
|
-
* asserted to round-trip exactly via deepEqual.
|
|
44
|
-
*/
|
|
45
|
-
const customArb = fc.dictionary(fc.string({ maxLength: 20 }), fc.oneof(fc.string(), fc.integer(), fc.boolean()), { maxKeys: 5 });
|
|
46
|
-
/**
|
|
47
|
-
* Arbitrary write-time metadata. Each field is optional (may be absent) so the
|
|
48
|
-
* property covers both explicitly-supplied values and the default fallbacks.
|
|
49
|
-
*/
|
|
50
|
-
const writeMetadataArb = fc.record({
|
|
51
|
-
contentType: fc.string({ minLength: 1, maxLength: 40 }),
|
|
52
|
-
owner: fc.string({ minLength: 1, maxLength: 40 }),
|
|
53
|
-
tenant: fc.string({ minLength: 1, maxLength: 40 }),
|
|
54
|
-
accessLevel: fc.constantFrom(...ACCESS_LEVELS),
|
|
55
|
-
custom: customArb,
|
|
56
|
-
}, { requiredKeys: [] });
|
|
57
|
-
test("Feature: unified-storage-framework, Property 5: Metadata round-trips through write and read", async () => {
|
|
58
|
-
await fc.assert(fc.asyncProperty(keyArb, contentArb, writeMetadataArb, async (key, content, write) => {
|
|
59
|
-
// A fresh store per case keeps each key/content pair independent.
|
|
60
|
-
const storage = createStorage({ provider: "memory", clock: fixedClock });
|
|
61
|
-
const putMeta = await storage.put(key, content, write);
|
|
62
|
-
const statMeta = await storage.stat(key);
|
|
63
|
-
const getResult = await storage.get(key);
|
|
64
|
-
assert.notEqual(statMeta, null, "stat must return metadata for a written key");
|
|
65
|
-
assert.equal(getResult.found, true, "get must find a written key");
|
|
66
|
-
// The write-supplied fields must equal what was written on every surface
|
|
67
|
-
// that returns metadata (put, stat, get).
|
|
68
|
-
for (const meta of [putMeta, statMeta, getResult.metadata]) {
|
|
69
|
-
assert.ok(meta, "metadata must be present on every surface");
|
|
70
|
-
assert.equal(meta.owner, write.owner, "owner must round-trip");
|
|
71
|
-
assert.equal(meta.tenant, write.tenant, "tenant must round-trip");
|
|
72
|
-
assert.equal(meta.contentType, write.contentType ?? DEFAULT_CONTENT_TYPE, "contentType must round-trip (or fall back to the default)");
|
|
73
|
-
assert.equal(meta.accessLevel, write.accessLevel ?? DEFAULT_ACCESS_LEVEL, "accessLevel must round-trip (or fall back to the default)");
|
|
74
|
-
assert.deepEqual(meta.custom, write.custom ?? {}, "custom fields must round-trip (or default to {})");
|
|
75
|
-
// The computed fields must be present and consistent with the content.
|
|
76
|
-
assert.equal(meta.size, content.byteLength, "size must equal the content byte length");
|
|
77
|
-
assert.equal(typeof meta.checksum, "string", "checksum must be present");
|
|
78
|
-
assert.ok(meta.checksum.length > 0, "checksum must be non-empty");
|
|
79
|
-
assert.equal(typeof meta.etag, "string", "etag must be present");
|
|
80
|
-
assert.ok(meta.etag.length > 0, "etag must be non-empty");
|
|
81
|
-
assert.equal(typeof meta.createdAt, "number", "createdAt must be present");
|
|
82
|
-
assert.equal(typeof meta.updatedAt, "number", "updatedAt must be present");
|
|
83
|
-
}
|
|
84
|
-
await storage.close();
|
|
85
|
-
}), { numRuns: 100 });
|
|
86
|
-
});
|
|
87
|
-
//# sourceMappingURL=prop-metadata.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-metadata.test.js","sourceRoot":"","sources":["../../src/tests/prop-metadata.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-move.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-move.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
// Property test: move relocates content and removes the source.
|
|
2
|
-
//
|
|
3
|
-
// Feature: unified-storage-framework, Property 3: Move relocates content and
|
|
4
|
-
// removes the source.
|
|
5
|
-
// Validates: Requirements 4.7, 4.8, 26.3
|
|
6
|
-
//
|
|
7
|
-
// Req 4.7: `move(source, destination)` relocates the object — the content
|
|
8
|
-
// becomes available at `destination` and the source object is removed.
|
|
9
|
-
// Req 4.8: after a successful relocation the source key no longer exists.
|
|
10
|
-
// Req 26.3: the observable move semantics hold across arbitrary keys/content.
|
|
11
|
-
//
|
|
12
|
-
// Strategy: through the real facade built with the zero-dependency memory
|
|
13
|
-
// provider (`createStorage({ provider: "memory" })`), for arbitrary DISTINCT
|
|
14
|
-
// source/destination keys and arbitrary content bytes:
|
|
15
|
-
// 1. `put(source, bytes)` stores the content,
|
|
16
|
-
// 2. `move(source, dest)` relocates it, and we assert the four observable
|
|
17
|
-
// consequences of a successful move:
|
|
18
|
-
// (a) the move result is `{ moved: true }`,
|
|
19
|
-
// (b) `get(dest)` returns bytes byte-for-byte equal to the original,
|
|
20
|
-
// (c) `exists(source)` is now false, and
|
|
21
|
-
// (d) `get(source)` reports `{ found: false }`.
|
|
22
|
-
// A control case guards the not-found path: moving a source that was never
|
|
23
|
-
// stored returns `{ moved: false }` without throwing.
|
|
24
|
-
//
|
|
25
|
-
// Uses the Node.js built-in test runner (node:test) and fast-check at the
|
|
26
|
-
// spec-mandated `{ numRuns: 100 }`.
|
|
27
|
-
import test from "node:test";
|
|
28
|
-
import assert from "node:assert/strict";
|
|
29
|
-
import fc from "fast-check";
|
|
30
|
-
import { createStorage } from "../index.js";
|
|
31
|
-
/**
|
|
32
|
-
* Generate two distinct, non-empty object keys. fast-check's `uniqueArray`
|
|
33
|
-
* guarantees the pair differs, so `source` and `destination` never collide
|
|
34
|
-
* (a collision would make "removes the source" ambiguous).
|
|
35
|
-
*/
|
|
36
|
-
const distinctKeys = fc
|
|
37
|
-
.uniqueArray(fc.string({ minLength: 1, maxLength: 40 }).filter((s) => s.trim().length > 0), { minLength: 2, maxLength: 2 })
|
|
38
|
-
.map(([source, destination]) => ({ source, destination }));
|
|
39
|
-
test("Feature: unified-storage-framework, Property 3: move relocates content and removes the source", async () => {
|
|
40
|
-
await fc.assert(fc.asyncProperty(distinctKeys, fc.uint8Array({ minLength: 0, maxLength: 512 }), async ({ source, destination }, content) => {
|
|
41
|
-
const storage = createStorage({ provider: "memory" });
|
|
42
|
-
await storage.put(source, content);
|
|
43
|
-
const result = await storage.move(source, destination);
|
|
44
|
-
// (a) the move reports success.
|
|
45
|
-
assert.equal(result.moved, true);
|
|
46
|
-
// (b) the destination now holds the original bytes, unchanged.
|
|
47
|
-
const atDest = await storage.get(destination);
|
|
48
|
-
assert.equal(atDest.found, true);
|
|
49
|
-
assert.deepEqual(atDest.bytes, content);
|
|
50
|
-
// (c) the source no longer exists.
|
|
51
|
-
assert.equal(await storage.exists(source), false);
|
|
52
|
-
// (d) reading the source reports not-found (never throws).
|
|
53
|
-
const atSource = await storage.get(source);
|
|
54
|
-
assert.equal(atSource.found, false);
|
|
55
|
-
}), { numRuns: 100 });
|
|
56
|
-
});
|
|
57
|
-
test("Feature: unified-storage-framework, Property 3: moving a missing source returns { moved: false }", async () => {
|
|
58
|
-
await fc.assert(fc.asyncProperty(distinctKeys, async ({ source, destination }) => {
|
|
59
|
-
const storage = createStorage({ provider: "memory" });
|
|
60
|
-
// Nothing was ever stored under `source`.
|
|
61
|
-
const result = await storage.move(source, destination);
|
|
62
|
-
assert.equal(result.moved, false);
|
|
63
|
-
// No object is fabricated at the destination.
|
|
64
|
-
assert.equal(await storage.exists(destination), false);
|
|
65
|
-
}), { numRuns: 100 });
|
|
66
|
-
});
|
|
67
|
-
//# sourceMappingURL=prop-move.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-move.test.js","sourceRoot":"","sources":["../../src/tests/prop-move.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-multipart-abort.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-multipart-abort.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// Property-based test for the storage facade's multipart abort guarantee.
|
|
2
|
-
//
|
|
3
|
-
// Property 9 (Abort leaves no object): for an arbitrary key and an arbitrary
|
|
4
|
-
// list of parts uploaded via `createMultipartUpload` → `uploadPart` for each
|
|
5
|
-
// part, calling `abortMultipartUpload(uploadId)` discards every uploaded part
|
|
6
|
-
// and creates no completed object. After the abort the target key must not
|
|
7
|
-
// exist (`exists(key) === false`) and reading it must report not-found, so no
|
|
8
|
-
// leftover final object is ever produced by the aborted upload (Requirement
|
|
9
|
-
// 6.4). The abort path runs over the zero-dependency `memory` provider — the
|
|
10
|
-
// identical code path every provider shares — exercised via the public facade.
|
|
11
|
-
//
|
|
12
|
-
// Uses the Node.js built-in test runner (node:test) with fast-check for input
|
|
13
|
-
// generation, executed via `node --test dist/tests/*.test.js`. fast-check is
|
|
14
|
-
// configured with { numRuns: 100 } per the design's property-testing contract.
|
|
15
|
-
//
|
|
16
|
-
// Feature: unified-storage-framework, Property 9: Abort leaves no object
|
|
17
|
-
//
|
|
18
|
-
// Validates: Requirements 6.4
|
|
19
|
-
import test from "node:test";
|
|
20
|
-
import assert from "node:assert/strict";
|
|
21
|
-
import fc from "fast-check";
|
|
22
|
-
import { createStorage } from "../index.js";
|
|
23
|
-
test("Feature: unified-storage-framework, Property 9: Abort leaves no object", async () => {
|
|
24
|
-
await fc.assert(fc.asyncProperty(
|
|
25
|
-
// An arbitrary target key for the multipart upload and an arbitrary
|
|
26
|
-
// ordered list of parts. At least one part is generated so there is
|
|
27
|
-
// always something to upload before aborting; individual parts may be
|
|
28
|
-
// empty, exercising abort after zero-length segments.
|
|
29
|
-
fc.string(), fc.array(fc.uint8Array(), { minLength: 1, maxLength: 8 }), async (key, parts) => {
|
|
30
|
-
// A fresh store per run keeps each key/parts pair independent.
|
|
31
|
-
const storage = createStorage({ provider: "memory" });
|
|
32
|
-
// ── Upload parts, then abort ──────────────────────────────────────
|
|
33
|
-
const uploadId = await storage.createMultipartUpload(key);
|
|
34
|
-
for (let index = 0; index < parts.length; index += 1) {
|
|
35
|
-
// Part numbers are 1-based positive integers assigned in order.
|
|
36
|
-
await storage.uploadPart(uploadId, index + 1, parts[index]);
|
|
37
|
-
}
|
|
38
|
-
await storage.abortMultipartUpload(uploadId);
|
|
39
|
-
// The aborted upload must create no completed object at the key: the
|
|
40
|
-
// key must not exist and reading it must report not-found (no
|
|
41
|
-
// leftover final object).
|
|
42
|
-
assert.equal(await storage.exists(key), false, "aborted multipart upload must leave no object at the target key");
|
|
43
|
-
const result = await storage.get(key);
|
|
44
|
-
assert.equal(result.found, false, "reading the target key after abort must report not-found");
|
|
45
|
-
await storage.close();
|
|
46
|
-
}), { numRuns: 100 });
|
|
47
|
-
});
|
|
48
|
-
//# sourceMappingURL=prop-multipart-abort.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-multipart-abort.test.js","sourceRoot":"","sources":["../../src/tests/prop-multipart-abort.test.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,8EAA8E;AAC9E,2EAA2E;AAC3E,8EAA8E;AAC9E,4EAA4E;AAC5E,6EAA6E;AAC7E,+EAA+E;AAC/E,EAAE;AACF,8EAA8E;AAC9E,6EAA6E;AAC7E,+EAA+E;AAC/E,EAAE;AACF,yEAAyE;AACzE,EAAE;AACF,8BAA8B;AAE9B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAExC,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,IAAI,CACF,wEAAwE,EACxE,KAAK,IAAI,EAAE;IACT,MAAM,EAAE,CAAC,MAAM,CACb,EAAE,CAAC,aAAa;IACd,oEAAoE;IACpE,oEAAoE;IACpE,sEAAsE;IACtE,sDAAsD;IACtD,EAAE,CAAC,MAAM,EAAE,EACX,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,EACzD,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACnB,+DAA+D;QAC/D,MAAM,OAAO,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEtD,qEAAqE;QACrE,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAC1D,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;YACrD,gEAAgE;YAChE,MAAM,OAAO,CAAC,UAAU,CAAC,QAAQ,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9D,CAAC;QAED,MAAM,OAAO,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QAE7C,qEAAqE;QACrE,8DAA8D;QAC9D,0BAA0B;QAC1B,MAAM,CAAC,KAAK,CACV,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EACzB,KAAK,EACL,iEAAiE,CAClE,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CACV,MAAM,CAAC,KAAK,EACZ,KAAK,EACL,0DAA0D,CAC3D,CAAC;QAEF,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC,CACF,EACD,EAAE,OAAO,EAAE,GAAG,EAAE,CACjB,CAAC;AACJ,CAAC,CACF,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-multipart.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-multipart.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
// Property-based test for the storage facade's multipart upload guarantee.
|
|
2
|
-
//
|
|
3
|
-
// Property 8 (Multipart equals a single upload): for arbitrary content split
|
|
4
|
-
// into arbitrary ordered parts, performing a multipart upload
|
|
5
|
-
// (`createMultipartUpload` → `uploadPart` for each part in order →
|
|
6
|
-
// `completeMultipartUpload`) produces an object whose bytes are exactly equal
|
|
7
|
-
// to a single `put` of the concatenation of those parts. Equality is checked
|
|
8
|
-
// both by the raw stored bytes and by the content checksum the drivers compute,
|
|
9
|
-
// so the multipart assembly path is proven observationally identical to the
|
|
10
|
-
// single-shot write path (Requirement 6.3). Both uploads run over the
|
|
11
|
-
// zero-dependency `memory` provider — the identical code path every provider
|
|
12
|
-
// shares — exercised via the public facade.
|
|
13
|
-
//
|
|
14
|
-
// Uses the Node.js built-in test runner (node:test) with fast-check for input
|
|
15
|
-
// generation, executed via `node --test dist/tests/*.test.js`. fast-check is
|
|
16
|
-
// configured with { numRuns: 100 } per the design's property-testing contract.
|
|
17
|
-
//
|
|
18
|
-
// Feature: unified-storage-framework, Property 8: Multipart equals a single upload
|
|
19
|
-
//
|
|
20
|
-
// Validates: Requirements 6.3, 26.5
|
|
21
|
-
import test from "node:test";
|
|
22
|
-
import assert from "node:assert/strict";
|
|
23
|
-
import { Buffer } from "node:buffer";
|
|
24
|
-
import fc from "fast-check";
|
|
25
|
-
import { createStorage } from "../facade.js";
|
|
26
|
-
test("Feature: unified-storage-framework, Property 8: Multipart equals a single upload", async () => {
|
|
27
|
-
await fc.assert(fc.asyncProperty(
|
|
28
|
-
// A key for both objects and an arbitrary ordered list of parts. At
|
|
29
|
-
// least one part is generated so there is always something to upload;
|
|
30
|
-
// individual parts may be empty, exercising the assembly of zero-length
|
|
31
|
-
// segments.
|
|
32
|
-
fc.string(), fc.array(fc.uint8Array(), { minLength: 1, maxLength: 8 }), async (key, parts) => {
|
|
33
|
-
// A fresh store per run keeps each key/parts pair independent.
|
|
34
|
-
const storage = createStorage({ provider: "memory" });
|
|
35
|
-
// The concatenation of the parts, in the order they will be uploaded,
|
|
36
|
-
// is the exact byte sequence a single `put` would persist.
|
|
37
|
-
const concatenated = Buffer.concat(parts.map((part) => Buffer.from(part)));
|
|
38
|
-
// ── Multipart upload path ─────────────────────────────────────────
|
|
39
|
-
const multipartKey = `${key}/multipart`;
|
|
40
|
-
const uploadId = await storage.createMultipartUpload(multipartKey);
|
|
41
|
-
const storedParts = [];
|
|
42
|
-
for (let index = 0; index < parts.length; index += 1) {
|
|
43
|
-
// Part numbers are 1-based positive integers assigned in order.
|
|
44
|
-
const stored = await storage.uploadPart(uploadId, index + 1, parts[index]);
|
|
45
|
-
storedParts.push(stored);
|
|
46
|
-
}
|
|
47
|
-
const multipartMeta = await storage.completeMultipartUpload(uploadId, storedParts);
|
|
48
|
-
// ── Single upload path ────────────────────────────────────────────
|
|
49
|
-
const singleKey = `${key}/single`;
|
|
50
|
-
const singleMeta = await storage.put(singleKey, concatenated);
|
|
51
|
-
// The assembled object must equal a single put of the concatenation,
|
|
52
|
-
// both in raw bytes and in the computed content checksum.
|
|
53
|
-
const multipartResult = await storage.get(multipartKey);
|
|
54
|
-
const singleResult = await storage.get(singleKey);
|
|
55
|
-
assert.equal(multipartResult.found, true);
|
|
56
|
-
assert.equal(singleResult.found, true);
|
|
57
|
-
assert.ok(multipartResult.bytes);
|
|
58
|
-
assert.ok(singleResult.bytes);
|
|
59
|
-
assert.deepEqual(Buffer.from(multipartResult.bytes), Buffer.from(singleResult.bytes));
|
|
60
|
-
assert.deepEqual(Buffer.from(multipartResult.bytes), concatenated);
|
|
61
|
-
assert.equal(multipartMeta.checksum, singleMeta.checksum);
|
|
62
|
-
assert.equal(multipartMeta.size, singleMeta.size);
|
|
63
|
-
}), { numRuns: 100 });
|
|
64
|
-
});
|
|
65
|
-
//# sourceMappingURL=prop-multipart.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-multipart.test.js","sourceRoot":"","sources":["../../src/tests/prop-multipart.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-resumable.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-resumable.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
// Property-based test for the resumable upload equivalence guarantee.
|
|
2
|
-
//
|
|
3
|
-
// Property 10 (Resumable equals uninterrupted): for arbitrary content, a
|
|
4
|
-
// resumable upload — optionally interrupted partway (a first `resumeUpload`
|
|
5
|
-
// whose source stream errors after emitting a prefix) and then resumed with the
|
|
6
|
-
// object's full content — produces an object byte-identical to an equivalent
|
|
7
|
-
// single, uninterrupted `put` of the same content on a separate store. The
|
|
8
|
-
// upload is driven through `startUpload` → (optional failing `resumeUpload`) →
|
|
9
|
-
// `resumeUpload(full stream)`; the resulting bytes and checksum are compared
|
|
10
|
-
// against a plain `put` on an independent `memory` store.
|
|
11
|
-
//
|
|
12
|
-
// This exercises the facade's ResumableManager over the zero-dependency
|
|
13
|
-
// `memory` provider, driving the identical offset-tracked resume code path
|
|
14
|
-
// every provider shares (Requirements 7.2, 7.3), and asserts the cross-path
|
|
15
|
-
// determinism the framework guarantees (Requirement 26.5).
|
|
16
|
-
//
|
|
17
|
-
// Uses the Node.js built-in test runner (node:test) with fast-check for input
|
|
18
|
-
// generation, executed via `node --test dist/tests/*.test.js`. fast-check is
|
|
19
|
-
// configured with { numRuns: 100 } per the design's property-testing contract.
|
|
20
|
-
//
|
|
21
|
-
// Feature: unified-storage-framework, Property 10: Resumable equals uninterrupted
|
|
22
|
-
//
|
|
23
|
-
// Validates: Requirements 7.2, 7.3, 26.5
|
|
24
|
-
import test from "node:test";
|
|
25
|
-
import assert from "node:assert/strict";
|
|
26
|
-
import { Readable } from "node:stream";
|
|
27
|
-
import { Buffer } from "node:buffer";
|
|
28
|
-
import fc from "fast-check";
|
|
29
|
-
import { createStorage } from "../facade.js";
|
|
30
|
-
test("Feature: unified-storage-framework, Property 10: Resumable equals uninterrupted", async () => {
|
|
31
|
-
await fc.assert(fc.asyncProperty(fc.string(), fc.uint8Array(),
|
|
32
|
-
// `interrupt` decides whether the upload is interrupted before its
|
|
33
|
-
// final resume; `prefixLen` (bounded to the content) picks how many
|
|
34
|
-
// bytes the interrupted resume persists before erroring.
|
|
35
|
-
fc.boolean(), fc.nat(), async (key, content, interrupt, prefixLen) => {
|
|
36
|
-
const payload = Buffer.from(content);
|
|
37
|
-
// The resumable store: start a session, optionally interrupt, then
|
|
38
|
-
// resume with the FULL content.
|
|
39
|
-
const resumableStore = createStorage({ provider: "memory" });
|
|
40
|
-
const sessionId = await resumableStore.startUpload(key, {});
|
|
41
|
-
if (interrupt && payload.byteLength > 0) {
|
|
42
|
-
// Emit a prefix of the content then error partway, simulating a
|
|
43
|
-
// network interruption. Only the prefix is persisted (Req 7.2).
|
|
44
|
-
const cut = prefixLen % payload.byteLength;
|
|
45
|
-
const prefix = payload.subarray(0, cut);
|
|
46
|
-
const failing = new Readable({
|
|
47
|
-
read() {
|
|
48
|
-
if (prefix.byteLength > 0) {
|
|
49
|
-
this.push(prefix);
|
|
50
|
-
}
|
|
51
|
-
this.destroy(new Error("network interruption"));
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
await assert.rejects(() => resumableStore.resumeUpload(sessionId, failing), /network interruption/);
|
|
55
|
-
// No final object exists yet after an interrupted resume.
|
|
56
|
-
assert.equal(await resumableStore.exists(key), false);
|
|
57
|
-
}
|
|
58
|
-
// Resume with the full content: the manager appends only the bytes
|
|
59
|
-
// beyond the persisted offset and completes (Req 7.3).
|
|
60
|
-
const resumedMeta = await resumableStore.resumeUpload(sessionId, Readable.from([payload]));
|
|
61
|
-
// The reference store: a single, uninterrupted put of the same bytes.
|
|
62
|
-
const referenceStore = createStorage({ provider: "memory" });
|
|
63
|
-
const singleMeta = await referenceStore.put(key, new Uint8Array(payload), {});
|
|
64
|
-
// Byte-identical object: same size and checksum as the single put.
|
|
65
|
-
assert.equal(resumedMeta.size, singleMeta.size);
|
|
66
|
-
assert.equal(resumedMeta.checksum, singleMeta.checksum);
|
|
67
|
-
// And the stored bytes read back equal on both stores.
|
|
68
|
-
const resumedGet = await resumableStore.get(key);
|
|
69
|
-
const referenceGet = await referenceStore.get(key);
|
|
70
|
-
assert.equal(resumedGet.found, true);
|
|
71
|
-
assert.equal(referenceGet.found, true);
|
|
72
|
-
assert.ok(resumedGet.bytes);
|
|
73
|
-
assert.ok(referenceGet.bytes);
|
|
74
|
-
assert.deepEqual(Buffer.from(resumedGet.bytes), payload);
|
|
75
|
-
assert.deepEqual(Buffer.from(resumedGet.bytes), Buffer.from(referenceGet.bytes));
|
|
76
|
-
}), { numRuns: 100 });
|
|
77
|
-
});
|
|
78
|
-
//# sourceMappingURL=prop-resumable.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-resumable.test.js","sourceRoot":"","sources":["../../src/tests/prop-resumable.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-search.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-search.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
// Property-based test for the storage facade `search(filters)` operation.
|
|
2
|
-
//
|
|
3
|
-
// Feature: unified-storage-framework, Property 15 — Search returns exactly the
|
|
4
|
-
// matching objects. For an arbitrary set of stored objects (with varied
|
|
5
|
-
// owner/tenant/contentType/size/custom metadata) and an arbitrary combination
|
|
6
|
-
// of SearchFilters, `storage.search(filters)` returns EXACTLY the set of
|
|
7
|
-
// objects that satisfy EVERY supplied filter (conjunctive / AND semantics):
|
|
8
|
-
// no matching object is missing and no non-matching object is included. When
|
|
9
|
-
// no object satisfies the filters, the result is the empty set.
|
|
10
|
-
//
|
|
11
|
-
// The expected set is computed independently of the implementation and
|
|
12
|
-
// compared for exact set equality.
|
|
13
|
-
//
|
|
14
|
-
// Uses the public facade via `createStorage({ provider: 'memory' })`, the
|
|
15
|
-
// Node.js built-in test runner (node:test), and fast-check configured with
|
|
16
|
-
// { numRuns: 100 }. Executed via `node --test dist/tests/*.test.js`.
|
|
17
|
-
//
|
|
18
|
-
// Validates: Requirements 16.2, 16.3
|
|
19
|
-
import test from "node:test";
|
|
20
|
-
import assert from "node:assert/strict";
|
|
21
|
-
import fc from "fast-check";
|
|
22
|
-
import { createStorage } from "../index.js";
|
|
23
|
-
// UTF-8 byte length, matching how the facade encodes string payloads before
|
|
24
|
-
// the driver records `size`.
|
|
25
|
-
const byteSize = (content) => new TextEncoder().encode(content).length;
|
|
26
|
-
// Domains kept small so filters match frequently, exercising both the
|
|
27
|
-
// "matches" and "excludes nothing/everything" branches.
|
|
28
|
-
const ownerArb = fc.option(fc.constantFrom("alice", "bob"), { nil: undefined });
|
|
29
|
-
const tenantArb = fc.option(fc.constantFrom("acme", "globex"), { nil: undefined });
|
|
30
|
-
const contentTypeArb = fc.constantFrom("image/jpeg", "image/png", "text/plain");
|
|
31
|
-
const categoryArb = fc.option(fc.constantFrom("invoice", "receipt"), { nil: undefined });
|
|
32
|
-
// Keys drawn from a small alphabet so shared prefixes arise often. The alphabet
|
|
33
|
-
// excludes '.', so no key collides with the reserved internal key spaces.
|
|
34
|
-
const keyArb = fc.stringMatching(/^[a-c/]{1,6}$/).filter((k) => k.length > 0);
|
|
35
|
-
// An object to store: a key, content (whose byte length gives size), and
|
|
36
|
-
// varied metadata.
|
|
37
|
-
const objectArb = fc.record({
|
|
38
|
-
key: keyArb,
|
|
39
|
-
content: fc.string({ maxLength: 6 }),
|
|
40
|
-
owner: ownerArb,
|
|
41
|
-
tenant: tenantArb,
|
|
42
|
-
contentType: contentTypeArb,
|
|
43
|
-
category: categoryArb,
|
|
44
|
-
});
|
|
45
|
-
// Arbitrary SearchFilters. Every field is optional (undefined => no
|
|
46
|
-
// constraint). Filter domains deliberately include values that may match
|
|
47
|
-
// nothing (e.g. owner "carol") so the empty-result case is covered.
|
|
48
|
-
const filtersArb = fc.record({
|
|
49
|
-
prefix: fc.option(fc.stringMatching(/^[a-c/]{0,3}$/), { nil: undefined }),
|
|
50
|
-
contentType: fc.option(fc.constantFrom("image/jpeg", "image/png", "text/plain", "application/pdf"), {
|
|
51
|
-
nil: undefined,
|
|
52
|
-
}),
|
|
53
|
-
owner: fc.option(fc.constantFrom("alice", "bob", "carol"), { nil: undefined }),
|
|
54
|
-
tenant: fc.option(fc.constantFrom("acme", "globex", "initech"), { nil: undefined }),
|
|
55
|
-
minSize: fc.option(fc.integer({ min: 0, max: 6 }), { nil: undefined }),
|
|
56
|
-
maxSize: fc.option(fc.integer({ min: 0, max: 6 }), { nil: undefined }),
|
|
57
|
-
metadata: fc.option(fc.constantFrom({ category: "invoice" }, { category: "receipt" }), {
|
|
58
|
-
nil: undefined,
|
|
59
|
-
}),
|
|
60
|
-
});
|
|
61
|
-
// Independent reference implementation of the AND-semantics filter, evaluated
|
|
62
|
-
// against the known write-time metadata of a stored object.
|
|
63
|
-
function satisfies(obj, filters) {
|
|
64
|
-
const size = byteSize(obj.content);
|
|
65
|
-
const custom = obj.category !== undefined ? { category: obj.category } : {};
|
|
66
|
-
if (filters.prefix !== undefined && !obj.key.startsWith(filters.prefix))
|
|
67
|
-
return false;
|
|
68
|
-
if (filters.contentType !== undefined && obj.contentType !== filters.contentType)
|
|
69
|
-
return false;
|
|
70
|
-
if (filters.owner !== undefined && obj.owner !== filters.owner)
|
|
71
|
-
return false;
|
|
72
|
-
if (filters.tenant !== undefined && obj.tenant !== filters.tenant)
|
|
73
|
-
return false;
|
|
74
|
-
if (filters.minSize !== undefined && size < filters.minSize)
|
|
75
|
-
return false;
|
|
76
|
-
if (filters.maxSize !== undefined && size > filters.maxSize)
|
|
77
|
-
return false;
|
|
78
|
-
if (filters.metadata !== undefined) {
|
|
79
|
-
for (const [field, value] of Object.entries(filters.metadata)) {
|
|
80
|
-
if (custom[field] !== value)
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
test("Feature: unified-storage-framework, Property 15 — search returns exactly the matching objects", async () => {
|
|
87
|
-
await fc.assert(fc.asyncProperty(fc.uniqueArray(objectArb, {
|
|
88
|
-
selector: (obj) => obj.key,
|
|
89
|
-
minLength: 0,
|
|
90
|
-
maxLength: 12,
|
|
91
|
-
}), filtersArb, async (objects, filters) => {
|
|
92
|
-
const storage = createStorage({ provider: "memory" });
|
|
93
|
-
for (const obj of objects) {
|
|
94
|
-
const metadata = {
|
|
95
|
-
contentType: obj.contentType,
|
|
96
|
-
};
|
|
97
|
-
if (obj.owner !== undefined)
|
|
98
|
-
metadata.owner = obj.owner;
|
|
99
|
-
if (obj.tenant !== undefined)
|
|
100
|
-
metadata.tenant = obj.tenant;
|
|
101
|
-
if (obj.category !== undefined)
|
|
102
|
-
metadata.custom = { category: obj.category };
|
|
103
|
-
await storage.put(obj.key, obj.content, metadata);
|
|
104
|
-
}
|
|
105
|
-
const result = await storage.search(filters);
|
|
106
|
-
const observed = new Set(result.map((item) => item.key));
|
|
107
|
-
// Expected: exactly the stored keys whose object satisfies every filter.
|
|
108
|
-
const expected = new Set(objects.filter((obj) => satisfies(obj, filters)).map((obj) => obj.key));
|
|
109
|
-
// Exact set equality: same cardinality + same membership (no extras,
|
|
110
|
-
// none missing). An empty expected set implies an empty result.
|
|
111
|
-
assert.equal(observed.size, expected.size, `size mismatch: observed ${[...observed]} vs expected ${[...expected]}`);
|
|
112
|
-
for (const key of expected) {
|
|
113
|
-
assert.ok(observed.has(key), `missing matching key: ${key}`);
|
|
114
|
-
}
|
|
115
|
-
for (const key of observed) {
|
|
116
|
-
assert.ok(expected.has(key), `unexpected non-matching key: ${key}`);
|
|
117
|
-
}
|
|
118
|
-
}), { numRuns: 100 });
|
|
119
|
-
});
|
|
120
|
-
//# sourceMappingURL=prop-search.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-search.test.js","sourceRoot":"","sources":["../../src/tests/prop-search.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-signed-url.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-signed-url.test.ts"],"names":[],"mappings":""}
|