@streetjs/storage 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 +21 -0
- package/README.md +719 -0
- package/dist/access.d.ts +95 -0
- package/dist/access.d.ts.map +1 -0
- package/dist/access.js +114 -0
- package/dist/access.js.map +1 -0
- package/dist/cli/commands.d.ts +88 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +369 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/generators.d.ts +41 -0
- package/dist/cli/generators.d.ts.map +1 -0
- package/dist/cli/generators.js +119 -0
- package/dist/cli/generators.js.map +1 -0
- package/dist/directory.d.ts +88 -0
- package/dist/directory.d.ts.map +1 -0
- package/dist/directory.js +148 -0
- package/dist/directory.js.map +1 -0
- package/dist/driver.d.ts +83 -0
- package/dist/driver.d.ts.map +1 -0
- package/dist/driver.js +16 -0
- package/dist/driver.js.map +1 -0
- package/dist/drivers/azure.d.ts +239 -0
- package/dist/drivers/azure.d.ts.map +1 -0
- package/dist/drivers/azure.js +476 -0
- package/dist/drivers/azure.js.map +1 -0
- package/dist/drivers/backblaze.d.ts +105 -0
- package/dist/drivers/backblaze.d.ts.map +1 -0
- package/dist/drivers/backblaze.js +279 -0
- package/dist/drivers/backblaze.js.map +1 -0
- package/dist/drivers/gcs.d.ts +239 -0
- package/dist/drivers/gcs.d.ts.map +1 -0
- package/dist/drivers/gcs.js +454 -0
- package/dist/drivers/gcs.js.map +1 -0
- package/dist/drivers/local.d.ts +126 -0
- package/dist/drivers/local.d.ts.map +1 -0
- package/dist/drivers/local.js +321 -0
- package/dist/drivers/local.js.map +1 -0
- package/dist/drivers/memory.d.ts +104 -0
- package/dist/drivers/memory.d.ts.map +1 -0
- package/dist/drivers/memory.js +197 -0
- package/dist/drivers/memory.js.map +1 -0
- package/dist/drivers/minio.d.ts +90 -0
- package/dist/drivers/minio.d.ts.map +1 -0
- package/dist/drivers/minio.js +276 -0
- package/dist/drivers/minio.js.map +1 -0
- package/dist/drivers/r2.d.ts +100 -0
- package/dist/drivers/r2.d.ts.map +1 -0
- package/dist/drivers/r2.js +240 -0
- package/dist/drivers/r2.js.map +1 -0
- package/dist/drivers/s3-base.d.ts +270 -0
- package/dist/drivers/s3-base.d.ts.map +1 -0
- package/dist/drivers/s3-base.js +436 -0
- package/dist/drivers/s3-base.js.map +1 -0
- package/dist/drivers/s3.d.ts +111 -0
- package/dist/drivers/s3.d.ts.map +1 -0
- package/dist/drivers/s3.js +311 -0
- package/dist/drivers/s3.js.map +1 -0
- package/dist/drivers/supabase.d.ts +246 -0
- package/dist/drivers/supabase.d.ts.map +1 -0
- package/dist/drivers/supabase.js +502 -0
- package/dist/drivers/supabase.js.map +1 -0
- package/dist/errors.d.ts +115 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +131 -0
- package/dist/errors.js.map +1 -0
- package/dist/examples/storage-demo.d.ts +53 -0
- package/dist/examples/storage-demo.d.ts.map +1 -0
- package/dist/examples/storage-demo.js +242 -0
- package/dist/examples/storage-demo.js.map +1 -0
- package/dist/facade.d.ts +192 -0
- package/dist/facade.d.ts.map +1 -0
- package/dist/facade.js +898 -0
- package/dist/facade.js.map +1 -0
- package/dist/image.d.ts +94 -0
- package/dist/image.d.ts.map +1 -0
- package/dist/image.js +224 -0
- package/dist/image.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/events.d.ts +108 -0
- package/dist/integrations/events.d.ts.map +1 -0
- package/dist/integrations/events.js +111 -0
- package/dist/integrations/events.js.map +1 -0
- package/dist/integrations/queue.d.ts +89 -0
- package/dist/integrations/queue.d.ts.map +1 -0
- package/dist/integrations/queue.js +91 -0
- package/dist/integrations/queue.js.map +1 -0
- package/dist/integrations/realtime.d.ts +95 -0
- package/dist/integrations/realtime.d.ts.map +1 -0
- package/dist/integrations/realtime.js +90 -0
- package/dist/integrations/realtime.js.map +1 -0
- package/dist/lifecycle.d.ts +137 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +240 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/metadata.d.ts +109 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +139 -0
- package/dist/metadata.js.map +1 -0
- package/dist/multipart.d.ts +108 -0
- package/dist/multipart.d.ts.map +1 -0
- package/dist/multipart.js +200 -0
- package/dist/multipart.js.map +1 -0
- package/dist/observability.d.ts +82 -0
- package/dist/observability.d.ts.map +1 -0
- package/dist/observability.js +175 -0
- package/dist/observability.js.map +1 -0
- package/dist/plugin.d.ts +82 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +100 -0
- package/dist/plugin.js.map +1 -0
- package/dist/resumable.d.ts +118 -0
- package/dist/resumable.d.ts.map +1 -0
- package/dist/resumable.js +223 -0
- package/dist/resumable.js.map +1 -0
- package/dist/search.d.ts +57 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +172 -0
- package/dist/search.js.map +1 -0
- package/dist/signed-url.d.ts +110 -0
- package/dist/signed-url.d.ts.map +1 -0
- package/dist/signed-url.js +237 -0
- package/dist/signed-url.js.map +1 -0
- package/dist/testing/index.d.ts +219 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +393 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/tests/access.test.d.ts +2 -0
- package/dist/tests/access.test.d.ts.map +1 -0
- package/dist/tests/access.test.js +270 -0
- package/dist/tests/access.test.js.map +1 -0
- package/dist/tests/azure-driver.test.d.ts +2 -0
- package/dist/tests/azure-driver.test.d.ts.map +1 -0
- package/dist/tests/azure-driver.test.js +183 -0
- package/dist/tests/azure-driver.test.js.map +1 -0
- package/dist/tests/backblaze-driver.test.d.ts +2 -0
- package/dist/tests/backblaze-driver.test.d.ts.map +1 -0
- package/dist/tests/backblaze-driver.test.js +185 -0
- package/dist/tests/backblaze-driver.test.js.map +1 -0
- package/dist/tests/bridge-degradation.test.d.ts +2 -0
- package/dist/tests/bridge-degradation.test.d.ts.map +1 -0
- package/dist/tests/bridge-degradation.test.js +138 -0
- package/dist/tests/bridge-degradation.test.js.map +1 -0
- package/dist/tests/cli.test.d.ts +2 -0
- package/dist/tests/cli.test.d.ts.map +1 -0
- package/dist/tests/cli.test.js +127 -0
- package/dist/tests/cli.test.js.map +1 -0
- package/dist/tests/contract.d.ts +131 -0
- package/dist/tests/contract.d.ts.map +1 -0
- package/dist/tests/contract.js +222 -0
- package/dist/tests/contract.js.map +1 -0
- package/dist/tests/contract.test.d.ts +2 -0
- package/dist/tests/contract.test.d.ts.map +1 -0
- package/dist/tests/contract.test.js +110 -0
- package/dist/tests/contract.test.js.map +1 -0
- package/dist/tests/directory.test.d.ts +2 -0
- package/dist/tests/directory.test.d.ts.map +1 -0
- package/dist/tests/directory.test.js +125 -0
- package/dist/tests/directory.test.js.map +1 -0
- package/dist/tests/errors.test.d.ts +2 -0
- package/dist/tests/errors.test.d.ts.map +1 -0
- package/dist/tests/errors.test.js +93 -0
- package/dist/tests/errors.test.js.map +1 -0
- package/dist/tests/events-bridge.test.d.ts +2 -0
- package/dist/tests/events-bridge.test.d.ts.map +1 -0
- package/dist/tests/events-bridge.test.js +228 -0
- package/dist/tests/events-bridge.test.js.map +1 -0
- package/dist/tests/example-smoke.test.d.ts +2 -0
- package/dist/tests/example-smoke.test.d.ts.map +1 -0
- package/dist/tests/example-smoke.test.js +34 -0
- package/dist/tests/example-smoke.test.js.map +1 -0
- package/dist/tests/gcs-driver.test.d.ts +2 -0
- package/dist/tests/gcs-driver.test.d.ts.map +1 -0
- package/dist/tests/gcs-driver.test.js +197 -0
- package/dist/tests/gcs-driver.test.js.map +1 -0
- package/dist/tests/image.test.d.ts +2 -0
- package/dist/tests/image.test.d.ts.map +1 -0
- package/dist/tests/image.test.js +102 -0
- package/dist/tests/image.test.js.map +1 -0
- package/dist/tests/lifecycle.test.d.ts +2 -0
- package/dist/tests/lifecycle.test.d.ts.map +1 -0
- package/dist/tests/lifecycle.test.js +171 -0
- package/dist/tests/lifecycle.test.js.map +1 -0
- package/dist/tests/local-driver.test.d.ts +2 -0
- package/dist/tests/local-driver.test.d.ts.map +1 -0
- package/dist/tests/local-driver.test.js +153 -0
- package/dist/tests/local-driver.test.js.map +1 -0
- package/dist/tests/local-streaming.test.d.ts +2 -0
- package/dist/tests/local-streaming.test.d.ts.map +1 -0
- package/dist/tests/local-streaming.test.js +121 -0
- package/dist/tests/local-streaming.test.js.map +1 -0
- package/dist/tests/memory-driver.test.d.ts +2 -0
- package/dist/tests/memory-driver.test.d.ts.map +1 -0
- package/dist/tests/memory-driver.test.js +180 -0
- package/dist/tests/memory-driver.test.js.map +1 -0
- package/dist/tests/memory-streaming.test.d.ts +2 -0
- package/dist/tests/memory-streaming.test.d.ts.map +1 -0
- package/dist/tests/memory-streaming.test.js +92 -0
- package/dist/tests/memory-streaming.test.js.map +1 -0
- package/dist/tests/minio-driver.test.d.ts +2 -0
- package/dist/tests/minio-driver.test.d.ts.map +1 -0
- package/dist/tests/minio-driver.test.js +146 -0
- package/dist/tests/minio-driver.test.js.map +1 -0
- package/dist/tests/non-s3-integration.test.d.ts +2 -0
- package/dist/tests/non-s3-integration.test.d.ts.map +1 -0
- package/dist/tests/non-s3-integration.test.js +201 -0
- package/dist/tests/non-s3-integration.test.js.map +1 -0
- package/dist/tests/observability.registration.test.d.ts +2 -0
- package/dist/tests/observability.registration.test.d.ts.map +1 -0
- package/dist/tests/observability.registration.test.js +103 -0
- package/dist/tests/observability.registration.test.js.map +1 -0
- package/dist/tests/observability.test.d.ts +2 -0
- package/dist/tests/observability.test.d.ts.map +1 -0
- package/dist/tests/observability.test.js +240 -0
- package/dist/tests/observability.test.js.map +1 -0
- package/dist/tests/plugin.test.d.ts +2 -0
- package/dist/tests/plugin.test.d.ts.map +1 -0
- package/dist/tests/plugin.test.js +112 -0
- package/dist/tests/plugin.test.js.map +1 -0
- package/dist/tests/prop-concurrent.test.d.ts +2 -0
- package/dist/tests/prop-concurrent.test.d.ts.map +1 -0
- package/dist/tests/prop-concurrent.test.js +59 -0
- package/dist/tests/prop-concurrent.test.js.map +1 -0
- package/dist/tests/prop-copy.test.d.ts +2 -0
- package/dist/tests/prop-copy.test.d.ts.map +1 -0
- package/dist/tests/prop-copy.test.js +63 -0
- package/dist/tests/prop-copy.test.js.map +1 -0
- package/dist/tests/prop-delete.test.d.ts +2 -0
- package/dist/tests/prop-delete.test.d.ts.map +1 -0
- package/dist/tests/prop-delete.test.js +35 -0
- package/dist/tests/prop-delete.test.js.map +1 -0
- package/dist/tests/prop-directory.test.d.ts +2 -0
- package/dist/tests/prop-directory.test.d.ts.map +1 -0
- package/dist/tests/prop-directory.test.js +118 -0
- package/dist/tests/prop-directory.test.js.map +1 -0
- package/dist/tests/prop-driver-conformance.test.d.ts +2 -0
- package/dist/tests/prop-driver-conformance.test.d.ts.map +1 -0
- package/dist/tests/prop-driver-conformance.test.js +110 -0
- package/dist/tests/prop-driver-conformance.test.js.map +1 -0
- package/dist/tests/prop-driver-equivalence.test.d.ts +2 -0
- package/dist/tests/prop-driver-equivalence.test.d.ts.map +1 -0
- package/dist/tests/prop-driver-equivalence.test.js +163 -0
- package/dist/tests/prop-driver-equivalence.test.js.map +1 -0
- package/dist/tests/prop-lifecycle.test.d.ts +2 -0
- package/dist/tests/prop-lifecycle.test.d.ts.map +1 -0
- package/dist/tests/prop-lifecycle.test.js +83 -0
- package/dist/tests/prop-lifecycle.test.js.map +1 -0
- package/dist/tests/prop-list.test.d.ts +2 -0
- package/dist/tests/prop-list.test.d.ts.map +1 -0
- package/dist/tests/prop-list.test.js +53 -0
- package/dist/tests/prop-list.test.js.map +1 -0
- package/dist/tests/prop-metadata.test.d.ts +2 -0
- package/dist/tests/prop-metadata.test.d.ts.map +1 -0
- package/dist/tests/prop-metadata.test.js +87 -0
- package/dist/tests/prop-metadata.test.js.map +1 -0
- package/dist/tests/prop-move.test.d.ts +2 -0
- package/dist/tests/prop-move.test.d.ts.map +1 -0
- package/dist/tests/prop-move.test.js +67 -0
- package/dist/tests/prop-move.test.js.map +1 -0
- package/dist/tests/prop-multipart-abort.test.d.ts +2 -0
- package/dist/tests/prop-multipart-abort.test.d.ts.map +1 -0
- package/dist/tests/prop-multipart-abort.test.js +48 -0
- package/dist/tests/prop-multipart-abort.test.js.map +1 -0
- package/dist/tests/prop-multipart.test.d.ts +2 -0
- package/dist/tests/prop-multipart.test.d.ts.map +1 -0
- package/dist/tests/prop-multipart.test.js +65 -0
- package/dist/tests/prop-multipart.test.js.map +1 -0
- package/dist/tests/prop-resumable.test.d.ts +2 -0
- package/dist/tests/prop-resumable.test.d.ts.map +1 -0
- package/dist/tests/prop-resumable.test.js +78 -0
- package/dist/tests/prop-resumable.test.js.map +1 -0
- package/dist/tests/prop-search.test.d.ts +2 -0
- package/dist/tests/prop-search.test.d.ts.map +1 -0
- package/dist/tests/prop-search.test.js +120 -0
- package/dist/tests/prop-search.test.js.map +1 -0
- package/dist/tests/prop-signed-url.test.d.ts +2 -0
- package/dist/tests/prop-signed-url.test.d.ts.map +1 -0
- package/dist/tests/prop-signed-url.test.js +74 -0
- package/dist/tests/prop-signed-url.test.js.map +1 -0
- package/dist/tests/prop-streaming.test.d.ts +2 -0
- package/dist/tests/prop-streaming.test.d.ts.map +1 -0
- package/dist/tests/prop-streaming.test.js +34 -0
- package/dist/tests/prop-streaming.test.js.map +1 -0
- package/dist/tests/prop-upload-download.test.d.ts +2 -0
- package/dist/tests/prop-upload-download.test.d.ts.map +1 -0
- package/dist/tests/prop-upload-download.test.js +30 -0
- package/dist/tests/prop-upload-download.test.js.map +1 -0
- package/dist/tests/prop-validation.test.d.ts +2 -0
- package/dist/tests/prop-validation.test.d.ts.map +1 -0
- package/dist/tests/prop-validation.test.js +50 -0
- package/dist/tests/prop-validation.test.js.map +1 -0
- package/dist/tests/prop-versioning.test.d.ts +2 -0
- package/dist/tests/prop-versioning.test.d.ts.map +1 -0
- package/dist/tests/prop-versioning.test.js +74 -0
- package/dist/tests/prop-versioning.test.js.map +1 -0
- package/dist/tests/queue-bridge.test.d.ts +2 -0
- package/dist/tests/queue-bridge.test.d.ts.map +1 -0
- package/dist/tests/queue-bridge.test.js +111 -0
- package/dist/tests/queue-bridge.test.js.map +1 -0
- package/dist/tests/r2-driver.test.d.ts +2 -0
- package/dist/tests/r2-driver.test.d.ts.map +1 -0
- package/dist/tests/r2-driver.test.js +143 -0
- package/dist/tests/r2-driver.test.js.map +1 -0
- package/dist/tests/realtime-bridge.test.d.ts +2 -0
- package/dist/tests/realtime-bridge.test.d.ts.map +1 -0
- package/dist/tests/realtime-bridge.test.js +106 -0
- package/dist/tests/realtime-bridge.test.js.map +1 -0
- package/dist/tests/resumable.test.d.ts +2 -0
- package/dist/tests/resumable.test.d.ts.map +1 -0
- package/dist/tests/resumable.test.js +104 -0
- package/dist/tests/resumable.test.js.map +1 -0
- package/dist/tests/s3-base.test.d.ts +2 -0
- package/dist/tests/s3-base.test.d.ts.map +1 -0
- package/dist/tests/s3-base.test.js +289 -0
- package/dist/tests/s3-base.test.js.map +1 -0
- package/dist/tests/s3-integration.test.d.ts +2 -0
- package/dist/tests/s3-integration.test.d.ts.map +1 -0
- package/dist/tests/s3-integration.test.js +270 -0
- package/dist/tests/s3-integration.test.js.map +1 -0
- package/dist/tests/s3.test.d.ts +2 -0
- package/dist/tests/s3.test.d.ts.map +1 -0
- package/dist/tests/s3.test.js +203 -0
- package/dist/tests/s3.test.js.map +1 -0
- package/dist/tests/scaffold.test.d.ts +2 -0
- package/dist/tests/scaffold.test.d.ts.map +1 -0
- package/dist/tests/scaffold.test.js +13 -0
- package/dist/tests/scaffold.test.js.map +1 -0
- package/dist/tests/search.test.d.ts +2 -0
- package/dist/tests/search.test.d.ts.map +1 -0
- package/dist/tests/search.test.js +106 -0
- package/dist/tests/search.test.js.map +1 -0
- package/dist/tests/supabase-driver.test.d.ts +2 -0
- package/dist/tests/supabase-driver.test.d.ts.map +1 -0
- package/dist/tests/supabase-driver.test.js +196 -0
- package/dist/tests/supabase-driver.test.js.map +1 -0
- package/dist/tests/testing-utilities.test.d.ts +2 -0
- package/dist/tests/testing-utilities.test.d.ts.map +1 -0
- package/dist/tests/testing-utilities.test.js +138 -0
- package/dist/tests/testing-utilities.test.js.map +1 -0
- package/dist/tests/validation.test.d.ts +2 -0
- package/dist/tests/validation.test.d.ts.map +1 -0
- package/dist/tests/validation.test.js +135 -0
- package/dist/tests/validation.test.js.map +1 -0
- package/dist/tests/versioning.test.d.ts +2 -0
- package/dist/tests/versioning.test.d.ts.map +1 -0
- package/dist/tests/versioning.test.js +128 -0
- package/dist/tests/versioning.test.js.map +1 -0
- package/dist/types.d.ts +232 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +23 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +105 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +225 -0
- package/dist/validation.js.map +1 -0
- package/dist/versioning.d.ts +100 -0
- package/dist/versioning.d.ts.map +1 -0
- package/dist/versioning.js +179 -0
- package/dist/versioning.js.map +1 -0
- package/package.json +137 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// src/tests/plugin.test.js
|
|
2
|
+
// Unit tests for StoragePlugin load/unload (task 23.2).
|
|
3
|
+
//
|
|
4
|
+
// These cover the two behaviors the task mandates:
|
|
5
|
+
//
|
|
6
|
+
// 1. After `onLoad`, the plugin exposes the live Storage facade through its
|
|
7
|
+
// `storage` accessor and that facade is usable (put/get round-trips)
|
|
8
|
+
// (Requirements 20.1, 20.3).
|
|
9
|
+
// 2. After `onUnload`, resources are released: the `storage` accessor becomes
|
|
10
|
+
// `undefined`, the facade's `close()` is called (which stops the
|
|
11
|
+
// observability refresh timer), and any declarative `wireBridges` detach
|
|
12
|
+
// functions are invoked (Requirement 20.3).
|
|
13
|
+
//
|
|
14
|
+
// A minimal SandboxedApp-like stub is passed to the hooks — the plugin ignores
|
|
15
|
+
// the app beyond the hook signatures, resolving its metrics/health registries
|
|
16
|
+
// from the plugin options instead. Uses the Node.js built-in test runner
|
|
17
|
+
// (node:test); executed via `node --test dist/tests/*.test.js`.
|
|
18
|
+
//
|
|
19
|
+
// Requirements: 20.1, 20.3
|
|
20
|
+
import test from "node:test";
|
|
21
|
+
import assert from "node:assert/strict";
|
|
22
|
+
import { HealthCheckRegistry, MetricsRegistry } from "streetjs";
|
|
23
|
+
import { StoragePlugin, STORAGE_HEALTH_CHECK_NAME, STORAGE_UPLOADS_METRIC, } from "../index.js";
|
|
24
|
+
/** A minimal SandboxedApp-like stub: exposes only `use` / `on`. */
|
|
25
|
+
function fakeApp() {
|
|
26
|
+
return { use() { }, on() { } };
|
|
27
|
+
}
|
|
28
|
+
test("onLoad exposes a usable Storage facade via the `storage` accessor (Req 20.1, 20.3)", async () => {
|
|
29
|
+
const plugin = new StoragePlugin({ provider: "memory" });
|
|
30
|
+
// No facade before load.
|
|
31
|
+
assert.equal(plugin.storage, undefined, "no facade before load");
|
|
32
|
+
await plugin.onLoad(fakeApp());
|
|
33
|
+
// The accessor now exposes the live facade.
|
|
34
|
+
assert.ok(plugin.storage, "facade exposed after load");
|
|
35
|
+
const storage = plugin.storage;
|
|
36
|
+
// The exposed facade is actually usable — a put/get round-trips.
|
|
37
|
+
const written = await storage.put("greeting.txt", "hello world");
|
|
38
|
+
assert.equal(written.key, "greeting.txt");
|
|
39
|
+
const read = await storage.get("greeting.txt");
|
|
40
|
+
assert.equal(read.found, true);
|
|
41
|
+
assert.equal(Buffer.from(read.bytes).toString("utf8"), "hello world");
|
|
42
|
+
await plugin.onUnload(fakeApp());
|
|
43
|
+
});
|
|
44
|
+
test("onUnload releases resources: accessor cleared, close() called, detachers invoked (Req 20.3)", async () => {
|
|
45
|
+
let attached = 0;
|
|
46
|
+
let detached = 0;
|
|
47
|
+
let bridgedStorage;
|
|
48
|
+
const plugin = new StoragePlugin({
|
|
49
|
+
provider: "memory",
|
|
50
|
+
wireBridges: [
|
|
51
|
+
(storage) => {
|
|
52
|
+
attached += 1;
|
|
53
|
+
bridgedStorage = storage;
|
|
54
|
+
// Returning a detach function that MUST be called on unload.
|
|
55
|
+
return () => {
|
|
56
|
+
detached += 1;
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
() => {
|
|
60
|
+
attached += 1;
|
|
61
|
+
// A bridge that returns nothing is allowed (no detach registered).
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
});
|
|
65
|
+
await plugin.onLoad(fakeApp());
|
|
66
|
+
assert.equal(attached, 2, "both wireBridges attach fns ran on load");
|
|
67
|
+
assert.equal(bridgedStorage, plugin.storage, "the attach fn received the live facade");
|
|
68
|
+
assert.equal(detached, 0, "detach not called before unload");
|
|
69
|
+
// Spy on the facade's close() so we can assert it is called on unload.
|
|
70
|
+
const facade = plugin.storage;
|
|
71
|
+
assert.ok(facade, "facade exposed after load");
|
|
72
|
+
let closeCalls = 0;
|
|
73
|
+
const originalClose = facade.close.bind(facade);
|
|
74
|
+
facade.close = async () => {
|
|
75
|
+
closeCalls += 1;
|
|
76
|
+
return originalClose();
|
|
77
|
+
};
|
|
78
|
+
await plugin.onUnload(fakeApp());
|
|
79
|
+
// The accessor is cleared, close() ran exactly once, and the returned detach
|
|
80
|
+
// function was invoked.
|
|
81
|
+
assert.equal(plugin.storage, undefined, "facade accessor cleared after unload");
|
|
82
|
+
assert.equal(closeCalls, 1, "facade close() called on unload");
|
|
83
|
+
assert.equal(detached, 1, "the returned detach function was called on unload");
|
|
84
|
+
});
|
|
85
|
+
test("observability from plugin-option registries loads and unloads cleanly (Req 20.3)", async () => {
|
|
86
|
+
const metrics = new MetricsRegistry();
|
|
87
|
+
const health = new HealthCheckRegistry();
|
|
88
|
+
const plugin = new StoragePlugin({ provider: "memory", metrics, health });
|
|
89
|
+
await plugin.onLoad(fakeApp());
|
|
90
|
+
// Observability wired from the plugin-option registries on load: the storage
|
|
91
|
+
// health check is registered and the storage metrics are present.
|
|
92
|
+
const live = await health.runLiveness();
|
|
93
|
+
assert.ok(STORAGE_HEALTH_CHECK_NAME in live.checks, "storage health check registered on load");
|
|
94
|
+
assert.equal(metrics.has(STORAGE_UPLOADS_METRIC), true, "storage metrics registered on load");
|
|
95
|
+
// Unload releases cleanly (stops the observability refresh timer) without throwing.
|
|
96
|
+
await assert.doesNotReject(() => plugin.onUnload(fakeApp()));
|
|
97
|
+
assert.equal(plugin.storage, undefined, "facade cleared after unload");
|
|
98
|
+
});
|
|
99
|
+
test("onLoad is idempotent — a second load reuses the same facade", async () => {
|
|
100
|
+
const plugin = new StoragePlugin({ provider: "memory" });
|
|
101
|
+
await plugin.onLoad(fakeApp());
|
|
102
|
+
const first = plugin.storage;
|
|
103
|
+
await plugin.onLoad(fakeApp());
|
|
104
|
+
assert.equal(plugin.storage, first, "facade identity unchanged on a second onLoad");
|
|
105
|
+
await plugin.onUnload(fakeApp());
|
|
106
|
+
});
|
|
107
|
+
test("onUnload is a no-op when never loaded", async () => {
|
|
108
|
+
const plugin = new StoragePlugin({ provider: "memory" });
|
|
109
|
+
await assert.doesNotReject(() => plugin.onUnload(fakeApp()));
|
|
110
|
+
assert.equal(plugin.storage, undefined);
|
|
111
|
+
});
|
|
112
|
+
//# sourceMappingURL=plugin.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.test.js","sourceRoot":"","sources":["../../src/tests/plugin.test.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,wDAAwD;AACxD,EAAE;AACF,mDAAmD;AACnD,EAAE;AACF,8EAA8E;AAC9E,0EAA0E;AAC1E,kCAAkC;AAClC,gFAAgF;AAChF,sEAAsE;AACtE,8EAA8E;AAC9E,iDAAiD;AACjD,EAAE;AACF,+EAA+E;AAC/E,8EAA8E;AAC9E,yEAAyE;AACzE,gEAAgE;AAChE,EAAE;AACF,2BAA2B;AAE3B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAExC,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhE,OAAO,EACL,aAAa,EACb,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,mEAAmE;AACnE,SAAS,OAAO;IACd,OAAO,EAAE,GAAG,KAAI,CAAC,EAAE,EAAE,KAAI,CAAC,EAAE,CAAC;AAC/B,CAAC;AAED,IAAI,CAAC,oFAAoF,EAAE,KAAK,IAAI,EAAE;IACpG,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;IAEzD,yBAAyB;IACzB,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,uBAAuB,CAAC,CAAC;IAEjE,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAE/B,4CAA4C;IAC5C,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,2BAA2B,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAgD,CAAC;IAExE,iEAAiE;IACjE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,aAAa,CAAC,CAAC;IACjE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAE1C,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC/C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC/B,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC;IAEvE,MAAM,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;AACnC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,6FAA6F,EAAE,KAAK,IAAI,EAAE;IAC7G,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,cAAc,CAAC;IAEnB,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC;QAC/B,QAAQ,EAAE,QAAQ;QAClB,WAAW,EAAE;YACX,CAAC,OAAO,EAAE,EAAE;gBACV,QAAQ,IAAI,CAAC,CAAC;gBACd,cAAc,GAAG,OAAO,CAAC;gBACzB,6DAA6D;gBAC7D,OAAO,GAAG,EAAE;oBACV,QAAQ,IAAI,CAAC,CAAC;gBAChB,CAAC,CAAC;YACJ,CAAC;YACD,GAAG,EAAE;gBACH,QAAQ,IAAI,CAAC,CAAC;gBACd,mEAAmE;YACrE,CAAC;SACF;KACF,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAE/B,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,EAAE,yCAAyC,CAAC,CAAC;IACrE,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE,MAAM,CAAC,OAAO,EAAE,wCAAwC,CAAC,CAAC;IACvF,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,EAAE,iCAAiC,CAAC,CAAC;IAE7D,uEAAuE;IACvE,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;IAC9B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAAC;IAC/C,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,CAAC,KAAK,GAAG,KAAK,IAAI,EAAE;QACxB,UAAU,IAAI,CAAC,CAAC;QAChB,OAAO,aAAa,EAAE,CAAC;IACzB,CAAC,CAAC;IAEF,MAAM,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IAEjC,6EAA6E;IAC7E,wBAAwB;IACxB,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,sCAAsC,CAAC,CAAC;IAChF,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC,EAAE,iCAAiC,CAAC,CAAC;IAC/D,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,EAAE,mDAAmD,CAAC,CAAC;AACjF,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,kFAAkF,EAAE,KAAK,IAAI,EAAE;IAClG,MAAM,OAAO,GAAG,IAAI,eAAe,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,mBAAmB,EAAE,CAAC;IAEzC,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IAE1E,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAE/B,6EAA6E;IAC7E,kEAAkE;IAClE,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;IACxC,MAAM,CAAC,EAAE,CACP,yBAAyB,IAAI,IAAI,CAAC,MAAM,EACxC,yCAAyC,CAC1C,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,EAAE,IAAI,EAAE,oCAAoC,CAAC,CAAC;IAE9F,oFAAoF;IACpF,MAAM,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC7D,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,6BAA6B,CAAC,CAAC;AACzE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;IAC7E,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;IAEzD,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC;IAE7B,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/B,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,8CAA8C,CAAC,CAAC;IAEpF,MAAM,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;AACnC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;IACvD,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;IACzD,MAAM,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC7D,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prop-concurrent.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-concurrent.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Property-based test for concurrent write isolation on the storage facade.
|
|
2
|
+
//
|
|
3
|
+
// Feature: unified-storage-framework, Property 17: Concurrent uploads never
|
|
4
|
+
// corrupt data.
|
|
5
|
+
//
|
|
6
|
+
// For an arbitrary set of DISTINCT keys, each paired with its own byte content,
|
|
7
|
+
// performing all `put` operations CONCURRENTLY (`Promise.all`) against a single
|
|
8
|
+
// storage instance results in every key holding exactly its own content. No
|
|
9
|
+
// key observes another key's bytes (no cross-contamination), and no bytes are
|
|
10
|
+
// corrupted: reading each key back yields bytes exactly equal to the content
|
|
11
|
+
// that was intended for that key.
|
|
12
|
+
//
|
|
13
|
+
// Uses the Node.js built-in test runner (node:test) and fast-check at
|
|
14
|
+
// `{ numRuns: 100 }`, exercising the public facade via
|
|
15
|
+
// `createStorage({ provider: 'memory' })` imported from the built package
|
|
16
|
+
// entry point (`../index.js`), executed via `node --test dist/tests/*.test.js`.
|
|
17
|
+
//
|
|
18
|
+
// Validates: Requirements 26.6
|
|
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
|
+
/** A fixed clock so object timestamps are deterministic across runs. */
|
|
24
|
+
const fixedClock = () => 1_700_000_000_000;
|
|
25
|
+
/**
|
|
26
|
+
* An arbitrary set of distinct keys each mapped to its own byte content.
|
|
27
|
+
*
|
|
28
|
+
* `fc.uniqueArray` on non-empty keys guarantees the keys are DISTINCT, so each
|
|
29
|
+
* concurrent `put` targets a different object and the property genuinely tests
|
|
30
|
+
* cross-key isolation rather than last-writer-wins on a shared key. `minLength:
|
|
31
|
+
* 2` ensures there is always genuine concurrency to exercise.
|
|
32
|
+
*/
|
|
33
|
+
const distinctEntriesArb = fc
|
|
34
|
+
.uniqueArray(fc.string({ minLength: 1, maxLength: 40 }), {
|
|
35
|
+
minLength: 2,
|
|
36
|
+
maxLength: 25,
|
|
37
|
+
})
|
|
38
|
+
.chain((keys) => fc.tuple(fc.constant(keys), fc.array(fc.uint8Array({ minLength: 0, maxLength: 256 }), {
|
|
39
|
+
minLength: keys.length,
|
|
40
|
+
maxLength: keys.length,
|
|
41
|
+
})))
|
|
42
|
+
.map(([keys, contents]) => keys.map((key, index) => [key, contents[index]]));
|
|
43
|
+
test("Feature: unified-storage-framework, Property 17: Concurrent uploads never corrupt data", async () => {
|
|
44
|
+
await fc.assert(fc.asyncProperty(distinctEntriesArb, async (entries) => {
|
|
45
|
+
// A single shared storage instance receives every concurrent write.
|
|
46
|
+
const storage = createStorage({ provider: "memory", clock: fixedClock });
|
|
47
|
+
// Fire all puts CONCURRENTLY against the one instance.
|
|
48
|
+
await Promise.all(entries.map(([key, content]) => storage.put(key, content)));
|
|
49
|
+
// Every key must hold exactly its own content — read them all back
|
|
50
|
+
// concurrently and assert byte-for-byte equality with the intended value.
|
|
51
|
+
await Promise.all(entries.map(async ([key, content]) => {
|
|
52
|
+
const result = await storage.get(key);
|
|
53
|
+
assert.equal(result.found, true, `key ${JSON.stringify(key)} must be present after concurrent writes`);
|
|
54
|
+
assert.deepEqual(result.bytes, content, `key ${JSON.stringify(key)} must hold exactly its own content (no cross-contamination)`);
|
|
55
|
+
}));
|
|
56
|
+
await storage.close();
|
|
57
|
+
}), { numRuns: 100 });
|
|
58
|
+
});
|
|
59
|
+
//# sourceMappingURL=prop-concurrent.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prop-concurrent.test.js","sourceRoot":"","sources":["../../src/tests/prop-concurrent.test.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,EAAE;AACF,4EAA4E;AAC5E,gBAAgB;AAChB,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAChF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,kCAAkC;AAClC,EAAE;AACF,sEAAsE;AACtE,uDAAuD;AACvD,0EAA0E;AAC1E,gFAAgF;AAChF,EAAE;AACF,+BAA+B;AAE/B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,wEAAwE;AACxE,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,iBAAiB,CAAC;AAE3C;;;;;;;GAOG;AACH,MAAM,kBAAkB,GAAG,EAAE;KAC1B,WAAW,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,EAAE;IACvD,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,EAAE;CACd,CAAC;KACD,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CACd,EAAE,CAAC,KAAK,CACN,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EACjB,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE;IACxD,SAAS,EAAE,IAAI,CAAC,MAAM;IACtB,SAAS,EAAE,IAAI,CAAC,MAAM;CACvB,CAAC,CACH,CACF;KACA,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,CACxB,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAwB,EAAE,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CACvE,CAAC;AAEJ,IAAI,CAAC,wFAAwF,EAAE,KAAK,IAAI,EAAE;IACxG,MAAM,EAAE,CAAC,MAAM,CACb,EAAE,CAAC,aAAa,CAAC,kBAAkB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACrD,oEAAoE;QACpE,MAAM,OAAO,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;QAEzE,uDAAuD;QACvD,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QAE9E,mEAAmE;QACnE,0EAA0E;QAC1E,MAAM,OAAO,CAAC,GAAG,CACf,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,EAAE;YACnC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;YACvG,MAAM,CAAC,SAAS,CACd,MAAM,CAAC,KAAK,EACZ,OAAO,EACP,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,6DAA6D,CACxF,CAAC;QACJ,CAAC,CAAC,CACH,CAAC;QAEF,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC,CAAC,EACF,EAAE,OAAO,EAAE,GAAG,EAAE,CACjB,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prop-copy.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-copy.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Property-based test for the storage facade `copy` operation.
|
|
2
|
+
//
|
|
3
|
+
// Feature: unified-storage-framework, Property 2: Copy is non-mutating and
|
|
4
|
+
// duplicates content.
|
|
5
|
+
//
|
|
6
|
+
// For arbitrary, distinct source/destination keys and arbitrary content, after
|
|
7
|
+
// `put(source, bytes)` followed by `copy(source, dest)`:
|
|
8
|
+
// - the source still returns the original bytes (unchanged),
|
|
9
|
+
// - the destination returns bytes equal to the source content, and
|
|
10
|
+
// - the copy result is `{ copied: true }`.
|
|
11
|
+
// Additionally, copying a source key that was never written returns
|
|
12
|
+
// `{ copied: false }` and creates nothing at the destination.
|
|
13
|
+
//
|
|
14
|
+
// Uses the Node.js built-in test runner (node:test) and fast-check at
|
|
15
|
+
// `{ numRuns: 100 }`, exercising the public facade via
|
|
16
|
+
// `createStorage({ provider: 'memory' })` imported from the built package
|
|
17
|
+
// entry point (`../index.js`), executed via `node --test dist/tests/*.test.js`.
|
|
18
|
+
//
|
|
19
|
+
// Validates: Requirements 4.5, 26.3
|
|
20
|
+
import test from "node:test";
|
|
21
|
+
import assert from "node:assert/strict";
|
|
22
|
+
import fc from "fast-check";
|
|
23
|
+
import { createStorage } from "../index.js";
|
|
24
|
+
/** A fixed clock so object timestamps are deterministic across runs. */
|
|
25
|
+
const fixedClock = () => 1_700_000_000_000;
|
|
26
|
+
/**
|
|
27
|
+
* Arbitrary object content: arbitrary byte arrays (including empty) mapped to a
|
|
28
|
+
* Uint8Array, which is what the facade/driver persists.
|
|
29
|
+
*/
|
|
30
|
+
const contentArb = fc.uint8Array({ minLength: 0, maxLength: 256 });
|
|
31
|
+
/**
|
|
32
|
+
* Two distinct, non-empty object keys. Keys are constrained to non-empty
|
|
33
|
+
* strings and the pair is filtered so the source and destination never collide
|
|
34
|
+
* (a copy onto itself is a different scenario than "duplicate to a new key").
|
|
35
|
+
*/
|
|
36
|
+
const distinctKeysArb = fc
|
|
37
|
+
.tuple(fc.string({ minLength: 1, maxLength: 40 }), fc.string({ minLength: 1, maxLength: 40 }))
|
|
38
|
+
.filter(([source, dest]) => source !== dest);
|
|
39
|
+
test("Feature: unified-storage-framework, Property 2: Copy is non-mutating and duplicates content", async () => {
|
|
40
|
+
await fc.assert(fc.asyncProperty(distinctKeysArb, contentArb, async ([source, dest], content) => {
|
|
41
|
+
// A fresh storage instance per case keeps runs independent.
|
|
42
|
+
const storage = createStorage({ provider: "memory", clock: fixedClock });
|
|
43
|
+
// ── Copy of a missing source: no-op that creates nothing ────────────────
|
|
44
|
+
const missing = await storage.copy(source, dest);
|
|
45
|
+
assert.equal(missing.copied, false, "copy of a missing source must report copied:false");
|
|
46
|
+
assert.equal(await storage.exists(source), false, "missing source must not be created by copy");
|
|
47
|
+
assert.equal(await storage.exists(dest), false, "destination must not be created when source is missing");
|
|
48
|
+
// ── Copy after a real write: duplicates content, source unchanged ───────
|
|
49
|
+
await storage.put(source, content);
|
|
50
|
+
const result = await storage.copy(source, dest);
|
|
51
|
+
assert.equal(result.copied, true, "copy of an existing source must report copied:true");
|
|
52
|
+
// Source still returns the original bytes (non-mutating).
|
|
53
|
+
const afterSource = await storage.get(source);
|
|
54
|
+
assert.equal(afterSource.found, true, "source must still exist after copy");
|
|
55
|
+
assert.deepEqual(afterSource.bytes, content, "source bytes must be unchanged after copy");
|
|
56
|
+
// Destination returns bytes equal to the source content (duplicated).
|
|
57
|
+
const afterDest = await storage.get(dest);
|
|
58
|
+
assert.equal(afterDest.found, true, "destination must exist after copy");
|
|
59
|
+
assert.deepEqual(afterDest.bytes, content, "destination bytes must equal the source content");
|
|
60
|
+
await storage.close();
|
|
61
|
+
}), { numRuns: 100 });
|
|
62
|
+
});
|
|
63
|
+
//# sourceMappingURL=prop-copy.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prop-copy.test.js","sourceRoot":"","sources":["../../src/tests/prop-copy.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prop-delete.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-delete.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Property-based test for the storage facade's delete semantics.
|
|
2
|
+
//
|
|
3
|
+
// Property 4: Delete removes visibility. For any stored object, after
|
|
4
|
+
// `put(key, bytes)` then `delete(key)`, the object becomes invisible through
|
|
5
|
+
// every read surface: `exists(key)` is false, `get(key)` reports not-found,
|
|
6
|
+
// and `stat(key)` returns null.
|
|
7
|
+
//
|
|
8
|
+
// Backed by the zero-dependency in-memory provider via `createStorage({
|
|
9
|
+
// provider: 'memory' })`, exercised across arbitrary keys and byte contents
|
|
10
|
+
// with fast-check at { numRuns: 100 }. Executed via the Node.js built-in test
|
|
11
|
+
// runner (`node --test dist/tests/*.test.js`).
|
|
12
|
+
//
|
|
13
|
+
// Feature: unified-storage-framework, Property 4
|
|
14
|
+
// Validates: Requirements 4.4, 26.4
|
|
15
|
+
import test from "node:test";
|
|
16
|
+
import assert from "node:assert/strict";
|
|
17
|
+
import fc from "fast-check";
|
|
18
|
+
import { createStorage } from "../index.js";
|
|
19
|
+
test("Feature: unified-storage-framework, Property 4 — delete removes visibility", async () => {
|
|
20
|
+
await fc.assert(fc.asyncProperty(
|
|
21
|
+
// Arbitrary non-empty keys and arbitrary byte contents.
|
|
22
|
+
fc.string({ minLength: 1 }), fc.uint8Array(), async (key, content) => {
|
|
23
|
+
const storage = createStorage({ provider: "memory" });
|
|
24
|
+
await storage.put(key, content);
|
|
25
|
+
await storage.delete(key);
|
|
26
|
+
// exists reports false after delete.
|
|
27
|
+
assert.equal(await storage.exists(key), false);
|
|
28
|
+
// get reports not-found (never throws).
|
|
29
|
+
const result = await storage.get(key);
|
|
30
|
+
assert.equal(result.found, false);
|
|
31
|
+
// stat returns null for the deleted key.
|
|
32
|
+
assert.equal(await storage.stat(key), null);
|
|
33
|
+
}), { numRuns: 100 });
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=prop-delete.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prop-delete.test.js","sourceRoot":"","sources":["../../src/tests/prop-delete.test.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,sEAAsE;AACtE,6EAA6E;AAC7E,4EAA4E;AAC5E,gCAAgC;AAChC,EAAE;AACF,wEAAwE;AACxE,4EAA4E;AAC5E,8EAA8E;AAC9E,+CAA+C;AAC/C,EAAE;AACF,iDAAiD;AACjD,oCAAoC;AAEpC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,IAAI,CACF,4EAA4E,EAC5E,KAAK,IAAI,EAAE;IACT,MAAM,EAAE,CAAC,MAAM,CACb,EAAE,CAAC,aAAa;IACd,wDAAwD;IACxD,EAAE,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,EAC3B,EAAE,CAAC,UAAU,EAAE,EACf,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE;QACrB,MAAM,OAAO,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEtD,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAChC,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAE1B,qCAAqC;QACrC,MAAM,CAAC,KAAK,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;QAE/C,wCAAwC;QACxC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAElC,yCAAyC;QACzC,MAAM,CAAC,KAAK,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;IAC9C,CAAC,CACF,EACD,EAAE,OAAO,EAAE,GAAG,EAAE,CACjB,CAAC;AACJ,CAAC,CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prop-directory.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-directory.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// Property-based test for the storage Directory API over the flat key space.
|
|
2
|
+
//
|
|
3
|
+
// Feature: unified-storage-framework, Property 16 — Directory operations over a
|
|
4
|
+
// flat key space. For an arbitrary set of `/`-delimited keys put into storage,
|
|
5
|
+
// the directory operations are consistent over the flat key space:
|
|
6
|
+
//
|
|
7
|
+
// - walk(prefix) returns exactly the keys beneath the prefix (Req 15.4).
|
|
8
|
+
// - listDirectory(prefix) returns exactly the immediate children (files plus
|
|
9
|
+
// collapsed sub-directory entries) with no duplicates and nothing outside
|
|
10
|
+
// the prefix (Req 15.2).
|
|
11
|
+
// - removeDirectory(prefix) removes exactly the keys beneath the prefix, and
|
|
12
|
+
// returns { removed: false } for an empty/missing prefix (Req 15.3, 15.6).
|
|
13
|
+
//
|
|
14
|
+
// Each observation is asserted against a computed expectation derived directly
|
|
15
|
+
// from the generated key set.
|
|
16
|
+
//
|
|
17
|
+
// Uses the public facade via `createStorage({ provider: 'memory' })`, the
|
|
18
|
+
// Node.js built-in test runner (node:test), and fast-check configured with
|
|
19
|
+
// { numRuns: 100 }. Executed via `node --test dist/tests/*.test.js`.
|
|
20
|
+
//
|
|
21
|
+
// Validates: Requirements 15.2, 15.3, 15.4, 15.6
|
|
22
|
+
import test from "node:test";
|
|
23
|
+
import assert from "node:assert/strict";
|
|
24
|
+
import fc from "fast-check";
|
|
25
|
+
import { createStorage } from "../index.js";
|
|
26
|
+
// Segments are drawn from a tiny alphabet so shared prefixes arise frequently,
|
|
27
|
+
// exercising both matching and non-matching keys against a directory prefix.
|
|
28
|
+
const segArb = fc.constantFrom("a", "b", "c");
|
|
29
|
+
// A key is 1–3 `/`-delimited segments (no leading/trailing delimiter).
|
|
30
|
+
const keyArb = fc
|
|
31
|
+
.array(segArb, { minLength: 1, maxLength: 3 })
|
|
32
|
+
.map((segments) => segments.join("/"));
|
|
33
|
+
// A directory path is 0–2 segments; the empty path denotes the root.
|
|
34
|
+
const dirArb = fc
|
|
35
|
+
.array(segArb, { minLength: 0, maxLength: 2 })
|
|
36
|
+
.map((segments) => segments.join("/"));
|
|
37
|
+
/** Normalize a directory path the same way the Directory API does. */
|
|
38
|
+
function toPrefix(path) {
|
|
39
|
+
return path === "" ? "" : path + "/";
|
|
40
|
+
}
|
|
41
|
+
/** Keys strictly beneath `prefix` in the flat key set (no markers here). */
|
|
42
|
+
function expectedWalk(keys, prefix) {
|
|
43
|
+
return keys.filter((key) => key.startsWith(prefix) && key !== prefix);
|
|
44
|
+
}
|
|
45
|
+
/** Immediate children beneath `prefix`: file keys and collapsed sub-dir keys. */
|
|
46
|
+
function expectedImmediate(keys, prefix) {
|
|
47
|
+
const entries = new Set();
|
|
48
|
+
for (const key of keys) {
|
|
49
|
+
if (!key.startsWith(prefix))
|
|
50
|
+
continue;
|
|
51
|
+
const remainder = key.slice(prefix.length);
|
|
52
|
+
if (remainder === "")
|
|
53
|
+
continue; // the directory marker itself, if any
|
|
54
|
+
const slash = remainder.indexOf("/");
|
|
55
|
+
if (slash === -1) {
|
|
56
|
+
entries.add(key); // immediate file child
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
entries.add(prefix + remainder.slice(0, slash) + "/"); // sub-directory
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return entries;
|
|
63
|
+
}
|
|
64
|
+
test("Feature: unified-storage-framework, Property 16 — directory operations are consistent over the flat key space", async () => {
|
|
65
|
+
await fc.assert(fc.asyncProperty(
|
|
66
|
+
// A set of unique keys, each paired with arbitrary string content.
|
|
67
|
+
fc.uniqueArray(fc.tuple(keyArb, fc.string()), {
|
|
68
|
+
selector: ([key]) => key,
|
|
69
|
+
minLength: 0,
|
|
70
|
+
maxLength: 15,
|
|
71
|
+
}),
|
|
72
|
+
// An arbitrary directory path, possibly the root, possibly unrelated.
|
|
73
|
+
dirArb, async (entries, dirPath) => {
|
|
74
|
+
const storage = createStorage({ provider: "memory" });
|
|
75
|
+
const keys = entries.map(([key]) => key);
|
|
76
|
+
for (const [key, content] of entries) {
|
|
77
|
+
await storage.put(key, content, {});
|
|
78
|
+
}
|
|
79
|
+
const prefix = toPrefix(dirPath);
|
|
80
|
+
const under = expectedWalk(keys, prefix);
|
|
81
|
+
// --- walk: exactly the keys beneath the prefix (15.4) -------------
|
|
82
|
+
const walked = await storage.directory.walk(dirPath);
|
|
83
|
+
const walkedSet = new Set(walked);
|
|
84
|
+
assert.equal(walkedSet.size, walked.length, "walk returned duplicate keys");
|
|
85
|
+
assert.equal(walkedSet.size, under.length, "walk cardinality");
|
|
86
|
+
for (const key of under) {
|
|
87
|
+
assert.ok(walkedSet.has(key), `walk missing key: ${key}`);
|
|
88
|
+
}
|
|
89
|
+
for (const key of walked) {
|
|
90
|
+
assert.ok(key.startsWith(prefix), `walk leaked key outside prefix: ${key}`);
|
|
91
|
+
}
|
|
92
|
+
// --- listDirectory: exactly the immediate children (15.2) --------
|
|
93
|
+
const listing = await storage.directory.listDirectory(dirPath);
|
|
94
|
+
const listedKeys = listing.map((item) => item.key);
|
|
95
|
+
const listedSet = new Set(listedKeys);
|
|
96
|
+
assert.equal(listedSet.size, listedKeys.length, "listDirectory returned duplicate entries");
|
|
97
|
+
const expectedChildren = expectedImmediate(keys, prefix);
|
|
98
|
+
assert.equal(listedSet.size, expectedChildren.size, "listDirectory cardinality");
|
|
99
|
+
for (const key of expectedChildren) {
|
|
100
|
+
assert.ok(listedSet.has(key), `listDirectory missing child: ${key}`);
|
|
101
|
+
}
|
|
102
|
+
for (const key of listedKeys) {
|
|
103
|
+
assert.ok(key.startsWith(prefix) && key !== prefix, `listDirectory leaked entry outside prefix: ${key}`);
|
|
104
|
+
}
|
|
105
|
+
// --- removeDirectory: removes exactly the keys beneath (15.3/15.6)
|
|
106
|
+
const result = await storage.directory.removeDirectory(dirPath);
|
|
107
|
+
assert.deepEqual(result, { removed: under.length > 0 }, "removeDirectory removed flag");
|
|
108
|
+
// Nothing beneath the prefix survives; everything else is intact.
|
|
109
|
+
assert.deepEqual(await storage.directory.walk(dirPath), [], "removeDirectory left keys beneath the prefix");
|
|
110
|
+
const remaining = new Set(await storage.directory.walk(""));
|
|
111
|
+
const expectedRemaining = keys.filter((key) => !key.startsWith(prefix));
|
|
112
|
+
assert.equal(remaining.size, expectedRemaining.length);
|
|
113
|
+
for (const key of expectedRemaining) {
|
|
114
|
+
assert.ok(remaining.has(key), `removeDirectory wrongly removed sibling: ${key}`);
|
|
115
|
+
}
|
|
116
|
+
}), { numRuns: 100 });
|
|
117
|
+
});
|
|
118
|
+
//# sourceMappingURL=prop-directory.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prop-directory.test.js","sourceRoot":"","sources":["../../src/tests/prop-directory.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prop-driver-conformance.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-driver-conformance.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// Property-based test: every available driver conforms to the StorageDriver contract.
|
|
2
|
+
//
|
|
3
|
+
// Property 19: Every available (zero-dependency) driver conforms to the shared
|
|
4
|
+
// StorageDriver contract. This reuses the parameterized contract-conformance
|
|
5
|
+
// suite from `./contract.js` (task 27.1) — `runStorageDriverContract` and
|
|
6
|
+
// `storageDriverContractChecks` — asserting the returned report passes for both
|
|
7
|
+
// the Memory and Local drivers.
|
|
8
|
+
//
|
|
9
|
+
// Because the contract checks use fixed internal keys, this property ALSO folds
|
|
10
|
+
// in a fast-check-generated round-trip assertion per driver over arbitrary
|
|
11
|
+
// key+byte inputs (put→get equals, exists→true, delete→exists false,
|
|
12
|
+
// get→found:false) so the property genuinely varies its inputs at
|
|
13
|
+
// { numRuns: 100 }. A fresh driver is constructed per run; each Local driver is
|
|
14
|
+
// rooted at a unique temp directory that is cleaned up after the run.
|
|
15
|
+
//
|
|
16
|
+
// Executed via the Node.js built-in test runner (`node --test dist/tests/*.test.js`).
|
|
17
|
+
//
|
|
18
|
+
// Feature: unified-storage-framework, Property 19
|
|
19
|
+
// Validates: Requirements 2.1, 2.3, 2.4, 26.6
|
|
20
|
+
import test from "node:test";
|
|
21
|
+
import assert from "node:assert/strict";
|
|
22
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
23
|
+
import { tmpdir } from "node:os";
|
|
24
|
+
import { join } from "node:path";
|
|
25
|
+
import fc from "fast-check";
|
|
26
|
+
import { runStorageDriverContract, storageDriverContractChecks, } from "./contract.js";
|
|
27
|
+
import { MemoryStorageDriver } from "../drivers/memory.js";
|
|
28
|
+
import { LocalStorageDriver } from "../drivers/local.js";
|
|
29
|
+
/** A fixed clock for deterministic timestamps. */
|
|
30
|
+
const fixedClock = () => 1_700_000_000_000;
|
|
31
|
+
/** Temp roots allocated for Local drivers, cleaned up after the run. */
|
|
32
|
+
const tempRoots = [];
|
|
33
|
+
/** Factory: a fresh in-memory driver per call. */
|
|
34
|
+
function makeMemoryDriver() {
|
|
35
|
+
return new MemoryStorageDriver({ clock: fixedClock });
|
|
36
|
+
}
|
|
37
|
+
/** Factory: a fresh filesystem driver rooted at a unique temp dir per call. */
|
|
38
|
+
function makeLocalDriver() {
|
|
39
|
+
const root = mkdtempSync(join(tmpdir(), "streetjs-storage-conformance-"));
|
|
40
|
+
tempRoots.push(root);
|
|
41
|
+
return new LocalStorageDriver({ root, clock: fixedClock });
|
|
42
|
+
}
|
|
43
|
+
/** The available zero-dependency drivers under test. */
|
|
44
|
+
const DRIVERS = [
|
|
45
|
+
{ label: "memory", make: makeMemoryDriver },
|
|
46
|
+
{ label: "local", make: makeLocalDriver },
|
|
47
|
+
];
|
|
48
|
+
/**
|
|
49
|
+
* A generator over the domain of *valid object keys*.
|
|
50
|
+
*
|
|
51
|
+
* A key is generated as one or more non-empty path segments joined by `/`,
|
|
52
|
+
* where each segment is drawn from a filesystem-safe character set and is never
|
|
53
|
+
* the reserved relative-path names `.` or `..`. This deliberately excludes keys
|
|
54
|
+
* that no real object store accepts as an object key and that the Local driver
|
|
55
|
+
* (which maps keys onto filesystem paths) cannot represent equivalently to the
|
|
56
|
+
* opaque-map Memory driver:
|
|
57
|
+
* - the empty string and empty segments (e.g. `""`, `"a//b"`),
|
|
58
|
+
* - a leading or trailing `/` (e.g. `"/a"`, `"a/"`),
|
|
59
|
+
* - the relative segments `"."` / `".."` (path traversal),
|
|
60
|
+
* - control characters such as NUL.
|
|
61
|
+
* Such inputs resolve to an existing/invalid filesystem path (EISDIR / ENOTDIR
|
|
62
|
+
* / ERR_INVALID_ARG_VALUE) on the Local driver while the Memory driver treats
|
|
63
|
+
* them as opaque map keys — an out-of-domain divergence, not a driver defect.
|
|
64
|
+
* This matches the valid-key domain the equivalence property (Property 18)
|
|
65
|
+
* already documents for its curated key pool.
|
|
66
|
+
*/
|
|
67
|
+
const KEY_SEGMENT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.".split("");
|
|
68
|
+
const segmentArb = fc
|
|
69
|
+
.array(fc.constantFrom(...KEY_SEGMENT_CHARS), { minLength: 1, maxLength: 12 })
|
|
70
|
+
.map((chars) => chars.join(""))
|
|
71
|
+
.filter((segment) => segment !== "." && segment !== "..");
|
|
72
|
+
const keyArb = fc
|
|
73
|
+
.array(segmentArb, { minLength: 1, maxLength: 4 })
|
|
74
|
+
.map((segments) => segments.join("/"));
|
|
75
|
+
test.after(() => {
|
|
76
|
+
for (const root of tempRoots) {
|
|
77
|
+
rmSync(root, { recursive: true, force: true });
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
test("Feature: unified-storage-framework, Property 19 — every driver conforms to the StorageDriver contract", async () => {
|
|
81
|
+
await fc.assert(fc.asyncProperty(
|
|
82
|
+
// A valid object key and arbitrary byte content drive an additional
|
|
83
|
+
// round-trip so inputs genuinely vary across runs. See `keyArb` for why
|
|
84
|
+
// the key domain excludes path-relative / empty-segment / control-char
|
|
85
|
+
// keys that the two drivers cannot represent equivalently.
|
|
86
|
+
keyArb, fc.uint8Array(), async (key, content) => {
|
|
87
|
+
for (const { label, make } of DRIVERS) {
|
|
88
|
+
// 1. The full contract-conformance suite must pass for the driver.
|
|
89
|
+
const report = await runStorageDriverContract(make);
|
|
90
|
+
assert.equal(report.passed, true, `${label} driver must conform to the contract, got: ${JSON.stringify(report.results)}`);
|
|
91
|
+
assert.equal(report.results.length, storageDriverContractChecks.length, `${label} driver must run every contract check`);
|
|
92
|
+
// 2. An input-varying round-trip on a fresh driver instance.
|
|
93
|
+
const driver = await make();
|
|
94
|
+
await driver.put(key, content, {});
|
|
95
|
+
// put→get returns the exact stored bytes.
|
|
96
|
+
const found = await driver.get(key);
|
|
97
|
+
assert.equal(found.found, true, `${label}: get must find the stored key`);
|
|
98
|
+
assert.ok(found.found === true, `${label}: result must be the found variant`);
|
|
99
|
+
assert.deepEqual(found.bytes, content, `${label}: get must return the exact stored bytes`);
|
|
100
|
+
// exists reports presence.
|
|
101
|
+
assert.equal(await driver.exists(key), true, `${label}: exists must be true after put`);
|
|
102
|
+
// delete removes visibility.
|
|
103
|
+
await driver.delete(key);
|
|
104
|
+
assert.equal(await driver.exists(key), false, `${label}: exists must be false after delete`);
|
|
105
|
+
const missing = await driver.get(key);
|
|
106
|
+
assert.equal(missing.found, false, `${label}: get must report not-found after delete`);
|
|
107
|
+
}
|
|
108
|
+
}), { numRuns: 100 });
|
|
109
|
+
});
|
|
110
|
+
//# sourceMappingURL=prop-driver-conformance.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prop-driver-conformance.test.js","sourceRoot":"","sources":["../../src/tests/prop-driver-conformance.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prop-driver-equivalence.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-driver-equivalence.test.ts"],"names":[],"mappings":""}
|