@toa.io/core 1.0.0-alpha.272 → 1.0.0-alpha.277
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 +16 -0
- package/package.json +8 -8
- package/src/assignment.js +2 -6
- package/src/call.js +15 -9
- package/src/cascade.js +2 -6
- package/src/component.js +4 -8
- package/src/composition.js +3 -7
- package/src/connector.js +2 -6
- package/src/context.js +2 -6
- package/src/contract/contract.js +2 -6
- package/src/contract/index.js +2 -7
- package/src/contract/reply.js +4 -8
- package/src/contract/request.js +4 -8
- package/src/contract/schemas/index.js +9 -6
- package/src/discovery.js +3 -7
- package/src/effect.js +2 -6
- package/src/emission.js +2 -6
- package/src/entities/changeset.js +2 -6
- package/src/entities/entity.js +3 -7
- package/src/entities/factory.js +5 -9
- package/src/entities/index.js +1 -5
- package/src/entities/newid.js +2 -4
- package/src/entities/set.js +2 -6
- package/src/event.js +3 -7
- package/src/exceptions.js +37 -30
- package/src/exposition.js +2 -6
- package/src/guard.js +1 -5
- package/src/index.js +28 -55
- package/src/locator.js +2 -6
- package/src/observation.js +2 -6
- package/src/operation.js +4 -8
- package/src/outbox/index.js +1 -6
- package/src/outbox/outbox.js +5 -10
- package/src/query/criteria.js +3 -7
- package/src/query/options.js +2 -6
- package/src/query.js +5 -6
- package/src/receiver.js +4 -8
- package/src/reflection.js +2 -6
- package/src/remote.js +3 -7
- package/src/state.js +2 -6
- package/src/transition.js +4 -8
- package/src/transmission.js +3 -7
- package/src/unmanaged.js +2 -6
- package/test/call.fixtures.js +8 -12
- package/test/call.test.js +21 -9
- package/test/component.fixtures.js +5 -8
- package/test/component.test.js +22 -11
- package/test/connector.fixtures.js +5 -11
- package/test/connector.test.js +42 -41
- package/test/context.fixtures.js +8 -12
- package/test/context.test.js +18 -7
- package/test/contract/conditions.test.js +8 -6
- package/test/contract/contract.fixtures.js +12 -16
- package/test/contract/request.test.js +51 -40
- package/test/discovery.test.js +25 -17
- package/test/emission.fixtures.js +5 -8
- package/test/emission.test.js +29 -12
- package/test/entities/entity.fixtures.js +7 -11
- package/test/entities/entity.test.js +30 -19
- package/test/entities/factory.fixtures.js +22 -10
- package/test/entities/factory.test.js +29 -17
- package/test/entities/set.fixtures.js +6 -8
- package/test/entities/set.test.js +6 -5
- package/test/event.fixtures.js +9 -14
- package/test/event.test.js +57 -31
- package/test/locator.test.js +25 -24
- package/test/outbox.test.js +44 -37
- package/test/query.fixtures.js +1 -5
- package/test/query.test.js +28 -17
- package/test/receiver.fixtures.js +8 -12
- package/test/receiver.test.js +45 -22
- package/test/reflection.test.js +7 -6
- package/test/state.fixtures.js +24 -32
- package/test/state.test.js +35 -30
- package/test/transmission.fixtures.js +4 -6
- package/test/transmission.test.js +33 -15
- package/types/atomicity.d.ts +1 -1
- package/types/bindings.d.ts +1 -1
- package/types/bridges.ts +3 -3
- package/types/component.d.ts +4 -4
- package/types/context.d.ts +4 -4
- package/types/entity.d.ts +2 -2
- package/types/event.d.ts +1 -1
- package/types/extensions.d.ts +8 -7
- package/types/index.ts +16 -16
- package/types/operations.d.ts +1 -1
- package/types/outbox.d.ts +2 -2
- package/types/receiver.d.ts +2 -2
- package/types/reflection.d.ts +1 -1
- package/types/remote.d.ts +1 -1
- package/types/request.d.ts +1 -1
- package/types/state.d.ts +2 -2
- package/types/storages.d.ts +3 -3
package/test/connector.test.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import { describe, it, beforeEach } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
import { timeout } from '@toa.io/generic'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
import * as fixtures from './connector.fixtures.js'
|
|
6
7
|
|
|
7
8
|
let sequence
|
|
8
9
|
|
|
@@ -19,14 +20,14 @@ describe('callbacks', () => {
|
|
|
19
20
|
|
|
20
21
|
it('should call connection', async () => {
|
|
21
22
|
await a.connect()
|
|
22
|
-
|
|
23
|
+
assert.deepStrictEqual(sequence, ['+a'])
|
|
23
24
|
})
|
|
24
25
|
|
|
25
26
|
it('should call disconnection', async () => {
|
|
26
27
|
await a.connect()
|
|
27
28
|
await a.disconnect()
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
assert.ok(sequence.indexOf('+a') < sequence.indexOf('-a'))
|
|
30
31
|
})
|
|
31
32
|
|
|
32
33
|
it('should reconnect', async () => {
|
|
@@ -34,7 +35,7 @@ describe('callbacks', () => {
|
|
|
34
35
|
await a.reconnect()
|
|
35
36
|
await a.reconnect()
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
assert.deepStrictEqual(sequence, ['+a', '-a', '*a', '+a', '-a', '*a', '+a'])
|
|
38
39
|
})
|
|
39
40
|
})
|
|
40
41
|
|
|
@@ -57,9 +58,9 @@ describe('dependencies', () => {
|
|
|
57
58
|
|
|
58
59
|
await a.connect()
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
assert.ok(sequence.indexOf('+c') < sequence.indexOf('+b'))
|
|
62
|
+
assert.ok(sequence.indexOf('+b') < sequence.indexOf('+a'))
|
|
63
|
+
assert.ok(sequence.indexOf('+d') < sequence.indexOf('+a'))
|
|
63
64
|
})
|
|
64
65
|
|
|
65
66
|
it('should wait array of connectors', async () => {
|
|
@@ -69,10 +70,10 @@ describe('dependencies', () => {
|
|
|
69
70
|
|
|
70
71
|
await a.connect()
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
assert.ok(sequence.indexOf('+c') < sequence.indexOf('+b'))
|
|
74
|
+
assert.ok(sequence.indexOf('+c') < sequence.indexOf('+d'))
|
|
75
|
+
assert.ok(sequence.indexOf('+b') < sequence.indexOf('+a'))
|
|
76
|
+
assert.ok(sequence.indexOf('+d') < sequence.indexOf('+a'))
|
|
76
77
|
})
|
|
77
78
|
|
|
78
79
|
it('should wait array(1) of connectors', async () => {
|
|
@@ -81,12 +82,12 @@ describe('dependencies', () => {
|
|
|
81
82
|
|
|
82
83
|
await a.connect()
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
assert.ok(sequence.indexOf('+c') < sequence.indexOf('+b'))
|
|
86
|
+
assert.ok(sequence.indexOf('+b') < sequence.indexOf('+a'))
|
|
86
87
|
})
|
|
87
88
|
|
|
88
89
|
it('should throw on empty array', async () => {
|
|
89
|
-
|
|
90
|
+
assert.throws(() => a.depends([]), (error) => /must not be empty/.test(error.message))
|
|
90
91
|
})
|
|
91
92
|
|
|
92
93
|
it('should await 2-way dependencies', async () => {
|
|
@@ -95,12 +96,12 @@ describe('dependencies', () => {
|
|
|
95
96
|
|
|
96
97
|
await a.connect()
|
|
97
98
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
assert.ok(sequence.indexOf('+b') < sequence.indexOf('+a'))
|
|
100
|
+
assert.ok(sequence.indexOf('+c') < sequence.indexOf('+a'))
|
|
101
|
+
assert.ok(sequence.indexOf('+d') < sequence.indexOf('+a'))
|
|
101
102
|
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
assert.ok(sequence.indexOf('+b') < sequence.indexOf('+d'))
|
|
104
|
+
assert.ok(sequence.indexOf('+c') < sequence.indexOf('+d'))
|
|
104
105
|
})
|
|
105
106
|
|
|
106
107
|
it('should disconnect before dependencies', async () => {
|
|
@@ -110,9 +111,9 @@ describe('dependencies', () => {
|
|
|
110
111
|
await a.connect()
|
|
111
112
|
await a.disconnect()
|
|
112
113
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
assert.ok(sequence.indexOf('-a') < sequence.indexOf('-b'))
|
|
115
|
+
assert.ok(sequence.indexOf('-b') < sequence.indexOf('-c'))
|
|
116
|
+
assert.ok(sequence.indexOf('-b') < sequence.indexOf('-d'))
|
|
116
117
|
})
|
|
117
118
|
|
|
118
119
|
it('should call disconnected', async () => {
|
|
@@ -121,10 +122,10 @@ describe('dependencies', () => {
|
|
|
121
122
|
|
|
122
123
|
await a.disconnect()
|
|
123
124
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
assert.ok(sequence.indexOf('*c') < sequence.indexOf('*b'))
|
|
126
|
+
assert.ok(sequence.indexOf('*b') < sequence.indexOf('*a'))
|
|
127
|
+
assert.ok(sequence.indexOf('*d') < sequence.indexOf('*b'))
|
|
128
|
+
assert.strictEqual(sequence.indexOf('*a'), sequence.length - 1)
|
|
128
129
|
})
|
|
129
130
|
|
|
130
131
|
it('should disconnect if no parents left', async () => {
|
|
@@ -134,19 +135,19 @@ describe('dependencies', () => {
|
|
|
134
135
|
await a.connect()
|
|
135
136
|
await b.connect()
|
|
136
137
|
|
|
137
|
-
|
|
138
|
+
assert.deepStrictEqual(sequence, ['+c', '+a', '+b'])
|
|
138
139
|
|
|
139
140
|
await a.disconnect()
|
|
140
141
|
|
|
141
|
-
|
|
142
|
+
assert.deepStrictEqual(sequence, ['+c', '+a', '+b', '-a', '*a'])
|
|
142
143
|
|
|
143
144
|
await b.disconnect()
|
|
144
145
|
|
|
145
|
-
|
|
146
|
+
assert.deepStrictEqual(sequence, ['+c', '+a', '+b', '-a', '*a', '-b', '-c', '*c', '*b'])
|
|
146
147
|
})
|
|
147
148
|
|
|
148
149
|
it('should throw if depends not on Connector', async () => {
|
|
149
|
-
|
|
150
|
+
assert.throws(() => a.depends({}))
|
|
150
151
|
})
|
|
151
152
|
|
|
152
153
|
it('should disconnect while still connecting', async () => {
|
|
@@ -159,11 +160,11 @@ describe('dependencies', () => {
|
|
|
159
160
|
while (b.connected !== true) await timeout(1)
|
|
160
161
|
|
|
161
162
|
// `a` never connects, and disconnecting must not wait for it to
|
|
162
|
-
|
|
163
|
+
assert.deepStrictEqual(a.connected, false)
|
|
163
164
|
|
|
164
165
|
await a.disconnect()
|
|
165
166
|
|
|
166
|
-
|
|
167
|
+
assert.deepStrictEqual(sequence, ['+b', '-b', '*b', '*a'])
|
|
167
168
|
})
|
|
168
169
|
|
|
169
170
|
describe('errors', () => {
|
|
@@ -176,21 +177,21 @@ describe('dependencies', () => {
|
|
|
176
177
|
it('should disconnect on fail', async () => {
|
|
177
178
|
f.depends(b).depends(c)
|
|
178
179
|
|
|
179
|
-
await
|
|
180
|
-
|
|
180
|
+
await assert.rejects(f.connect(), (error) => /FailingConnector/.test(error.message))
|
|
181
|
+
assert.deepStrictEqual(sequence, ['+c', '+b', '-b', '-c', '*c', '*b'])
|
|
181
182
|
})
|
|
182
183
|
|
|
183
184
|
it('should interrupt connection chain', async () => {
|
|
184
185
|
a.depends(f).depends(c)
|
|
185
186
|
f.depends(d)
|
|
186
187
|
|
|
187
|
-
await
|
|
188
|
+
await assert.rejects(a.connect(), (error) => /FailingConnector/.test(error.message))
|
|
188
189
|
|
|
189
|
-
|
|
190
|
-
|
|
190
|
+
assert.ok(sequence.indexOf('+c') < sequence.indexOf('-c'))
|
|
191
|
+
assert.ok(sequence.indexOf('+d') < sequence.indexOf('-d'))
|
|
191
192
|
|
|
192
|
-
|
|
193
|
-
|
|
193
|
+
assert.strictEqual(sequence.indexOf('+a'), -1)
|
|
194
|
+
assert.strictEqual(sequence.indexOf('-a'), -1)
|
|
194
195
|
})
|
|
195
196
|
})
|
|
196
197
|
})
|
package/test/context.fixtures.js
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import { mock } from 'node:test'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import { Connector } from '../src/connector.js'
|
|
4
4
|
|
|
5
|
-
const local = {
|
|
6
|
-
link:
|
|
5
|
+
export const local = {
|
|
6
|
+
link: mock.fn()
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
const discover =
|
|
10
|
-
invoke:
|
|
11
|
-
link:
|
|
9
|
+
export const discover = mock.fn(() => ({
|
|
10
|
+
invoke: mock.fn(),
|
|
11
|
+
link: mock.fn()
|
|
12
12
|
}))
|
|
13
13
|
|
|
14
|
-
const aspects = [new Connector(), new Connector()]
|
|
15
|
-
|
|
16
|
-
exports.local = local
|
|
17
|
-
exports.discover = discover
|
|
18
|
-
exports.aspects = aspects
|
|
14
|
+
export const aspects = [new Connector(), new Connector()]
|
package/test/context.test.js
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
import { describe, it, beforeEach, mock } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
import * as fixtures from './context.fixtures.js'
|
|
5
|
+
import { Context } from '../src/context.js'
|
|
5
6
|
|
|
6
7
|
/** @type {toa.core.Context} */
|
|
7
8
|
let context
|
|
8
9
|
|
|
9
10
|
beforeEach(() => {
|
|
10
|
-
|
|
11
|
+
resetCalls()
|
|
11
12
|
|
|
12
13
|
context = new Context(fixtures.local, fixtures.discover, fixtures.aspects)
|
|
13
14
|
})
|
|
14
15
|
|
|
15
16
|
it('should expose aspects', () => {
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
assert.notStrictEqual(context.aspects, undefined)
|
|
18
|
+
assert.deepStrictEqual(context.aspects, fixtures.aspects)
|
|
18
19
|
})
|
|
19
20
|
|
|
20
21
|
describe('call', () => {
|
|
@@ -24,6 +25,16 @@ describe('call', () => {
|
|
|
24
25
|
await context.call('a', 'b', 'c', request)
|
|
25
26
|
await context.call('a', 'b', 'c', request)
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
assert.strictEqual(fixtures.discover.mock.callCount(), 1)
|
|
28
29
|
})
|
|
29
30
|
})
|
|
31
|
+
|
|
32
|
+
function resetCalls (target = [assert, fixtures], seen = new Set()) {
|
|
33
|
+
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
34
|
+
|
|
35
|
+
seen.add(target)
|
|
36
|
+
|
|
37
|
+
for (const value of Object.values(target))
|
|
38
|
+
if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
|
|
39
|
+
else resetCalls(value, seen)
|
|
40
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import { it, beforeEach } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { isDeepStrictEqual } from 'node:util'
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
import { generate } from 'randomstring'
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
import { Contract } from '../../src/contract/contract.js'
|
|
8
|
+
import * as fixtures from './contract.fixtures.js'
|
|
7
9
|
|
|
8
10
|
let contract
|
|
9
11
|
|
|
@@ -16,11 +18,11 @@ it('should fit value', () => {
|
|
|
16
18
|
|
|
17
19
|
contract.fit(value)
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
assert.ok(fixtures.schema.fit.mock.calls.some((call) => call.arguments.length === 1 && isDeepStrictEqual(call.arguments[0], value)))
|
|
20
22
|
})
|
|
21
23
|
|
|
22
24
|
it('should throw on invalid value', () => {
|
|
23
25
|
const value = { invalid: true }
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
assert.throws(() => contract.fit(value))
|
|
26
28
|
})
|
|
@@ -1,33 +1,29 @@
|
|
|
1
|
-
|
|
1
|
+
import { mock } from 'node:test'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import { generate } from 'randomstring'
|
|
4
|
+
import { readFileSync } from 'node:fs'
|
|
5
|
+
import { load as parseYAML } from 'js-yaml'
|
|
6
|
+
import { resolve } from 'path'
|
|
6
7
|
|
|
7
8
|
// noinspection JSCheckFunctionSignatures
|
|
8
|
-
const schema = {
|
|
9
|
-
fit:
|
|
9
|
+
export const schema = {
|
|
10
|
+
fit: mock.fn((input) => (input.invalid ? { message: generate() } : null))
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
const query = {
|
|
13
|
-
parse:
|
|
13
|
+
export const query = {
|
|
14
|
+
parse: mock.fn(() => ({ [generate()]: generate() }))
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
const declaration = {}
|
|
17
|
+
export const declaration = {}
|
|
17
18
|
|
|
18
|
-
const schemas = {
|
|
19
|
+
export const schemas = {
|
|
19
20
|
request: {
|
|
20
21
|
type: 'object',
|
|
21
22
|
properties: {
|
|
22
23
|
input: { type: 'null' },
|
|
23
|
-
query:
|
|
24
|
+
query: parseYAML(readFileSync(resolve(import.meta.dirname, '../../src/contract/schemas/query.yaml'), 'utf8')),
|
|
24
25
|
authentic: { type: 'boolean' }
|
|
25
26
|
},
|
|
26
27
|
additionalProperties: true
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
|
-
|
|
30
|
-
exports.schema = schema
|
|
31
|
-
exports.query = query
|
|
32
|
-
exports.declaration = declaration
|
|
33
|
-
exports.schemas = schemas
|
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
import * as schemas from '@toa.io/schemas'
|
|
2
|
+
import { describe, it, beforeEach, mock } from 'node:test'
|
|
3
|
+
import assert from 'node:assert/strict'
|
|
4
|
+
import { isDeepStrictEqual } from 'node:util'
|
|
2
5
|
|
|
3
|
-
|
|
4
|
-
|
|
6
|
+
import clone from 'clone-deep'
|
|
7
|
+
import { generate } from 'randomstring'
|
|
5
8
|
|
|
6
|
-
|
|
9
|
+
import { Request } from '../../src/contract/request.js'
|
|
10
|
+
import { Contract } from '../../src/contract/contract.js'
|
|
11
|
+
import * as fixtures from './contract.fixtures.js'
|
|
7
12
|
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const fixtures = require('./contract.fixtures')
|
|
13
|
+
// the base is real; what it was constructed with and told to fit is observable
|
|
14
|
+
const fit = mock.method(Contract.prototype, 'fit', () => undefined)
|
|
11
15
|
|
|
12
16
|
let contract
|
|
13
17
|
|
|
14
18
|
beforeEach(() => {
|
|
15
|
-
|
|
19
|
+
resetCalls()
|
|
20
|
+
fit.mock.resetCalls()
|
|
16
21
|
|
|
17
22
|
contract = new Request(fixtures.schema, {})
|
|
18
23
|
})
|
|
@@ -20,8 +25,8 @@ beforeEach(() => {
|
|
|
20
25
|
const dummy = { schema: { properties: {} } }
|
|
21
26
|
|
|
22
27
|
it('should extend Conditions', () => {
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
assert.ok(contract instanceof Contract)
|
|
29
|
+
assert.strictEqual(contract.schema, fixtures.schema)
|
|
25
30
|
})
|
|
26
31
|
|
|
27
32
|
it('should fit request', () => {
|
|
@@ -29,7 +34,8 @@ it('should fit request', () => {
|
|
|
29
34
|
|
|
30
35
|
contract.fit(request)
|
|
31
36
|
|
|
32
|
-
|
|
37
|
+
assert.ok(fit.mock.calls.some((call) =>
|
|
38
|
+
call.this === contract && isDeepStrictEqual(call.arguments[0], request)))
|
|
33
39
|
})
|
|
34
40
|
|
|
35
41
|
describe('schema', () => {
|
|
@@ -40,79 +46,74 @@ describe('schema', () => {
|
|
|
40
46
|
})
|
|
41
47
|
|
|
42
48
|
it('should provide schema', () => {
|
|
43
|
-
|
|
49
|
+
assert.notStrictEqual(Request.schema({}, dummy), undefined)
|
|
44
50
|
})
|
|
45
51
|
|
|
46
52
|
it('should add required input if defined', () => {
|
|
47
53
|
const input = { type: 'number' }
|
|
48
54
|
|
|
49
|
-
|
|
55
|
+
assert.deepStrictEqual(Request.schema({ input }, dummy).properties.input, input)
|
|
50
56
|
})
|
|
51
57
|
|
|
52
58
|
it('should set input as null if undefined', async () => {
|
|
53
|
-
|
|
59
|
+
assert.deepStrictEqual(Request.schema({}, dummy).properties.input, { type: 'null' })
|
|
54
60
|
})
|
|
55
61
|
|
|
56
62
|
it('should contain query if declaration.query is not defined', () => {
|
|
57
|
-
|
|
63
|
+
assert.notStrictEqual(Request.schema({}, dummy).properties.query, undefined)
|
|
58
64
|
})
|
|
59
65
|
|
|
60
66
|
it('should not contain query if declaration.query is false', () => {
|
|
61
67
|
schema.properties.query = { type: 'null' }
|
|
62
|
-
|
|
68
|
+
assert.partialDeepStrictEqual(Request.schema({ query: false }, dummy), schema)
|
|
63
69
|
})
|
|
64
70
|
|
|
65
71
|
it('should require query if declaration.query is true', () => {
|
|
66
72
|
schema.required = ['query']
|
|
67
|
-
|
|
73
|
+
assert.ok(['query'].every((item) => Request.schema({ query: true }, dummy).required.some((candidate) => isDeepStrictEqual(candidate, item))))
|
|
68
74
|
})
|
|
69
75
|
|
|
70
76
|
it('should forbid projection for non observations', () => {
|
|
71
|
-
|
|
72
|
-
.toBe(undefined)
|
|
77
|
+
assert.strictEqual(Request.schema({ type: 'transition' }, dummy).properties.query.properties.projection, undefined)
|
|
73
78
|
|
|
74
|
-
|
|
75
|
-
.toBe(undefined)
|
|
79
|
+
assert.strictEqual(Request.schema({ type: 'assignment' }, dummy).properties.query.properties.projection, undefined)
|
|
76
80
|
|
|
77
|
-
|
|
78
|
-
.toBeDefined()
|
|
81
|
+
assert.notStrictEqual(Request.schema({ type: 'observation' }, dummy).properties.query.properties.projection, undefined)
|
|
79
82
|
})
|
|
80
83
|
|
|
81
84
|
it('should forbid version for observations', () => {
|
|
82
|
-
|
|
83
|
-
.toBeDefined()
|
|
85
|
+
assert.notStrictEqual(Request.schema({ type: 'transition' }, dummy).properties.query.properties.version, undefined)
|
|
84
86
|
|
|
85
|
-
|
|
86
|
-
.toBe(undefined)
|
|
87
|
+
assert.strictEqual(Request.schema({ type: 'observation' }, dummy).properties.query.properties.version, undefined)
|
|
87
88
|
})
|
|
88
89
|
|
|
89
90
|
it('should allow omit, limit only for set observations', () => {
|
|
90
91
|
const schema = Request.schema({ type: 'transition' }, dummy)
|
|
91
92
|
const transition = schema.properties.query.properties
|
|
92
93
|
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
assert.strictEqual(transition.omit, undefined)
|
|
95
|
+
assert.strictEqual(transition.limit, undefined)
|
|
95
96
|
|
|
96
97
|
const object = Request.schema({
|
|
97
98
|
type: 'observation',
|
|
98
99
|
scope: 'object'
|
|
99
100
|
}, dummy).properties.query.properties
|
|
100
101
|
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
assert.strictEqual(object.omit, undefined)
|
|
103
|
+
assert.strictEqual(object.limit, undefined)
|
|
103
104
|
|
|
104
105
|
const objects = Request.schema({
|
|
105
106
|
type: 'observation',
|
|
106
107
|
scope: 'objects'
|
|
107
108
|
}, dummy).properties.query.properties
|
|
108
109
|
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
assert.notStrictEqual(objects.omit, undefined)
|
|
111
|
+
assert.notStrictEqual(objects.limit, undefined)
|
|
111
112
|
})
|
|
112
113
|
})
|
|
113
114
|
|
|
114
115
|
describe('source', () => {
|
|
115
|
-
|
|
116
|
+
|
|
116
117
|
|
|
117
118
|
const compile = (definition, entity) =>
|
|
118
119
|
schemas.schema(Request.schema(definition, entity), { removeAdditional: true })
|
|
@@ -120,8 +121,8 @@ describe('source', () => {
|
|
|
120
121
|
it('should declare source', () => {
|
|
121
122
|
const schema = Request.schema({}, dummy)
|
|
122
123
|
|
|
123
|
-
|
|
124
|
-
|
|
124
|
+
assert.notStrictEqual(schema.properties.source, undefined)
|
|
125
|
+
assert.deepStrictEqual(schema.properties.source.additionalProperties, false)
|
|
125
126
|
})
|
|
126
127
|
|
|
127
128
|
it('should pass known source variants', () => {
|
|
@@ -134,8 +135,8 @@ describe('source', () => {
|
|
|
134
135
|
]) {
|
|
135
136
|
const request = { input: null, query: null, source }
|
|
136
137
|
|
|
137
|
-
|
|
138
|
-
|
|
138
|
+
assert.deepStrictEqual(schema.fit(request), null)
|
|
139
|
+
assert.deepStrictEqual(request.source, source)
|
|
139
140
|
}
|
|
140
141
|
})
|
|
141
142
|
|
|
@@ -145,7 +146,17 @@ describe('source', () => {
|
|
|
145
146
|
const schema = compile({}, undefined)
|
|
146
147
|
const request = { input: null, query: null, source: { service: 'exposition', evil: 'x' } }
|
|
147
148
|
|
|
148
|
-
|
|
149
|
-
|
|
149
|
+
assert.deepStrictEqual(schema.fit(request), null)
|
|
150
|
+
assert.deepStrictEqual(request.source, { service: 'exposition' })
|
|
150
151
|
})
|
|
151
152
|
})
|
|
153
|
+
|
|
154
|
+
function resetCalls (target = [assert, clone, fixtures, dummy], seen = new Set()) {
|
|
155
|
+
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
156
|
+
|
|
157
|
+
seen.add(target)
|
|
158
|
+
|
|
159
|
+
for (const value of Object.values(target))
|
|
160
|
+
if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
|
|
161
|
+
else resetCalls(value, seen)
|
|
162
|
+
}
|
package/test/discovery.test.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
import { it, beforeEach, afterEach, mock } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { isDeepStrictEqual } from 'node:util'
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
import { console } from 'openspan'
|
|
6
|
+
import { Connector } from '../src/connector.js'
|
|
7
|
+
import { Discovery } from '../src/discovery.js'
|
|
6
8
|
|
|
7
9
|
class Lookup extends Connector {
|
|
8
|
-
invoke =
|
|
10
|
+
invoke = mock.fn(async () => ({ operations: {} }))
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
/** @type {Lookup} */
|
|
@@ -14,15 +16,15 @@ let lookup
|
|
|
14
16
|
/** @type {Discovery} */
|
|
15
17
|
let discovery
|
|
16
18
|
|
|
17
|
-
/** @type {
|
|
19
|
+
/** @type {import('node:test').Mock<any>} */
|
|
18
20
|
let warn
|
|
19
21
|
|
|
20
22
|
const locator = { id: 'dummies.one' }
|
|
21
23
|
|
|
22
24
|
beforeEach(async () => {
|
|
23
|
-
|
|
25
|
+
mock.timers.enable()
|
|
24
26
|
|
|
25
|
-
warn =
|
|
27
|
+
warn = mock.method(console, 'warn', () => undefined)
|
|
26
28
|
lookup = new Lookup()
|
|
27
29
|
discovery = new Discovery(async () => lookup)
|
|
28
30
|
|
|
@@ -30,27 +32,33 @@ beforeEach(async () => {
|
|
|
30
32
|
})
|
|
31
33
|
|
|
32
34
|
afterEach(() => {
|
|
33
|
-
warn.
|
|
34
|
-
|
|
35
|
+
warn.mock.restore()
|
|
36
|
+
mock.timers.reset()
|
|
35
37
|
})
|
|
36
38
|
|
|
37
39
|
it('should not warn if a lookup is answered', async () => {
|
|
38
40
|
await discovery.lookup(locator)
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
mock.timers.tick(60_000)
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
assert.strictEqual(warn.mock.callCount(), 0)
|
|
43
45
|
})
|
|
44
46
|
|
|
45
47
|
it('should keep warning while a lookup is unanswered', async () => {
|
|
46
|
-
lookup.invoke.mockImplementation(() => new Promise(() => undefined))
|
|
48
|
+
lookup.invoke.mock.mockImplementation(() => new Promise(() => undefined))
|
|
47
49
|
|
|
48
50
|
void discovery.lookup(locator)
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
// the interval is set after the lookup is resolved, so it has to exist
|
|
53
|
+
// before time is advanced
|
|
54
|
+
await new Promise((resolve) => process.nextTick(resolve))
|
|
51
55
|
|
|
52
|
-
|
|
56
|
+
// node:test moves the clock before running the callbacks it releases, so the
|
|
57
|
+
// elapsed time each warning reports is only right when time advances by steps
|
|
58
|
+
mock.timers.tick(5_000)
|
|
59
|
+
mock.timers.tick(5_000)
|
|
53
60
|
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
assert.strictEqual(warn.mock.callCount(), 2)
|
|
62
|
+
|
|
63
|
+
assert.ok(((call) => call.arguments.length === 2 && isDeepStrictEqual(call.arguments[0], 'Waiting for lookup response') && isDeepStrictEqual(call.arguments[1], { component: locator.id, waiting: 10 }))(warn.mock.calls.at(-1) ?? { arguments: [] }))
|
|
56
64
|
})
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
import { mock } from 'node:test'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import { generate } from 'randomstring'
|
|
4
4
|
|
|
5
5
|
// noinspection JSCheckFunctionSignatures
|
|
6
|
-
const events = [0, 1, 2].map((index) => ({
|
|
7
|
-
emit:
|
|
6
|
+
export const events = [0, 1, 2].map((index) => ({
|
|
7
|
+
emit: mock.fn(async (state) => ({ ...state, event: index }))
|
|
8
8
|
}))
|
|
9
9
|
|
|
10
|
-
const event = {
|
|
10
|
+
export const event = {
|
|
11
11
|
origin: { [generate()]: generate() },
|
|
12
12
|
state: { [generate()]: generate() }
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
exports.events = events
|
|
16
|
-
exports.event = event
|