@toa.io/core 1.0.0-alpha.284 → 1.0.0-alpha.287
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -185
- package/package.json +19 -7
- package/source/assignment.ts +27 -0
- package/{src/call.js → source/call.ts} +16 -21
- package/{src/cascade.js → source/cascade.ts} +6 -8
- package/{src/component.js → source/component.ts} +27 -25
- package/{src/composition.js → source/composition.ts} +9 -3
- package/{src/connector.js → source/connector.ts} +36 -55
- package/source/context.ts +67 -0
- package/source/contract/contract.ts +23 -0
- package/{src/contract/reply.js → source/contract/reply.ts} +26 -19
- package/source/contract/request.ts +85 -0
- package/source/contract/schemas.ts +39 -0
- package/{src/discovery.js → source/discovery.ts} +15 -8
- package/source/effect.ts +14 -0
- package/{src/emission.js → source/emission.ts} +5 -3
- package/source/entities/changeset.ts +37 -0
- package/source/entities/entity.ts +137 -0
- package/source/entities/factory.ts +52 -0
- package/source/entities/index.ts +4 -0
- package/{src/entities/newid.js → source/entities/newid.ts} +1 -1
- package/{src/entities/set.js → source/entities/set.ts} +8 -5
- package/source/event.ts +57 -0
- package/{src/exceptions.js → source/exceptions.ts} +52 -33
- package/source/exposition.ts +33 -0
- package/source/guard.ts +16 -0
- package/{src/index.js → source/index.ts} +8 -0
- package/{src/locator.js → source/locator.ts} +17 -30
- package/source/observation.ts +16 -0
- package/source/operation.ts +138 -0
- package/{src/outbox/outbox.js → source/outbox/outbox.ts} +87 -53
- package/source/query/criteria.ts +90 -0
- package/source/query/options.ts +35 -0
- package/{src/query.js → source/query.ts} +14 -17
- package/source/receiver.ts +120 -0
- package/source/reflection.ts +20 -0
- package/source/remote.ts +20 -0
- package/source/state.ts +179 -0
- package/source/transition.ts +79 -0
- package/{src/transmission.js → source/transmission.ts} +8 -8
- package/source/types/atomicity.ts +63 -0
- package/source/types/bindings.ts +59 -0
- package/source/types/bridges.ts +54 -0
- package/source/types/extensions.ts +89 -0
- package/{types → source/types}/index.ts +9 -16
- package/{types/message.d.ts → source/types/message.ts} +2 -1
- package/source/types/operations.ts +31 -0
- package/source/types/outbox.ts +35 -0
- package/source/types/receiver.ts +10 -0
- package/{types/request.d.ts → source/types/request.ts} +8 -9
- package/source/types/state.ts +9 -0
- package/source/types/storages.ts +129 -0
- package/source/unmanaged.ts +8 -0
- package/test/call.fixtures.js +3 -1
- package/test/call.test.js +28 -7
- package/test/component.test.js +10 -5
- package/test/connector.fixtures.js +7 -7
- package/test/connector.test.js +15 -2
- package/test/context.fixtures.js +1 -1
- package/test/context.test.js +4 -4
- package/test/contract/conditions.test.js +6 -2
- package/test/contract/contract.fixtures.js +3 -4
- package/test/contract/request.test.js +68 -34
- package/test/discovery.test.js +10 -3
- package/test/emission.test.js +16 -8
- package/test/entities/entity.fixtures.js +5 -6
- package/test/entities/entity.test.js +54 -20
- package/test/entities/factory.fixtures.js +11 -10
- package/test/entities/factory.test.js +47 -10
- package/test/entities/set.test.js +1 -1
- package/test/event.test.js +29 -11
- package/test/locator.test.js +10 -4
- package/test/outbox.test.js +49 -15
- package/test/query.test.js +69 -7
- package/test/receiver.fixtures.js +2 -2
- package/test/receiver.test.js +53 -27
- package/test/reflection.test.js +3 -3
- package/test/state.fixtures.js +10 -3
- package/test/state.test.js +77 -14
- package/test/transmission.test.js +25 -12
- package/transpiled/assignment.d.ts +6 -0
- package/transpiled/assignment.js +20 -0
- package/transpiled/assignment.js.map +1 -0
- package/transpiled/call.d.ts +10 -0
- package/transpiled/call.js +52 -0
- package/transpiled/call.js.map +1 -0
- package/transpiled/cascade.d.ts +7 -0
- package/transpiled/cascade.js +28 -0
- package/transpiled/cascade.js.map +1 -0
- package/transpiled/component.d.ts +15 -0
- package/transpiled/component.js +61 -0
- package/transpiled/component.js.map +1 -0
- package/transpiled/composition.d.ts +6 -0
- package/transpiled/composition.js +23 -0
- package/transpiled/composition.js.map +1 -0
- package/transpiled/connector.d.ts +47 -0
- package/transpiled/connector.js +143 -0
- package/transpiled/connector.js.map +1 -0
- package/transpiled/context.d.ts +18 -0
- package/transpiled/context.js +41 -0
- package/transpiled/context.js.map +1 -0
- package/transpiled/contract/contract.d.ts +10 -0
- package/transpiled/contract/contract.js +14 -0
- package/transpiled/contract/contract.js.map +1 -0
- package/transpiled/contract/index.d.ts +2 -0
- package/transpiled/contract/index.js +3 -0
- package/transpiled/contract/index.js.map +1 -0
- package/transpiled/contract/reply.d.ts +7 -0
- package/transpiled/contract/reply.js +48 -0
- package/transpiled/contract/reply.js.map +1 -0
- package/transpiled/contract/request.d.ts +24 -0
- package/transpiled/contract/request.js +59 -0
- package/transpiled/contract/request.js.map +1 -0
- package/transpiled/contract/schemas.d.ts +4 -0
- package/transpiled/contract/schemas.js +36 -0
- package/transpiled/contract/schemas.js.map +1 -0
- package/transpiled/discovery.d.ts +12 -0
- package/transpiled/discovery.js +34 -0
- package/transpiled/discovery.js.map +1 -0
- package/transpiled/effect.d.ts +5 -0
- package/transpiled/effect.js +11 -0
- package/transpiled/effect.js.map +1 -0
- package/transpiled/emission.d.ts +8 -0
- package/transpiled/emission.js +14 -0
- package/transpiled/emission.js.map +1 -0
- package/transpiled/entities/changeset.d.ts +10 -0
- package/transpiled/entities/changeset.js +27 -0
- package/transpiled/entities/changeset.js.map +1 -0
- package/transpiled/entities/entity.d.ts +19 -0
- package/transpiled/entities/entity.js +109 -0
- package/transpiled/entities/entity.js.map +1 -0
- package/transpiled/entities/factory.d.ts +22 -0
- package/transpiled/entities/factory.js +34 -0
- package/transpiled/entities/factory.js.map +1 -0
- package/transpiled/entities/index.d.ts +4 -0
- package/transpiled/entities/index.js +5 -0
- package/transpiled/entities/index.js.map +1 -0
- package/transpiled/entities/newid.d.ts +1 -0
- package/transpiled/entities/newid.js +7 -0
- package/transpiled/entities/newid.js.map +1 -0
- package/transpiled/entities/set.d.ts +10 -0
- package/transpiled/entities/set.js +19 -0
- package/transpiled/entities/set.js.map +1 -0
- package/transpiled/event.d.ts +14 -0
- package/transpiled/event.js +38 -0
- package/transpiled/event.js.map +1 -0
- package/transpiled/exceptions.d.ts +61 -0
- package/transpiled/exceptions.js +93 -0
- package/transpiled/exceptions.js.map +1 -0
- package/transpiled/exposition.d.ts +18 -0
- package/transpiled/exposition.js +18 -0
- package/transpiled/exposition.js.map +1 -0
- package/transpiled/guard.d.ts +7 -0
- package/transpiled/guard.js +12 -0
- package/transpiled/guard.js.map +1 -0
- package/transpiled/index.d.ts +35 -0
- package/transpiled/index.js +29 -0
- package/transpiled/index.js.map +1 -0
- package/transpiled/locator.d.ts +12 -0
- package/transpiled/locator.js +32 -0
- package/transpiled/locator.js.map +1 -0
- package/transpiled/observation.d.ts +5 -0
- package/transpiled/observation.js +12 -0
- package/transpiled/observation.js.map +1 -0
- package/transpiled/operation.d.ts +49 -0
- package/transpiled/operation.js +77 -0
- package/transpiled/operation.js.map +1 -0
- package/transpiled/outbox/index.d.ts +1 -0
- package/transpiled/outbox/index.js +2 -0
- package/transpiled/outbox/index.js.map +1 -0
- package/transpiled/outbox/outbox.d.ts +46 -0
- package/transpiled/outbox/outbox.js +267 -0
- package/transpiled/outbox/outbox.js.map +1 -0
- package/transpiled/query/criteria.d.ts +6 -0
- package/transpiled/query/criteria.js +74 -0
- package/transpiled/query/criteria.js.map +1 -0
- package/transpiled/query/options.d.ts +3 -0
- package/transpiled/query/options.js +27 -0
- package/transpiled/query/options.js.map +1 -0
- package/transpiled/query.d.ts +9 -0
- package/transpiled/query.js +57 -0
- package/transpiled/query.js.map +1 -0
- package/transpiled/receiver.d.ts +20 -0
- package/transpiled/receiver.js +92 -0
- package/transpiled/receiver.js.map +1 -0
- package/transpiled/reflection.d.ts +9 -0
- package/transpiled/reflection.js +13 -0
- package/transpiled/reflection.js.map +1 -0
- package/transpiled/remote.d.ts +10 -0
- package/transpiled/remote.js +12 -0
- package/transpiled/remote.js.map +1 -0
- package/transpiled/state.d.ts +33 -0
- package/transpiled/state.js +126 -0
- package/transpiled/state.js.map +1 -0
- package/transpiled/transition.d.ts +14 -0
- package/transpiled/transition.js +51 -0
- package/transpiled/transition.js.map +1 -0
- package/transpiled/transmission.d.ts +8 -0
- package/transpiled/transmission.js +30 -0
- package/transpiled/transmission.js.map +1 -0
- package/transpiled/types/atomicity.d.ts +56 -0
- package/transpiled/types/atomicity.js +2 -0
- package/transpiled/types/atomicity.js.map +1 -0
- package/transpiled/types/bindings.d.ts +42 -0
- package/transpiled/types/bindings.js +2 -0
- package/transpiled/types/bindings.js.map +1 -0
- package/transpiled/types/bridges.d.ts +38 -0
- package/transpiled/types/bridges.js +2 -0
- package/transpiled/types/bridges.js.map +1 -0
- package/transpiled/types/extensions.d.ts +62 -0
- package/transpiled/types/extensions.js +2 -0
- package/transpiled/types/extensions.js.map +1 -0
- package/transpiled/types/index.d.ts +13 -0
- package/transpiled/types/index.js +8 -0
- package/transpiled/types/index.js.map +1 -0
- package/transpiled/types/message.d.ts +5 -0
- package/transpiled/types/message.js +2 -0
- package/transpiled/types/message.js.map +1 -0
- package/transpiled/types/operations.d.ts +15 -0
- package/transpiled/types/operations.js +2 -0
- package/transpiled/types/operations.js.map +1 -0
- package/transpiled/types/outbox.d.ts +28 -0
- package/transpiled/types/outbox.js +2 -0
- package/transpiled/types/outbox.js.map +1 -0
- package/transpiled/types/receiver.d.ts +9 -0
- package/transpiled/types/receiver.js +2 -0
- package/transpiled/types/receiver.js.map +1 -0
- package/transpiled/types/request.d.ts +55 -0
- package/transpiled/types/request.js +2 -0
- package/transpiled/types/request.js.map +1 -0
- package/transpiled/types/state.d.ts +9 -0
- package/transpiled/types/state.js +2 -0
- package/transpiled/types/state.js.map +1 -0
- package/transpiled/types/storages.d.ts +106 -0
- package/transpiled/types/storages.js +2 -0
- package/transpiled/types/storages.js.map +1 -0
- package/transpiled/unmanaged.d.ts +5 -0
- package/transpiled/unmanaged.js +7 -0
- package/transpiled/unmanaged.js.map +1 -0
- package/tsconfig.json +10 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/src/assignment.js +0 -28
- package/src/context.js +0 -57
- package/src/contract/contract.js +0 -18
- package/src/contract/request.js +0 -77
- package/src/contract/schemas/error.yaml +0 -9
- package/src/contract/schemas/index.js +0 -11
- package/src/contract/schemas/query.yaml +0 -43
- package/src/contract/schemas/source.yaml +0 -23
- package/src/effect.js +0 -15
- package/src/entities/changeset.js +0 -36
- package/src/entities/entity.js +0 -119
- package/src/entities/factory.js +0 -40
- package/src/entities/index.js +0 -1
- package/src/event.js +0 -54
- package/src/exposition.js +0 -24
- package/src/guard.js +0 -13
- package/src/observation.js +0 -8
- package/src/operation.js +0 -95
- package/src/query/criteria.js +0 -44
- package/src/query/options.js +0 -37
- package/src/receiver.js +0 -123
- package/src/reflection.js +0 -24
- package/src/remote.js +0 -14
- package/src/state.js +0 -138
- package/src/transition.js +0 -61
- package/src/unmanaged.js +0 -7
- package/types/atomicity.d.ts +0 -79
- package/types/bindings.d.ts +0 -42
- package/types/bridges.ts +0 -33
- package/types/call.d.ts +0 -13
- package/types/component.d.ts +0 -12
- package/types/connector.d.ts +0 -18
- package/types/context.d.ts +0 -24
- package/types/entity.d.ts +0 -46
- package/types/event.d.ts +0 -11
- package/types/exception.d.ts +0 -4
- package/types/extensions.d.ts +0 -73
- package/types/guard.d.ts +0 -5
- package/types/locator.d.ts +0 -13
- package/types/operations.d.ts +0 -8
- package/types/outbox.d.ts +0 -53
- package/types/query.d.ts +0 -17
- package/types/receiver.d.ts +0 -12
- package/types/reflection.d.ts +0 -14
- package/types/remote.d.ts +0 -19
- package/types/state.d.ts +0 -38
- package/types/storages.d.ts +0 -96
- /package/{src/contract/index.js → source/contract/index.ts} +0 -0
- /package/{src/outbox/index.js → source/outbox/index.ts} +0 -0
package/test/emission.test.js
CHANGED
|
@@ -4,15 +4,16 @@ import { isDeepStrictEqual } from 'node:util'
|
|
|
4
4
|
|
|
5
5
|
import clone from 'clone-deep'
|
|
6
6
|
|
|
7
|
-
import { Connector } from '../
|
|
7
|
+
import { Connector } from '../source/connector.js'
|
|
8
8
|
|
|
9
9
|
// the fixtures are not connectors, so a dependency is recorded rather than linked
|
|
10
10
|
const depends = mock.method(Connector.prototype, 'depends', () => undefined)
|
|
11
11
|
|
|
12
|
-
const dependencies = (instance) =>
|
|
13
|
-
.
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
const dependencies = (instance) =>
|
|
13
|
+
depends.mock.calls
|
|
14
|
+
.filter((call) => call.this === instance)
|
|
15
|
+
.map((call) => call.arguments[0])
|
|
16
|
+
import { Emission } from '../source/emission.js'
|
|
16
17
|
import * as fixtures from './emission.fixtures.js'
|
|
17
18
|
|
|
18
19
|
let emission, event
|
|
@@ -33,15 +34,22 @@ it('should depend on events', () => {
|
|
|
33
34
|
})
|
|
34
35
|
|
|
35
36
|
it('should emit events', async () => {
|
|
36
|
-
|
|
37
37
|
await emission.emit(event)
|
|
38
38
|
|
|
39
39
|
for (const evt of fixtures.events) {
|
|
40
|
-
assert.ok(
|
|
40
|
+
assert.ok(
|
|
41
|
+
evt.emit.mock.calls.some(
|
|
42
|
+
(call) =>
|
|
43
|
+
call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], event)
|
|
44
|
+
)
|
|
45
|
+
)
|
|
41
46
|
}
|
|
42
47
|
})
|
|
43
48
|
|
|
44
|
-
function resetCalls
|
|
49
|
+
function resetCalls(
|
|
50
|
+
target = [assert, clone, depends, dependencies, fixtures],
|
|
51
|
+
seen = new Set()
|
|
52
|
+
) {
|
|
45
53
|
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
46
54
|
|
|
47
55
|
seen.add(target)
|
|
@@ -4,8 +4,7 @@ import { generate } from 'randomstring'
|
|
|
4
4
|
|
|
5
5
|
// noinspection JSCheckFunctionSignatures
|
|
6
6
|
export const schema = {
|
|
7
|
-
fit: mock.fn((object) =>
|
|
8
|
-
(object.fail ? { [generate()]: generate() } : null)),
|
|
7
|
+
fit: mock.fn((object) => (object.fail ? { [generate()]: generate() } : null)),
|
|
9
8
|
|
|
10
9
|
defaults: mock.fn(() => ({ [generate()]: generate() }))
|
|
11
10
|
}
|
|
@@ -13,10 +12,10 @@ export const schema = {
|
|
|
13
12
|
export const state = () => ({
|
|
14
13
|
id: generate(),
|
|
15
14
|
foo: generate(),
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
CREATED: generate(),
|
|
16
|
+
UPDATED: generate(),
|
|
17
|
+
DELETED: generate(),
|
|
18
|
+
VERSION: 0
|
|
20
19
|
})
|
|
21
20
|
|
|
22
21
|
export const failed = () => ({
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { describe, it, beforeEach
|
|
1
|
+
import { describe, it, beforeEach } from 'node:test'
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
3
|
|
|
4
|
-
import { Entity } from '../../
|
|
4
|
+
import { Entity } from '../../source/entities/entity.js'
|
|
5
5
|
import * as fixtures from './entity.fixtures.js'
|
|
6
6
|
|
|
7
|
+
const BLANK = {}
|
|
8
|
+
|
|
7
9
|
beforeEach(() => {
|
|
8
10
|
resetCalls()
|
|
9
11
|
})
|
|
@@ -11,74 +13,106 @@ beforeEach(() => {
|
|
|
11
13
|
describe('argument', () => {
|
|
12
14
|
it('should set state', () => {
|
|
13
15
|
const state = fixtures.state()
|
|
14
|
-
const entity = new Entity(fixtures.schema, state)
|
|
16
|
+
const entity = new Entity(fixtures.schema, BLANK, state)
|
|
15
17
|
|
|
16
18
|
assert.deepStrictEqual(entity.get(), state)
|
|
17
19
|
})
|
|
18
20
|
|
|
19
21
|
it('should snapshot the record it may commit', () => {
|
|
20
22
|
const record = fixtures.state()
|
|
21
|
-
const entity = new Entity(fixtures.schema, record)
|
|
23
|
+
const entity = new Entity(fixtures.schema, BLANK, record)
|
|
22
24
|
|
|
23
25
|
assert.notStrictEqual(entity.get(), record)
|
|
24
26
|
assert.strictEqual(entity.event().origin, record)
|
|
25
27
|
})
|
|
26
28
|
})
|
|
27
29
|
|
|
30
|
+
describe('blank', () => {
|
|
31
|
+
it('should write what the component declares a record starts as', () => {
|
|
32
|
+
const entity = new Entity(fixtures.schema, { foo: 'declared' })
|
|
33
|
+
const state = entity.get()
|
|
34
|
+
|
|
35
|
+
assert.strictEqual(state.foo, 'declared')
|
|
36
|
+
assert.strictEqual(state.VERSION, 0)
|
|
37
|
+
assert.strictEqual(state.DELETED, null)
|
|
38
|
+
assert.strictEqual(typeof state.id, 'string')
|
|
39
|
+
assert.strictEqual(entity.event().origin, null)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('should not validate it', () => {
|
|
43
|
+
const entity = new Entity(fixtures.schema, { fail: true })
|
|
44
|
+
|
|
45
|
+
assert.strictEqual(entity.get().fail, true)
|
|
46
|
+
assert.strictEqual(fixtures.schema.fit.mock.callCount(), 0)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('should give every record its own copy', () => {
|
|
50
|
+
const blank = { foo: { bar: 'nested' } }
|
|
51
|
+
const one = new Entity(fixtures.schema, blank)
|
|
52
|
+
const other = new Entity(fixtures.schema, blank)
|
|
53
|
+
|
|
54
|
+
assert.notStrictEqual(one.get().foo, other.get().foo)
|
|
55
|
+
assert.notStrictEqual(one.get().foo, blank.foo)
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
|
|
28
59
|
describe('read-only', () => {
|
|
29
60
|
it('should take the record as it came', () => {
|
|
30
61
|
const record = fixtures.state()
|
|
31
|
-
const entity = new Entity(fixtures.schema, record, undefined, false)
|
|
62
|
+
const entity = new Entity(fixtures.schema, BLANK, record, undefined, false)
|
|
32
63
|
|
|
33
64
|
// no pre-image to diff against, hence no copy of it
|
|
34
65
|
assert.strictEqual(entity.get(), record)
|
|
35
66
|
})
|
|
36
67
|
|
|
37
68
|
it('should still report a tombstone', () => {
|
|
38
|
-
const record = { ...fixtures.state(),
|
|
39
|
-
const entity = new Entity(fixtures.schema, record, undefined, false)
|
|
69
|
+
const record = { ...fixtures.state(), DELETED: Date.now() }
|
|
70
|
+
const entity = new Entity(fixtures.schema, BLANK, record, undefined, false)
|
|
40
71
|
|
|
41
72
|
assert.strictEqual(entity.deleted, true)
|
|
42
73
|
})
|
|
43
74
|
|
|
44
75
|
it('should refuse to be modified', () => {
|
|
45
|
-
const entity = new Entity(fixtures.schema, fixtures.state(), undefined, false)
|
|
76
|
+
const entity = new Entity(fixtures.schema, BLANK, fixtures.state(), undefined, false)
|
|
46
77
|
|
|
47
|
-
assert.throws(
|
|
78
|
+
assert.throws(
|
|
79
|
+
() => entity.set(entity.get()),
|
|
80
|
+
(error) => /read-only/.test(error.message)
|
|
81
|
+
)
|
|
48
82
|
})
|
|
49
83
|
})
|
|
50
84
|
|
|
51
85
|
describe('tombstone', () => {
|
|
52
|
-
it('should lift tombstone when transition leaves
|
|
86
|
+
it('should lift tombstone when transition leaves DELETED untouched', () => {
|
|
53
87
|
const origin = fixtures.state()
|
|
54
|
-
const entity = new Entity(fixtures.schema, origin)
|
|
88
|
+
const entity = new Entity(fixtures.schema, BLANK, origin)
|
|
55
89
|
const state = entity.get()
|
|
56
90
|
|
|
57
91
|
state.foo = 'revived'
|
|
58
92
|
entity.set(state)
|
|
59
93
|
|
|
60
|
-
assert.strictEqual(entity.get().
|
|
94
|
+
assert.strictEqual(entity.get().DELETED, null)
|
|
61
95
|
assert.strictEqual(entity.deleted, false)
|
|
62
|
-
assert.strictEqual(entity.event().state.
|
|
96
|
+
assert.strictEqual(entity.event().state.DELETED, null)
|
|
63
97
|
})
|
|
64
98
|
|
|
65
99
|
it('should keep tombstone written by transition', () => {
|
|
66
|
-
const origin = { ...fixtures.state(),
|
|
67
|
-
const entity = new Entity(fixtures.schema, origin)
|
|
100
|
+
const origin = { ...fixtures.state(), DELETED: null }
|
|
101
|
+
const entity = new Entity(fixtures.schema, BLANK, origin)
|
|
68
102
|
const state = entity.get()
|
|
69
103
|
const timestamp = Date.now()
|
|
70
104
|
|
|
71
|
-
state.
|
|
105
|
+
state.DELETED = timestamp
|
|
72
106
|
entity.set(state)
|
|
73
107
|
|
|
74
|
-
assert.strictEqual(entity.get().
|
|
108
|
+
assert.strictEqual(entity.get().DELETED, timestamp)
|
|
75
109
|
assert.strictEqual(entity.deleted, true)
|
|
76
110
|
})
|
|
77
111
|
})
|
|
78
112
|
|
|
79
113
|
it('should provide event', () => {
|
|
80
114
|
const origin = fixtures.state()
|
|
81
|
-
const entity = new Entity(fixtures.schema, origin)
|
|
115
|
+
const entity = new Entity(fixtures.schema, BLANK, origin)
|
|
82
116
|
const state = entity.get()
|
|
83
117
|
|
|
84
118
|
state.foo = 'new value'
|
|
@@ -88,11 +122,11 @@ it('should provide event', () => {
|
|
|
88
122
|
|
|
89
123
|
assert.partialDeepStrictEqual(event, { state, origin })
|
|
90
124
|
assert.strictEqual(event.state.foo, 'new value')
|
|
91
|
-
assert.strictEqual(event.state.
|
|
125
|
+
assert.strictEqual(event.state.VERSION, 1)
|
|
92
126
|
assert.notStrictEqual(event.origin.foo, 'new value')
|
|
93
127
|
})
|
|
94
128
|
|
|
95
|
-
function resetCalls
|
|
129
|
+
function resetCalls(target = [assert, fixtures], seen = new Set()) {
|
|
96
130
|
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
97
131
|
|
|
98
132
|
seen.add(target)
|
|
@@ -2,11 +2,18 @@ import { mock } from 'node:test'
|
|
|
2
2
|
|
|
3
3
|
import randomstring from 'randomstring'
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const schemas = {
|
|
6
|
+
entity: { [randomstring.generate()]: randomstring.generate() },
|
|
7
|
+
changeset: { [randomstring.generate()]: randomstring.generate() }
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const blank = { [randomstring.generate()]: randomstring.generate() }
|
|
6
11
|
const storage = { id: mock.fn(() => randomstring.generate()) }
|
|
7
12
|
const entity = { [randomstring.generate()]: randomstring.generate() }
|
|
8
|
-
const set = Array.from(Array(5))
|
|
9
|
-
|
|
13
|
+
const set = Array.from(Array(5)).map((_, index) => ({
|
|
14
|
+
id: index,
|
|
15
|
+
[randomstring.generate()]: randomstring.generate()
|
|
16
|
+
}))
|
|
10
17
|
|
|
11
18
|
// node:test records a mock's calls but not the instances it constructed
|
|
12
19
|
const entities = []
|
|
@@ -18,13 +25,7 @@ const Entity = mock.fn(function () {
|
|
|
18
25
|
|
|
19
26
|
const EntitySet = mock.fn(function () {})
|
|
20
27
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
28
|
// named `mock` for its consumers, which is what node:test calls its own tracker
|
|
28
29
|
const mocks = { Entity, EntitySet }
|
|
29
30
|
|
|
30
|
-
export {
|
|
31
|
+
export { schemas, blank, storage, entity, set, entities, mocks as mock }
|
|
@@ -7,11 +7,14 @@ import { generate } from 'randomstring'
|
|
|
7
7
|
import * as fixtures from './factory.fixtures.js'
|
|
8
8
|
const mock = fixtures.mock
|
|
9
9
|
|
|
10
|
-
mocking.module('../../
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
mocking.module('../../source/entities/entity.js', {
|
|
11
|
+
namedExports: { Entity: mock.Entity }
|
|
12
|
+
})
|
|
13
|
+
mocking.module('../../source/entities/set.js', {
|
|
14
|
+
namedExports: { EntitySet: mock.EntitySet }
|
|
15
|
+
})
|
|
14
16
|
|
|
17
|
+
const { Factory } = await import('../../source/entities/factory.js')
|
|
15
18
|
|
|
16
19
|
let factory
|
|
17
20
|
|
|
@@ -19,7 +22,7 @@ beforeEach(async () => {
|
|
|
19
22
|
resetCalls()
|
|
20
23
|
fixtures.entities.length = 0
|
|
21
24
|
|
|
22
|
-
factory = new Factory(fixtures.
|
|
25
|
+
factory = new Factory(fixtures.schemas, fixtures.blank, () => fixtures.storage.id())
|
|
23
26
|
})
|
|
24
27
|
|
|
25
28
|
it('should create initial', () => {
|
|
@@ -27,14 +30,33 @@ it('should create initial', () => {
|
|
|
27
30
|
const initial = factory.init(id)
|
|
28
31
|
|
|
29
32
|
assert.ok(initial instanceof mock.Entity)
|
|
30
|
-
assert.ok(
|
|
33
|
+
assert.ok(
|
|
34
|
+
mock.Entity.mock.calls.some(
|
|
35
|
+
(call) =>
|
|
36
|
+
call.arguments.length === 4 &&
|
|
37
|
+
isDeepStrictEqual(call.arguments[0], fixtures.schemas.entity) &&
|
|
38
|
+
isDeepStrictEqual(call.arguments[1], fixtures.blank) &&
|
|
39
|
+
isDeepStrictEqual(call.arguments[2], id) &&
|
|
40
|
+
typeof call.arguments[3] === 'function'
|
|
41
|
+
)
|
|
42
|
+
)
|
|
31
43
|
})
|
|
32
44
|
|
|
33
45
|
it('should create instance', () => {
|
|
34
46
|
const object = factory.object(fixtures.entity)
|
|
35
47
|
|
|
36
48
|
assert.ok(object instanceof mock.Entity)
|
|
37
|
-
assert.ok(
|
|
49
|
+
assert.ok(
|
|
50
|
+
mock.Entity.mock.calls.some(
|
|
51
|
+
(call) =>
|
|
52
|
+
call.arguments.length === 5 &&
|
|
53
|
+
isDeepStrictEqual(call.arguments[0], fixtures.schemas.entity) &&
|
|
54
|
+
isDeepStrictEqual(call.arguments[1], fixtures.blank) &&
|
|
55
|
+
isDeepStrictEqual(call.arguments[2], fixtures.entity) &&
|
|
56
|
+
typeof call.arguments[3] === 'function' &&
|
|
57
|
+
isDeepStrictEqual(call.arguments[4], true)
|
|
58
|
+
)
|
|
59
|
+
)
|
|
38
60
|
})
|
|
39
61
|
|
|
40
62
|
it('should create set', () => {
|
|
@@ -43,15 +65,30 @@ it('should create set', () => {
|
|
|
43
65
|
assert.ok(objects instanceof mock.EntitySet)
|
|
44
66
|
|
|
45
67
|
const instances = fixtures.set.map((entity, index) => {
|
|
46
|
-
assert.ok(
|
|
68
|
+
assert.ok(
|
|
69
|
+
((call) =>
|
|
70
|
+
call.arguments.length === 5 &&
|
|
71
|
+
isDeepStrictEqual(call.arguments[0], fixtures.schemas.entity) &&
|
|
72
|
+
isDeepStrictEqual(call.arguments[1], fixtures.blank) &&
|
|
73
|
+
isDeepStrictEqual(call.arguments[2], entity) &&
|
|
74
|
+
typeof call.arguments[3] === 'function' &&
|
|
75
|
+
isDeepStrictEqual(call.arguments[4], true))(
|
|
76
|
+
mock.Entity.mock.calls[index + 1 - 1] ?? { arguments: [] }
|
|
77
|
+
)
|
|
78
|
+
)
|
|
47
79
|
|
|
48
80
|
return fixtures.entities[index]
|
|
49
81
|
})
|
|
50
82
|
|
|
51
|
-
assert.ok(
|
|
83
|
+
assert.ok(
|
|
84
|
+
mock.EntitySet.mock.calls.some(
|
|
85
|
+
(call) =>
|
|
86
|
+
call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], instances)
|
|
87
|
+
)
|
|
88
|
+
)
|
|
52
89
|
})
|
|
53
90
|
|
|
54
|
-
function resetCalls
|
|
91
|
+
function resetCalls(target = [assert, fixtures, mock], seen = new Set()) {
|
|
55
92
|
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
56
93
|
|
|
57
94
|
seen.add(target)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { it } from 'node:test'
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
3
|
|
|
4
|
-
import { EntitySet } from '../../
|
|
4
|
+
import { EntitySet } from '../../source/entities/set.js'
|
|
5
5
|
import * as fixtures from './set.fixtures.js'
|
|
6
6
|
|
|
7
7
|
it('should provide state', () => {
|
package/test/event.test.js
CHANGED
|
@@ -4,8 +4,8 @@ import { isDeepStrictEqual } from 'node:util'
|
|
|
4
4
|
|
|
5
5
|
import clone from 'clone-deep'
|
|
6
6
|
|
|
7
|
-
import { Connector } from '../
|
|
8
|
-
import { Event } from '../
|
|
7
|
+
import { Connector } from '../source/connector.js'
|
|
8
|
+
import { Event } from '../source/event.js'
|
|
9
9
|
import * as fixtures from './event.fixtures.js'
|
|
10
10
|
|
|
11
11
|
let event, emit
|
|
@@ -13,9 +13,10 @@ let event, emit
|
|
|
13
13
|
// the fixtures are not connectors, so the dependency is recorded rather than linked
|
|
14
14
|
const depends = mock.method(Connector.prototype, 'depends', () => undefined)
|
|
15
15
|
|
|
16
|
-
const dependencies = (instance) =>
|
|
17
|
-
.
|
|
18
|
-
|
|
16
|
+
const dependencies = (instance) =>
|
|
17
|
+
depends.mock.calls
|
|
18
|
+
.filter((call) => call.this === instance)
|
|
19
|
+
.map((call) => call.arguments[0])
|
|
19
20
|
|
|
20
21
|
beforeEach(() => {
|
|
21
22
|
resetCalls()
|
|
@@ -35,7 +36,9 @@ it('should depend on bridge if provided', () => {
|
|
|
35
36
|
|
|
36
37
|
const bridgeless = new Event(fixtures.definition, fixtures.binding)
|
|
37
38
|
|
|
38
|
-
assert.ok(
|
|
39
|
+
assert.ok(
|
|
40
|
+
!dependencies(bridgeless).some((one) => isDeepStrictEqual(one, fixtures.bridge))
|
|
41
|
+
)
|
|
39
42
|
})
|
|
40
43
|
|
|
41
44
|
describe('condition', () => {
|
|
@@ -43,7 +46,13 @@ describe('condition', () => {
|
|
|
43
46
|
it('should call condition', async () => {
|
|
44
47
|
await emit()
|
|
45
48
|
|
|
46
|
-
assert.ok(
|
|
49
|
+
assert.ok(
|
|
50
|
+
fixtures.bridge.condition.mock.calls.some(
|
|
51
|
+
(call) =>
|
|
52
|
+
call.arguments.length === 1 &&
|
|
53
|
+
isDeepStrictEqual(call.arguments[0], fixtures.event)
|
|
54
|
+
)
|
|
55
|
+
)
|
|
47
56
|
})
|
|
48
57
|
|
|
49
58
|
it('should emit if condition returns true', async () => {
|
|
@@ -74,9 +83,15 @@ describe('condition', () => {
|
|
|
74
83
|
})
|
|
75
84
|
|
|
76
85
|
it('should not call condition', async () => {
|
|
77
|
-
await event.emit(
|
|
86
|
+
await event.emit(
|
|
87
|
+
fixtures.event.origin,
|
|
88
|
+
fixtures.event.changeset,
|
|
89
|
+
fixtures.event.state
|
|
90
|
+
)
|
|
78
91
|
|
|
79
|
-
assert.ok(
|
|
92
|
+
assert.ok(
|
|
93
|
+
!fixtures.bridge.condition.mock.calls.some((call) => call.arguments.length === 0)
|
|
94
|
+
)
|
|
80
95
|
|
|
81
96
|
const payload = await fixtures.bridge.payload.mock.calls[0].result
|
|
82
97
|
assertEmitted(payload)
|
|
@@ -119,7 +134,10 @@ describe('payload', () => {
|
|
|
119
134
|
})
|
|
120
135
|
})
|
|
121
136
|
|
|
122
|
-
function resetCalls
|
|
137
|
+
function resetCalls(
|
|
138
|
+
target = [assert, clone, fixtures, depends, dependencies],
|
|
139
|
+
seen = new Set()
|
|
140
|
+
) {
|
|
123
141
|
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
124
142
|
|
|
125
143
|
seen.add(target)
|
|
@@ -130,7 +148,7 @@ function resetCalls (target = [assert, clone, fixtures, depends, dependencies],
|
|
|
130
148
|
}
|
|
131
149
|
|
|
132
150
|
/** The message carries the payload and a telemetry token generated per emission. */
|
|
133
|
-
function assertEmitted
|
|
151
|
+
function assertEmitted(payload) {
|
|
134
152
|
const emitted = fixtures.binding.emit.mock.calls
|
|
135
153
|
.map((call) => call.arguments[0])
|
|
136
154
|
.filter((message) => isDeepStrictEqual(message.payload, payload))
|
package/test/locator.test.js
CHANGED
|
@@ -2,7 +2,7 @@ import { describe, it, beforeEach } from 'node:test'
|
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
3
|
|
|
4
4
|
import { generate } from 'randomstring'
|
|
5
|
-
import { Locator } from '../
|
|
5
|
+
import { Locator } from '../source/locator.js'
|
|
6
6
|
|
|
7
7
|
/** @type {string} */
|
|
8
8
|
let name
|
|
@@ -10,7 +10,7 @@ let name
|
|
|
10
10
|
/** @type {string} */
|
|
11
11
|
let namespace
|
|
12
12
|
|
|
13
|
-
/** @type {toa.core.Locator} */
|
|
13
|
+
/** @type {import('@toa.io/core').Locator} */
|
|
14
14
|
let locator
|
|
15
15
|
|
|
16
16
|
beforeEach(() => {
|
|
@@ -34,7 +34,10 @@ it('should expose id, label', () => {
|
|
|
34
34
|
})
|
|
35
35
|
|
|
36
36
|
it('should expose uppercase', () => {
|
|
37
|
-
assert.deepStrictEqual(
|
|
37
|
+
assert.deepStrictEqual(
|
|
38
|
+
locator.uppercase,
|
|
39
|
+
(locator.namespace + '_' + locator.name).toUpperCase()
|
|
40
|
+
)
|
|
38
41
|
})
|
|
39
42
|
|
|
40
43
|
it('should throw if name is undefined', () => {
|
|
@@ -51,7 +54,10 @@ it('should expose host', () => {
|
|
|
51
54
|
it('should expose host with given prefix', () => {
|
|
52
55
|
const prefix = generate()
|
|
53
56
|
|
|
54
|
-
assert.deepStrictEqual(
|
|
57
|
+
assert.deepStrictEqual(
|
|
58
|
+
locator.hostname(prefix),
|
|
59
|
+
(prefix + '-' + namespace + '-' + name).toLowerCase()
|
|
60
|
+
)
|
|
55
61
|
})
|
|
56
62
|
|
|
57
63
|
describe('global', () => {
|
package/test/outbox.test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { it, beforeEach, afterEach, mock } from 'node:test'
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
3
|
|
|
4
|
-
import { Outbox } from '../
|
|
4
|
+
import { Outbox } from '../source/outbox/index.js'
|
|
5
5
|
|
|
6
6
|
let emission, storage, atom, outbox, listeners
|
|
7
7
|
|
|
@@ -36,7 +36,9 @@ beforeEach(() => {
|
|
|
36
36
|
listeners.push(listener)
|
|
37
37
|
listener({ i: 0, n: 1 })
|
|
38
38
|
|
|
39
|
-
return () => {
|
|
39
|
+
return () => {
|
|
40
|
+
listeners = listeners.filter((one) => one !== listener)
|
|
41
|
+
}
|
|
40
42
|
},
|
|
41
43
|
link: mock.fn()
|
|
42
44
|
}
|
|
@@ -70,9 +72,18 @@ it('should read nothing more when the first page is short', async () => {
|
|
|
70
72
|
})
|
|
71
73
|
|
|
72
74
|
it('should keep reading while a page comes back full', async () => {
|
|
73
|
-
storage.outbox.pending.mock.mockImplementationOnce(
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
storage.outbox.pending.mock.mockImplementationOnce(
|
|
76
|
+
async () => page(0, BATCH),
|
|
77
|
+
storage.outbox.pending.mock.callCount()
|
|
78
|
+
)
|
|
79
|
+
storage.outbox.pending.mock.mockImplementationOnce(
|
|
80
|
+
async () => page(BATCH, BATCH),
|
|
81
|
+
storage.outbox.pending.mock.callCount() + 1
|
|
82
|
+
)
|
|
83
|
+
storage.outbox.pending.mock.mockImplementationOnce(
|
|
84
|
+
async () => page(2 * BATCH, 5),
|
|
85
|
+
storage.outbox.pending.mock.callCount() + 2
|
|
86
|
+
)
|
|
76
87
|
|
|
77
88
|
await outbox.open()
|
|
78
89
|
await cycle()
|
|
@@ -82,8 +93,14 @@ it('should keep reading while a page comes back full', async () => {
|
|
|
82
93
|
})
|
|
83
94
|
|
|
84
95
|
it('should continue each page from the id the one before ended on', async () => {
|
|
85
|
-
storage.outbox.pending.mock.mockImplementationOnce(
|
|
86
|
-
|
|
96
|
+
storage.outbox.pending.mock.mockImplementationOnce(
|
|
97
|
+
async () => page(0, BATCH),
|
|
98
|
+
storage.outbox.pending.mock.callCount()
|
|
99
|
+
)
|
|
100
|
+
storage.outbox.pending.mock.mockImplementationOnce(
|
|
101
|
+
async () => page(BATCH, 1),
|
|
102
|
+
storage.outbox.pending.mock.callCount() + 1
|
|
103
|
+
)
|
|
87
104
|
|
|
88
105
|
await outbox.open()
|
|
89
106
|
await cycle()
|
|
@@ -95,8 +112,14 @@ it('should continue each page from the id the one before ended on', async () =>
|
|
|
95
112
|
})
|
|
96
113
|
|
|
97
114
|
it('should mark what it published, once, after the last page', async () => {
|
|
98
|
-
storage.outbox.pending.mock.mockImplementationOnce(
|
|
99
|
-
|
|
115
|
+
storage.outbox.pending.mock.mockImplementationOnce(
|
|
116
|
+
async () => page(0, BATCH),
|
|
117
|
+
storage.outbox.pending.mock.callCount()
|
|
118
|
+
)
|
|
119
|
+
storage.outbox.pending.mock.mockImplementationOnce(
|
|
120
|
+
async () => page(BATCH, 2),
|
|
121
|
+
storage.outbox.pending.mock.callCount() + 1
|
|
122
|
+
)
|
|
100
123
|
|
|
101
124
|
await outbox.open()
|
|
102
125
|
await cycle()
|
|
@@ -106,9 +129,17 @@ it('should mark what it published, once, after the last page', async () => {
|
|
|
106
129
|
})
|
|
107
130
|
|
|
108
131
|
it('should not publish a row it has published and not yet marked', async () => {
|
|
109
|
-
storage.outbox.settle.mock.mockImplementationOnce(async () => {
|
|
110
|
-
|
|
111
|
-
|
|
132
|
+
storage.outbox.settle.mock.mockImplementationOnce(async () => {
|
|
133
|
+
throw new Error('mongo is out')
|
|
134
|
+
})
|
|
135
|
+
storage.outbox.pending.mock.mockImplementationOnce(
|
|
136
|
+
async () => page(0, 2),
|
|
137
|
+
storage.outbox.pending.mock.callCount()
|
|
138
|
+
)
|
|
139
|
+
storage.outbox.pending.mock.mockImplementationOnce(
|
|
140
|
+
async () => page(0, 2),
|
|
141
|
+
storage.outbox.pending.mock.callCount() + 1
|
|
142
|
+
)
|
|
112
143
|
|
|
113
144
|
await outbox.open()
|
|
114
145
|
await cycle()
|
|
@@ -126,7 +157,7 @@ it('should read nothing while it owns no slots', async () => {
|
|
|
126
157
|
assert.strictEqual(storage.outbox.pending.mock.callCount(), 0)
|
|
127
158
|
})
|
|
128
159
|
|
|
129
|
-
function resetCalls
|
|
160
|
+
function resetCalls(target = [assert, BATCH, page, cycle], seen = new Set()) {
|
|
130
161
|
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
131
162
|
|
|
132
163
|
seen.add(target)
|
|
@@ -150,8 +181,11 @@ it('should read as soon as a claim arrives, rather than on its next cycle', asyn
|
|
|
150
181
|
|
|
151
182
|
await settled()
|
|
152
183
|
|
|
153
|
-
assert.strictEqual(
|
|
154
|
-
|
|
184
|
+
assert.strictEqual(
|
|
185
|
+
storage.outbox.pending.mock.callCount(),
|
|
186
|
+
1,
|
|
187
|
+
'the lane is its own now, and the cycle is up to five seconds away'
|
|
188
|
+
)
|
|
155
189
|
})
|
|
156
190
|
|
|
157
191
|
it('should read the lanes it inherits when the group resizes', async () => {
|