@toa.io/core 1.0.0-alpha.283 → 1.0.0-alpha.286
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/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} +95 -51
- 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 +95 -14
- package/test/query.test.js +76 -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/CHANGELOG.md +0 -180
- 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 -37
- 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 -58
- 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 -18
- 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/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,9 +1,9 @@
|
|
|
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
|
-
let emission, storage, atom, outbox
|
|
6
|
+
let emission, storage, atom, outbox, listeners
|
|
7
7
|
|
|
8
8
|
const BATCH = 4
|
|
9
9
|
|
|
@@ -28,7 +28,20 @@ beforeEach(() => {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
listeners = []
|
|
32
|
+
|
|
33
|
+
atom = {
|
|
34
|
+
slots: mock.fn(() => [0]),
|
|
35
|
+
onassigned: (listener) => {
|
|
36
|
+
listeners.push(listener)
|
|
37
|
+
listener({ i: 0, n: 1 })
|
|
38
|
+
|
|
39
|
+
return () => {
|
|
40
|
+
listeners = listeners.filter((one) => one !== listener)
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
link: mock.fn()
|
|
44
|
+
}
|
|
32
45
|
outbox = new Outbox(emission, storage, atom, { interval: 1000, batch: BATCH })
|
|
33
46
|
})
|
|
34
47
|
|
|
@@ -36,6 +49,11 @@ afterEach(() => {
|
|
|
36
49
|
mock.timers.reset()
|
|
37
50
|
})
|
|
38
51
|
|
|
52
|
+
/** everything the current turn awaited, without moving the clock */
|
|
53
|
+
const settled = async () => {
|
|
54
|
+
for (let i = 0; i < 20; i++) await Promise.resolve()
|
|
55
|
+
}
|
|
56
|
+
|
|
39
57
|
/** one cycle, and everything it awaited */
|
|
40
58
|
const cycle = async () => {
|
|
41
59
|
mock.timers.tick(1000)
|
|
@@ -54,9 +72,18 @@ it('should read nothing more when the first page is short', async () => {
|
|
|
54
72
|
})
|
|
55
73
|
|
|
56
74
|
it('should keep reading while a page comes back full', async () => {
|
|
57
|
-
storage.outbox.pending.mock.mockImplementationOnce(
|
|
58
|
-
|
|
59
|
-
|
|
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
|
+
)
|
|
60
87
|
|
|
61
88
|
await outbox.open()
|
|
62
89
|
await cycle()
|
|
@@ -66,8 +93,14 @@ it('should keep reading while a page comes back full', async () => {
|
|
|
66
93
|
})
|
|
67
94
|
|
|
68
95
|
it('should continue each page from the id the one before ended on', async () => {
|
|
69
|
-
storage.outbox.pending.mock.mockImplementationOnce(
|
|
70
|
-
|
|
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
|
+
)
|
|
71
104
|
|
|
72
105
|
await outbox.open()
|
|
73
106
|
await cycle()
|
|
@@ -79,8 +112,14 @@ it('should continue each page from the id the one before ended on', async () =>
|
|
|
79
112
|
})
|
|
80
113
|
|
|
81
114
|
it('should mark what it published, once, after the last page', async () => {
|
|
82
|
-
storage.outbox.pending.mock.mockImplementationOnce(
|
|
83
|
-
|
|
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
|
+
)
|
|
84
123
|
|
|
85
124
|
await outbox.open()
|
|
86
125
|
await cycle()
|
|
@@ -90,9 +129,17 @@ it('should mark what it published, once, after the last page', async () => {
|
|
|
90
129
|
})
|
|
91
130
|
|
|
92
131
|
it('should not publish a row it has published and not yet marked', async () => {
|
|
93
|
-
storage.outbox.settle.mock.mockImplementationOnce(async () => {
|
|
94
|
-
|
|
95
|
-
|
|
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
|
+
)
|
|
96
143
|
|
|
97
144
|
await outbox.open()
|
|
98
145
|
await cycle()
|
|
@@ -110,7 +157,7 @@ it('should read nothing while it owns no slots', async () => {
|
|
|
110
157
|
assert.strictEqual(storage.outbox.pending.mock.callCount(), 0)
|
|
111
158
|
})
|
|
112
159
|
|
|
113
|
-
function resetCalls
|
|
160
|
+
function resetCalls(target = [assert, BATCH, page, cycle], seen = new Set()) {
|
|
114
161
|
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
115
162
|
|
|
116
163
|
seen.add(target)
|
|
@@ -119,3 +166,37 @@ function resetCalls (target = [assert, BATCH, page, cycle], seen = new Set()) {
|
|
|
119
166
|
if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
|
|
120
167
|
else resetCalls(value, seen)
|
|
121
168
|
}
|
|
169
|
+
|
|
170
|
+
it('should read as soon as a claim arrives, rather than on its next cycle', async () => {
|
|
171
|
+
atom.slots.mock.mockImplementation(() => null)
|
|
172
|
+
|
|
173
|
+
await outbox.open()
|
|
174
|
+
await settled()
|
|
175
|
+
|
|
176
|
+
assert.strictEqual(storage.outbox.pending.mock.callCount(), 0, 'nothing is owned yet')
|
|
177
|
+
|
|
178
|
+
atom.slots.mock.mockImplementation(() => [0])
|
|
179
|
+
|
|
180
|
+
for (const listener of listeners) listener({ i: 0, n: 1 })
|
|
181
|
+
|
|
182
|
+
await settled()
|
|
183
|
+
|
|
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
|
+
)
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('should read the lanes it inherits when the group resizes', async () => {
|
|
192
|
+
await outbox.open()
|
|
193
|
+
await settled()
|
|
194
|
+
|
|
195
|
+
const before = storage.outbox.pending.mock.callCount()
|
|
196
|
+
|
|
197
|
+
for (const listener of listeners) listener({ i: 0, n: 2 })
|
|
198
|
+
|
|
199
|
+
await settled()
|
|
200
|
+
|
|
201
|
+
assert.strictEqual(storage.outbox.pending.mock.callCount(), before + 1)
|
|
202
|
+
})
|
package/test/query.test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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 { Query } from '../
|
|
4
|
+
import { Query } from '../source/query.js'
|
|
5
5
|
import * as fixtures from './query.fixtures.js'
|
|
6
6
|
|
|
7
7
|
beforeEach(() => {
|
|
@@ -23,6 +23,13 @@ describe('criteria', () => {
|
|
|
23
23
|
assert.deepStrictEqual(query.criteria, fixtures.samples.simple.parsed.criteria)
|
|
24
24
|
})
|
|
25
25
|
|
|
26
|
+
it('should coerce every value of a list', () => {
|
|
27
|
+
const instance = new Query({ n: { type: 'integer' } })
|
|
28
|
+
const query = instance.parse({ criteria: 'n=in=(1,2,3)' })
|
|
29
|
+
|
|
30
|
+
assert.deepStrictEqual(query.criteria.right.value, [1, 2, 3])
|
|
31
|
+
})
|
|
32
|
+
|
|
26
33
|
it('should keep a parsed criteria', () => {
|
|
27
34
|
const instance = new Query(fixtures.samples.simple.properties)
|
|
28
35
|
|
|
@@ -47,10 +54,62 @@ describe('criteria', () => {
|
|
|
47
54
|
assert.deepStrictEqual(query.criteria, fixtures.samples.extended.parsed.criteria)
|
|
48
55
|
})
|
|
49
56
|
|
|
57
|
+
it('should refuse a value the property cannot hold', () => {
|
|
58
|
+
const strict = new Query({
|
|
59
|
+
volume: { type: 'number' },
|
|
60
|
+
count: { type: 'integer' },
|
|
61
|
+
booked: { type: 'boolean' }
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
const refused = [
|
|
65
|
+
['volume>abc', /takes a number/],
|
|
66
|
+
['volume==1.5kg', /takes a number/],
|
|
67
|
+
['count==1.5', /takes an integer/],
|
|
68
|
+
['count==12kg', /takes an integer/],
|
|
69
|
+
['booked==yes', /takes a boolean/],
|
|
70
|
+
['booked==TRUE', /takes a boolean/],
|
|
71
|
+
['volume=in=(1,two)', /'two' is not one/]
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
for (const [criteria, message] of refused)
|
|
75
|
+
assert.throws(
|
|
76
|
+
() => strict.parse({ criteria }),
|
|
77
|
+
(error) => message.test(error.message),
|
|
78
|
+
criteria
|
|
79
|
+
)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('should read a value the property can hold', () => {
|
|
83
|
+
const strict = new Query({
|
|
84
|
+
volume: { type: 'number' },
|
|
85
|
+
count: { type: 'integer' },
|
|
86
|
+
booked: { type: 'boolean' },
|
|
87
|
+
title: { type: 'string' }
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
const read = [
|
|
91
|
+
['volume>1.5', 1.5],
|
|
92
|
+
['volume>-1.5', -1.5],
|
|
93
|
+
['count==12', 12],
|
|
94
|
+
['booked==false', false],
|
|
95
|
+
['title==12kg', '12kg']
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
for (const [criteria, value] of read)
|
|
99
|
+
assert.deepStrictEqual(
|
|
100
|
+
strict.parse({ criteria }).criteria.right.value,
|
|
101
|
+
value,
|
|
102
|
+
criteria
|
|
103
|
+
)
|
|
104
|
+
})
|
|
105
|
+
|
|
50
106
|
it('should throw on unknown properties', () => {
|
|
51
107
|
const instance = new Query(fixtures.samples.simple.properties)
|
|
52
108
|
|
|
53
|
-
assert.throws(
|
|
109
|
+
assert.throws(
|
|
110
|
+
() => instance.parse({ criteria: 'lastname==Johnson' }),
|
|
111
|
+
(error) => /not defined/.test(error.message)
|
|
112
|
+
)
|
|
54
113
|
})
|
|
55
114
|
|
|
56
115
|
it('should parse id', () => {
|
|
@@ -84,13 +143,20 @@ describe('options', () => {
|
|
|
84
143
|
const sort = ['a', 'b:desc', 'c']
|
|
85
144
|
const query = instance.parse({ sort })
|
|
86
145
|
|
|
87
|
-
assert.deepStrictEqual(query.options.sort, [
|
|
146
|
+
assert.deepStrictEqual(query.options.sort, [
|
|
147
|
+
['a', 'asc'],
|
|
148
|
+
['b', 'desc'],
|
|
149
|
+
['c', 'asc']
|
|
150
|
+
])
|
|
88
151
|
})
|
|
89
152
|
|
|
90
153
|
it('should throw on unknown properties', () => {
|
|
91
154
|
const sort = ['d:asc']
|
|
92
155
|
|
|
93
|
-
assert.throws(
|
|
156
|
+
assert.throws(
|
|
157
|
+
() => instance.parse({ sort }),
|
|
158
|
+
(error) => /not defined/.test(error.message)
|
|
159
|
+
)
|
|
94
160
|
})
|
|
95
161
|
})
|
|
96
162
|
|
|
@@ -98,12 +164,15 @@ describe('options', () => {
|
|
|
98
164
|
it('should throw on unknown properties', () => {
|
|
99
165
|
const projection = ['a', 'b', 'c', 'd']
|
|
100
166
|
|
|
101
|
-
assert.throws(
|
|
167
|
+
assert.throws(
|
|
168
|
+
() => instance.parse({ projection }),
|
|
169
|
+
(error) => /not defined/.test(error.message)
|
|
170
|
+
)
|
|
102
171
|
})
|
|
103
172
|
})
|
|
104
173
|
})
|
|
105
174
|
|
|
106
|
-
function resetCalls
|
|
175
|
+
function resetCalls(target = [assert, fixtures], seen = new Set()) {
|
|
107
176
|
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
108
177
|
|
|
109
178
|
seen.add(target)
|
|
@@ -8,13 +8,13 @@ export const definition = /** @type {toa.norm.component.Receiver} */ {
|
|
|
8
8
|
adaptive: false
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export const local = /** @type {toa.core.Component} */ {
|
|
11
|
+
export const local = /** @type {import('@toa.io/core').Component} */ {
|
|
12
12
|
locator: { id: 'default.dummy' },
|
|
13
13
|
invoke: mock.fn()
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// noinspection JSCheckFunctionSignatures
|
|
17
|
-
export const bridge = /** @type {toa.core.bridges.Event} */ {
|
|
17
|
+
export const bridge = /** @type {import('@toa.io/core/types').bridges.Event} */ {
|
|
18
18
|
condition: mock.fn(async (payload) => !(payload.reject === true)),
|
|
19
19
|
request: mock.fn(async () => ({ input: generate() }))
|
|
20
20
|
}
|
package/test/receiver.test.js
CHANGED
|
@@ -6,19 +6,20 @@ import clone from 'clone-deep'
|
|
|
6
6
|
import { generate } from 'randomstring'
|
|
7
7
|
import { merge } from '@toa.io/generic'
|
|
8
8
|
|
|
9
|
-
import { Connector } from '../
|
|
9
|
+
import { Connector } from '../source/connector.js'
|
|
10
10
|
|
|
11
11
|
// the fixtures are not connectors, so a dependency is recorded rather than linked
|
|
12
12
|
const depends = mock.method(Connector.prototype, 'depends', () => undefined)
|
|
13
13
|
|
|
14
|
-
const dependencies = (instance) =>
|
|
15
|
-
.
|
|
16
|
-
|
|
14
|
+
const dependencies = (instance) =>
|
|
15
|
+
depends.mock.calls
|
|
16
|
+
.filter((call) => call.this === instance)
|
|
17
|
+
.map((call) => call.arguments[0])
|
|
17
18
|
|
|
18
|
-
import { Receiver } from '../
|
|
19
|
+
import { Receiver } from '../source/receiver.js'
|
|
19
20
|
import * as fixtures from './receiver.fixtures.js'
|
|
20
21
|
|
|
21
|
-
/** @type {toa.core.Receiver} */
|
|
22
|
+
/** @type {import('@toa.io/core/types').Receiver} */
|
|
22
23
|
let receiver
|
|
23
24
|
|
|
24
25
|
/** @type {toa.norm.component.Receiver} */
|
|
@@ -42,29 +43,38 @@ it('should apply', async () => {
|
|
|
42
43
|
|
|
43
44
|
await receiver.receive({ payload })
|
|
44
45
|
|
|
45
|
-
assert.ok(
|
|
46
|
+
assert.ok(
|
|
47
|
+
fixtures.local.invoke.mock.calls.some(
|
|
48
|
+
(call) =>
|
|
49
|
+
call.arguments.length === 2 &&
|
|
50
|
+
isDeepStrictEqual(call.arguments[0], definition.operation) &&
|
|
51
|
+
isDeepStrictEqual(call.arguments[1], { input: payload })
|
|
52
|
+
)
|
|
53
|
+
)
|
|
46
54
|
})
|
|
47
55
|
|
|
48
56
|
for (const [adaptive] of [[false], [true]])
|
|
49
|
-
|
|
50
|
-
|
|
57
|
+
it(`should pass UI extensions (adaptive: ${adaptive})`, async () => {
|
|
58
|
+
resetCalls()
|
|
51
59
|
|
|
52
|
-
|
|
53
|
-
|
|
60
|
+
definition.adaptive = adaptive
|
|
61
|
+
receiver = new Receiver(definition, fixtures.local, fixtures.bridge)
|
|
54
62
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
63
|
+
const payload = { foo: generate() }
|
|
64
|
+
const extension = { [generate()]: generate() }
|
|
65
|
+
const message = { payload, ...extension }
|
|
58
66
|
|
|
59
|
-
|
|
67
|
+
await receiver.receive(message)
|
|
60
68
|
|
|
61
|
-
|
|
62
|
-
|
|
69
|
+
const request = adaptive
|
|
70
|
+
? await fixtures.bridge.request.mock.calls[0].result
|
|
71
|
+
: { input: payload }
|
|
72
|
+
const expected = merge(clone(request), extension)
|
|
63
73
|
|
|
64
|
-
|
|
74
|
+
const argument = fixtures.local.invoke.mock.calls[0].arguments[1]
|
|
65
75
|
|
|
66
|
-
|
|
67
|
-
})
|
|
76
|
+
assert.deepStrictEqual(argument, expected)
|
|
77
|
+
})
|
|
68
78
|
|
|
69
79
|
describe('conditioned', () => {
|
|
70
80
|
beforeEach(() => {
|
|
@@ -76,8 +86,20 @@ describe('conditioned', () => {
|
|
|
76
86
|
const payload = { foo: 'bar' }
|
|
77
87
|
await receiver.receive({ payload })
|
|
78
88
|
|
|
79
|
-
assert.ok(
|
|
80
|
-
|
|
89
|
+
assert.ok(
|
|
90
|
+
fixtures.bridge.condition.mock.calls.some(
|
|
91
|
+
(call) =>
|
|
92
|
+
call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], payload)
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
assert.ok(
|
|
96
|
+
fixtures.local.invoke.mock.calls.some(
|
|
97
|
+
(call) =>
|
|
98
|
+
call.arguments.length === 2 &&
|
|
99
|
+
isDeepStrictEqual(call.arguments[0], definition.operation) &&
|
|
100
|
+
isDeepStrictEqual(call.arguments[1], { input: payload })
|
|
101
|
+
)
|
|
102
|
+
)
|
|
81
103
|
})
|
|
82
104
|
|
|
83
105
|
it('should not apply if condition is false', async () => {
|
|
@@ -100,14 +122,18 @@ describe('adaptive', () => {
|
|
|
100
122
|
|
|
101
123
|
const request = await fixtures.bridge.request.mock.calls[0].result
|
|
102
124
|
|
|
103
|
-
assert.ok(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
125
|
+
assert.ok(
|
|
126
|
+
fixtures.local.invoke.mock.calls.some(
|
|
127
|
+
(call) =>
|
|
128
|
+
call.arguments.length === 2 &&
|
|
129
|
+
isDeepStrictEqual(call.arguments[0], definition.operation) &&
|
|
130
|
+
isDeepStrictEqual(call.arguments[1], request)
|
|
131
|
+
)
|
|
132
|
+
)
|
|
107
133
|
})
|
|
108
134
|
})
|
|
109
135
|
|
|
110
|
-
function resetCalls
|
|
136
|
+
function resetCalls(target = [assert, clone, fixtures], seen = new Set()) {
|
|
111
137
|
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
112
138
|
|
|
113
139
|
seen.add(target)
|
package/test/reflection.test.js
CHANGED
|
@@ -2,18 +2,18 @@ import { it, beforeEach } from 'node:test'
|
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
3
|
|
|
4
4
|
import { generate } from 'randomstring'
|
|
5
|
-
import { Reflection, Connector } from '../
|
|
5
|
+
import { Reflection, Connector } from '../source/index.js'
|
|
6
6
|
|
|
7
7
|
it('should export', () => {
|
|
8
8
|
assert.notStrictEqual(Reflection, undefined)
|
|
9
9
|
})
|
|
10
10
|
|
|
11
|
-
/** @type {toa.core.Reflection<string>} */
|
|
11
|
+
/** @type {import('@toa.io/core').Reflection<string>} */
|
|
12
12
|
let reflection
|
|
13
13
|
|
|
14
14
|
const value = generate()
|
|
15
15
|
|
|
16
|
-
/** @type {toa.core.
|
|
16
|
+
/** @type {import('@toa.io/core').ReflectionSource<string>} */
|
|
17
17
|
const source = async () => value
|
|
18
18
|
|
|
19
19
|
beforeEach(() => {
|
package/test/state.fixtures.js
CHANGED
|
@@ -5,7 +5,7 @@ import { generate } from 'randomstring'
|
|
|
5
5
|
export const storage = {
|
|
6
6
|
name: 'dummy',
|
|
7
7
|
get: mock.fn(() => ({ id: generate() })),
|
|
8
|
-
find: mock.fn(() =>
|
|
8
|
+
find: mock.fn(() => [{ id: generate() }]),
|
|
9
9
|
add: mock.fn(() => true),
|
|
10
10
|
set: mock.fn(() => true),
|
|
11
11
|
store: mock.fn(() => true),
|
|
@@ -27,7 +27,8 @@ export const entity = {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export const initial = {
|
|
30
|
-
initial: true,
|
|
30
|
+
initial: true,
|
|
31
|
+
...entity
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export const unchanged = {
|
|
@@ -37,6 +38,12 @@ export const unchanged = {
|
|
|
37
38
|
|
|
38
39
|
// a legacy outbox: no storage capability, so `publish` emits inline
|
|
39
40
|
export const outbox = {
|
|
40
|
-
row: mock.fn((event) => ({
|
|
41
|
+
row: mock.fn((event) => ({
|
|
42
|
+
id: generate(),
|
|
43
|
+
lane: 0,
|
|
44
|
+
published: false,
|
|
45
|
+
pending: 0,
|
|
46
|
+
event
|
|
47
|
+
})),
|
|
41
48
|
publish: mock.fn()
|
|
42
49
|
}
|