@toa.io/core 1.0.0-alpha.292 → 1.0.0-alpha.293
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 +10 -4
- package/CHANGELOG.md +0 -43
- package/source/assignment.ts +0 -27
- package/source/call.ts +0 -63
- package/source/cascade.ts +0 -32
- package/source/component.ts +0 -83
- package/source/composition.ts +0 -27
- package/source/connector.ts +0 -217
- package/source/context.ts +0 -68
- package/source/contract/contract.ts +0 -23
- package/source/contract/index.ts +0 -2
- package/source/contract/reply.ts +0 -56
- package/source/contract/request.ts +0 -140
- package/source/contract/schemas.ts +0 -39
- package/source/discovery.ts +0 -53
- package/source/effect.ts +0 -14
- package/source/emission.ts +0 -21
- package/source/entities/changeset.ts +0 -37
- package/source/entities/entity.ts +0 -137
- package/source/entities/factory.ts +0 -52
- package/source/entities/index.ts +0 -4
- package/source/entities/newid.ts +0 -9
- package/source/entities/set.ts +0 -27
- package/source/event.ts +0 -57
- package/source/exceptions.ts +0 -133
- package/source/exposition.ts +0 -33
- package/source/guard.ts +0 -16
- package/source/index.ts +0 -36
- package/source/locator.ts +0 -37
- package/source/observation.ts +0 -16
- package/source/operation.ts +0 -139
- package/source/outbox/index.ts +0 -1
- package/source/outbox/outbox.ts +0 -341
- package/source/query/criteria.ts +0 -90
- package/source/query/options.ts +0 -35
- package/source/query.ts +0 -67
- package/source/receiver.ts +0 -120
- package/source/reflection.ts +0 -20
- package/source/remote.ts +0 -20
- package/source/state.ts +0 -179
- package/source/transition.ts +0 -79
- package/source/transmission.ts +0 -38
- package/source/types/atomicity.ts +0 -63
- package/source/types/bindings.ts +0 -59
- package/source/types/bridges.ts +0 -54
- package/source/types/extensions.ts +0 -89
- package/source/types/index.ts +0 -14
- package/source/types/message.ts +0 -5
- package/source/types/operations.ts +0 -31
- package/source/types/outbox.ts +0 -35
- package/source/types/receiver.ts +0 -10
- package/source/types/request.ts +0 -54
- package/source/types/state.ts +0 -9
- package/source/types/storages.ts +0 -134
- package/source/unmanaged.ts +0 -8
- package/test/call.fixtures.js +0 -25
- package/test/call.test.js +0 -79
- package/test/component.fixtures.js +0 -18
- package/test/component.test.js +0 -57
- package/test/connector.fixtures.js +0 -56
- package/test/connector.test.js +0 -266
- package/test/context.fixtures.js +0 -14
- package/test/context.test.js +0 -40
- package/test/contract/conditions.test.js +0 -32
- package/test/contract/contract.fixtures.js +0 -28
- package/test/contract/request.test.js +0 -196
- package/test/discovery.test.js +0 -71
- package/test/emission.fixtures.js +0 -13
- package/test/emission.test.js +0 -60
- package/test/entities/entity.fixtures.js +0 -24
- package/test/entities/entity.test.js +0 -137
- package/test/entities/factory.fixtures.js +0 -31
- package/test/entities/factory.test.js +0 -99
- package/test/entities/set.fixtures.js +0 -9
- package/test/entities/set.test.js +0 -13
- package/test/event.fixtures.js +0 -24
- package/test/event.test.js +0 -162
- package/test/locator.test.js +0 -120
- package/test/outbox.test.js +0 -202
- package/test/query.fixtures.js +0 -96
- package/test/query.test.js +0 -183
- package/test/receiver.fixtures.js +0 -20
- package/test/receiver.test.js +0 -144
- package/test/reflection.test.js +0 -31
- package/test/state.fixtures.js +0 -49
- package/test/state.test.js +0 -162
- package/test/transmission.fixtures.js +0 -13
- package/test/transmission.test.js +0 -77
- package/tsconfig.json +0 -10
- package/tsconfig.tsbuildinfo +0 -1
package/test/outbox.test.js
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import { it, beforeEach, afterEach, mock } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import { Outbox } from '../source/outbox/index.js'
|
|
5
|
-
|
|
6
|
-
let emission, storage, atom, outbox, listeners
|
|
7
|
-
|
|
8
|
-
const BATCH = 4
|
|
9
|
-
|
|
10
|
-
/** rows as the storage hands them back, ids ascending like the uuid v7 they are */
|
|
11
|
-
const page = (from, count) =>
|
|
12
|
-
Array.from({ length: count }, (_, i) => ({
|
|
13
|
-
id: String(from + i).padStart(4, '0'),
|
|
14
|
-
event: { state: {} }
|
|
15
|
-
}))
|
|
16
|
-
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
resetCalls()
|
|
19
|
-
mock.timers.enable()
|
|
20
|
-
|
|
21
|
-
emission = { emit: mock.fn(async () => undefined), link: mock.fn() }
|
|
22
|
-
|
|
23
|
-
storage = {
|
|
24
|
-
link: mock.fn(),
|
|
25
|
-
outbox: {
|
|
26
|
-
pending: mock.fn(async () => []),
|
|
27
|
-
settle: mock.fn(async () => undefined)
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
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
|
-
}
|
|
45
|
-
outbox = new Outbox(emission, storage, atom, { interval: 1000, batch: BATCH })
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
afterEach(() => {
|
|
49
|
-
mock.timers.reset()
|
|
50
|
-
})
|
|
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
|
-
|
|
57
|
-
/** one cycle, and everything it awaited */
|
|
58
|
-
const cycle = async () => {
|
|
59
|
-
mock.timers.tick(1000)
|
|
60
|
-
|
|
61
|
-
for (let i = 0; i < 20; i++) await Promise.resolve()
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
it('should read nothing more when the first page is short', async () => {
|
|
65
|
-
storage.outbox.pending.mock.mockImplementationOnce(async () => page(0, 3))
|
|
66
|
-
|
|
67
|
-
await outbox.open()
|
|
68
|
-
await cycle()
|
|
69
|
-
|
|
70
|
-
assert.strictEqual(storage.outbox.pending.mock.callCount(), 1)
|
|
71
|
-
assert.strictEqual(emission.emit.mock.callCount(), 3)
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
it('should keep reading while a page comes back full', async () => {
|
|
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
|
-
)
|
|
87
|
-
|
|
88
|
-
await outbox.open()
|
|
89
|
-
await cycle()
|
|
90
|
-
|
|
91
|
-
assert.strictEqual(storage.outbox.pending.mock.callCount(), 3)
|
|
92
|
-
assert.strictEqual(emission.emit.mock.callCount(), 2 * BATCH + 5)
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
it('should continue each page from the id the one before ended on', async () => {
|
|
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
|
-
)
|
|
104
|
-
|
|
105
|
-
await outbox.open()
|
|
106
|
-
await cycle()
|
|
107
|
-
|
|
108
|
-
const [, second] = storage.outbox.pending.mock.calls
|
|
109
|
-
|
|
110
|
-
assert.strictEqual(storage.outbox.pending.mock.calls[0].arguments[3], undefined)
|
|
111
|
-
assert.deepStrictEqual(second.arguments[3], String(BATCH - 1).padStart(4, '0'))
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
it('should mark what it published, once, after the last page', async () => {
|
|
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
|
-
)
|
|
123
|
-
|
|
124
|
-
await outbox.open()
|
|
125
|
-
await cycle()
|
|
126
|
-
|
|
127
|
-
assert.strictEqual(storage.outbox.settle.mock.callCount(), 1)
|
|
128
|
-
assert.strictEqual(storage.outbox.settle.mock.calls[0].arguments[0].length, BATCH + 2)
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
it('should not publish a row it has published and not yet marked', async () => {
|
|
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
|
-
)
|
|
143
|
-
|
|
144
|
-
await outbox.open()
|
|
145
|
-
await cycle()
|
|
146
|
-
await cycle()
|
|
147
|
-
|
|
148
|
-
assert.strictEqual(emission.emit.mock.callCount(), 2)
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
it('should read nothing while it owns no slots', async () => {
|
|
152
|
-
atom.slots.mock.mockImplementation(() => null)
|
|
153
|
-
|
|
154
|
-
await outbox.open()
|
|
155
|
-
await cycle()
|
|
156
|
-
|
|
157
|
-
assert.strictEqual(storage.outbox.pending.mock.callCount(), 0)
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
function resetCalls(target = [assert, BATCH, page, cycle], seen = new Set()) {
|
|
161
|
-
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
162
|
-
|
|
163
|
-
seen.add(target)
|
|
164
|
-
|
|
165
|
-
for (const value of Object.values(target))
|
|
166
|
-
if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
|
|
167
|
-
else resetCalls(value, seen)
|
|
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.fixtures.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
export const samples = {
|
|
2
|
-
simple: {
|
|
3
|
-
query: {
|
|
4
|
-
criteria: 'name==Eddie'
|
|
5
|
-
},
|
|
6
|
-
parsed: {
|
|
7
|
-
criteria: {
|
|
8
|
-
type: 'COMPARISON',
|
|
9
|
-
left: { type: 'SELECTOR', selector: 'name' },
|
|
10
|
-
operator: '==',
|
|
11
|
-
right: { type: 'VALUE', value: 'Eddie' }
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
properties: {
|
|
15
|
-
name: {
|
|
16
|
-
type: 'string'
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
|
|
21
|
-
extended: {
|
|
22
|
-
query: {
|
|
23
|
-
criteria: 'flag==true;volume>2.1'
|
|
24
|
-
},
|
|
25
|
-
parsed: {
|
|
26
|
-
criteria: {
|
|
27
|
-
type: 'LOGIC',
|
|
28
|
-
left: {
|
|
29
|
-
type: 'COMPARISON',
|
|
30
|
-
left: { type: 'SELECTOR', selector: 'flag' },
|
|
31
|
-
operator: '==',
|
|
32
|
-
right: { type: 'VALUE', value: true }
|
|
33
|
-
},
|
|
34
|
-
operator: ';',
|
|
35
|
-
right: {
|
|
36
|
-
type: 'COMPARISON',
|
|
37
|
-
left: { type: 'SELECTOR', selector: 'volume' },
|
|
38
|
-
operator: '>',
|
|
39
|
-
right: { type: 'VALUE', value: 2.1 }
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
properties: {
|
|
44
|
-
flag: {
|
|
45
|
-
type: 'boolean'
|
|
46
|
-
},
|
|
47
|
-
volume: {
|
|
48
|
-
type: 'number'
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
},
|
|
52
|
-
|
|
53
|
-
abc: {
|
|
54
|
-
properties: {
|
|
55
|
-
a: {
|
|
56
|
-
type: 'string'
|
|
57
|
-
},
|
|
58
|
-
b: {
|
|
59
|
-
type: 'string'
|
|
60
|
-
},
|
|
61
|
-
c: {
|
|
62
|
-
type: 'string'
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
|
|
67
|
-
id: {
|
|
68
|
-
properties: {
|
|
69
|
-
id: {
|
|
70
|
-
type: 'string'
|
|
71
|
-
},
|
|
72
|
-
name: {
|
|
73
|
-
type: 'string'
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
query: {
|
|
77
|
-
id: '123',
|
|
78
|
-
criteria: 'name==Eddie'
|
|
79
|
-
},
|
|
80
|
-
parsed: {
|
|
81
|
-
id: '123',
|
|
82
|
-
criteria: {
|
|
83
|
-
type: 'COMPARISON',
|
|
84
|
-
left: {
|
|
85
|
-
type: 'SELECTOR',
|
|
86
|
-
selector: 'name'
|
|
87
|
-
},
|
|
88
|
-
operator: '==',
|
|
89
|
-
right: {
|
|
90
|
-
type: 'VALUE',
|
|
91
|
-
value: 'Eddie'
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
package/test/query.test.js
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
import { describe, it, beforeEach } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import { Query } from '../source/query.js'
|
|
5
|
-
import * as fixtures from './query.fixtures.js'
|
|
6
|
-
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
resetCalls()
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
describe('criteria', () => {
|
|
12
|
-
it('should not throw if no criteria', () => {
|
|
13
|
-
const instance = new Query(fixtures.samples.simple.properties)
|
|
14
|
-
const query = instance.parse({})
|
|
15
|
-
|
|
16
|
-
assert.strictEqual(query.criteria, undefined)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
it('should parse criteria', () => {
|
|
20
|
-
const instance = new Query(fixtures.samples.simple.properties)
|
|
21
|
-
const query = instance.parse(fixtures.samples.simple.query)
|
|
22
|
-
|
|
23
|
-
assert.deepStrictEqual(query.criteria, fixtures.samples.simple.parsed.criteria)
|
|
24
|
-
})
|
|
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
|
-
|
|
33
|
-
it('should keep a parsed criteria', () => {
|
|
34
|
-
const instance = new Query(fixtures.samples.simple.properties)
|
|
35
|
-
|
|
36
|
-
const first = instance.parse(fixtures.samples.simple.query).criteria
|
|
37
|
-
const second = instance.parse(fixtures.samples.simple.query).criteria
|
|
38
|
-
|
|
39
|
-
assert.strictEqual(second, first)
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('should not keep an invalid criteria', () => {
|
|
43
|
-
const instance = new Query(fixtures.samples.simple.properties)
|
|
44
|
-
const query = { criteria: 'nonexistent==1' }
|
|
45
|
-
|
|
46
|
-
assert.throws(() => instance.parse(query))
|
|
47
|
-
assert.throws(() => instance.parse(query))
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
it('should parse criteria with type coercion', () => {
|
|
51
|
-
const instance = new Query(fixtures.samples.extended.properties)
|
|
52
|
-
const query = instance.parse(fixtures.samples.extended.query)
|
|
53
|
-
|
|
54
|
-
assert.deepStrictEqual(query.criteria, fixtures.samples.extended.parsed.criteria)
|
|
55
|
-
})
|
|
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
|
-
|
|
106
|
-
it('should throw on unknown properties', () => {
|
|
107
|
-
const instance = new Query(fixtures.samples.simple.properties)
|
|
108
|
-
|
|
109
|
-
assert.throws(
|
|
110
|
-
() => instance.parse({ criteria: 'lastname==Johnson' }),
|
|
111
|
-
(error) => /not defined/.test(error.message)
|
|
112
|
-
)
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
it('should parse id', () => {
|
|
116
|
-
const instance = new Query(fixtures.samples.id.properties)
|
|
117
|
-
const query = instance.parse({ ...fixtures.samples.id.query })
|
|
118
|
-
|
|
119
|
-
assert.deepStrictEqual(query, fixtures.samples.id.parsed)
|
|
120
|
-
})
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
describe('options', () => {
|
|
124
|
-
const instance = new Query(fixtures.samples.abc.properties)
|
|
125
|
-
|
|
126
|
-
it('should not throw if no options', () => {
|
|
127
|
-
const query = instance.parse({})
|
|
128
|
-
|
|
129
|
-
assert.strictEqual(query.options, undefined)
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
describe('omit, limit', () => {
|
|
133
|
-
it('should pass', () => {
|
|
134
|
-
const input = { omit: 1, limit: 1 }
|
|
135
|
-
const query = instance.parse(input)
|
|
136
|
-
|
|
137
|
-
assert.deepStrictEqual(query.options, input)
|
|
138
|
-
})
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
describe('sort', () => {
|
|
142
|
-
it('should set default values', () => {
|
|
143
|
-
const sort = ['a', 'b:desc', 'c']
|
|
144
|
-
const query = instance.parse({ sort })
|
|
145
|
-
|
|
146
|
-
assert.deepStrictEqual(query.options.sort, [
|
|
147
|
-
['a', 'asc'],
|
|
148
|
-
['b', 'desc'],
|
|
149
|
-
['c', 'asc']
|
|
150
|
-
])
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
it('should throw on unknown properties', () => {
|
|
154
|
-
const sort = ['d:asc']
|
|
155
|
-
|
|
156
|
-
assert.throws(
|
|
157
|
-
() => instance.parse({ sort }),
|
|
158
|
-
(error) => /not defined/.test(error.message)
|
|
159
|
-
)
|
|
160
|
-
})
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
describe('projection', () => {
|
|
164
|
-
it('should throw on unknown properties', () => {
|
|
165
|
-
const projection = ['a', 'b', 'c', 'd']
|
|
166
|
-
|
|
167
|
-
assert.throws(
|
|
168
|
-
() => instance.parse({ projection }),
|
|
169
|
-
(error) => /not defined/.test(error.message)
|
|
170
|
-
)
|
|
171
|
-
})
|
|
172
|
-
})
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
function resetCalls(target = [assert, fixtures], seen = new Set()) {
|
|
176
|
-
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
177
|
-
|
|
178
|
-
seen.add(target)
|
|
179
|
-
|
|
180
|
-
for (const value of Object.values(target))
|
|
181
|
-
if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
|
|
182
|
-
else resetCalls(value, seen)
|
|
183
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { mock } from 'node:test'
|
|
2
|
-
|
|
3
|
-
import { generate } from 'randomstring'
|
|
4
|
-
|
|
5
|
-
export const definition = /** @type {toa.norm.component.Receiver} */ {
|
|
6
|
-
operation: generate(),
|
|
7
|
-
conditioned: false,
|
|
8
|
-
adaptive: false
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const local = /** @type {import('@toa.io/core').Component} */ {
|
|
12
|
-
locator: { id: 'default.dummy' },
|
|
13
|
-
invoke: mock.fn()
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// noinspection JSCheckFunctionSignatures
|
|
17
|
-
export const bridge = /** @type {import('@toa.io/core/types').bridges.Event} */ {
|
|
18
|
-
condition: mock.fn(async (payload) => !(payload.reject === true)),
|
|
19
|
-
request: mock.fn(async () => ({ input: generate() }))
|
|
20
|
-
}
|
package/test/receiver.test.js
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { describe, it, beforeEach, mock } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
import { isDeepStrictEqual } from 'node:util'
|
|
4
|
-
|
|
5
|
-
import clone from 'clone-deep'
|
|
6
|
-
import { generate } from 'randomstring'
|
|
7
|
-
import { merge } from '@toa.io/generic'
|
|
8
|
-
|
|
9
|
-
import { Connector } from '../source/connector.js'
|
|
10
|
-
|
|
11
|
-
// the fixtures are not connectors, so a dependency is recorded rather than linked
|
|
12
|
-
const depends = mock.method(Connector.prototype, 'depends', () => undefined)
|
|
13
|
-
|
|
14
|
-
const dependencies = (instance) =>
|
|
15
|
-
depends.mock.calls
|
|
16
|
-
.filter((call) => call.this === instance)
|
|
17
|
-
.map((call) => call.arguments[0])
|
|
18
|
-
|
|
19
|
-
import { Receiver } from '../source/receiver.js'
|
|
20
|
-
import * as fixtures from './receiver.fixtures.js'
|
|
21
|
-
|
|
22
|
-
/** @type {import('@toa.io/core/types').Receiver} */
|
|
23
|
-
let receiver
|
|
24
|
-
|
|
25
|
-
/** @type {toa.norm.component.Receiver} */
|
|
26
|
-
let definition
|
|
27
|
-
|
|
28
|
-
beforeEach(() => {
|
|
29
|
-
resetCalls()
|
|
30
|
-
depends.mock.resetCalls()
|
|
31
|
-
|
|
32
|
-
definition = clone(fixtures.definition)
|
|
33
|
-
receiver = new Receiver(fixtures.definition, fixtures.local, fixtures.bridge)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('should depend on local, bridge', () => {
|
|
37
|
-
assert.ok(dependencies(receiver).some((one) => isDeepStrictEqual(one, fixtures.local)))
|
|
38
|
-
assert.ok(dependencies(receiver).some((one) => isDeepStrictEqual(one, fixtures.bridge)))
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
it('should apply', async () => {
|
|
42
|
-
const payload = { foo: 'bar' }
|
|
43
|
-
|
|
44
|
-
await receiver.receive({ payload })
|
|
45
|
-
|
|
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
|
-
)
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
for (const [adaptive] of [[false], [true]])
|
|
57
|
-
it(`should pass UI extensions (adaptive: ${adaptive})`, async () => {
|
|
58
|
-
resetCalls()
|
|
59
|
-
|
|
60
|
-
definition.adaptive = adaptive
|
|
61
|
-
receiver = new Receiver(definition, fixtures.local, fixtures.bridge)
|
|
62
|
-
|
|
63
|
-
const payload = { foo: generate() }
|
|
64
|
-
const extension = { [generate()]: generate() }
|
|
65
|
-
const message = { payload, ...extension }
|
|
66
|
-
|
|
67
|
-
await receiver.receive(message)
|
|
68
|
-
|
|
69
|
-
const request = adaptive
|
|
70
|
-
? await fixtures.bridge.request.mock.calls[0].result
|
|
71
|
-
: { input: payload }
|
|
72
|
-
const expected = merge(clone(request), extension)
|
|
73
|
-
|
|
74
|
-
const argument = fixtures.local.invoke.mock.calls[0].arguments[1]
|
|
75
|
-
|
|
76
|
-
assert.deepStrictEqual(argument, expected)
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
describe('conditioned', () => {
|
|
80
|
-
beforeEach(() => {
|
|
81
|
-
definition.conditioned = true
|
|
82
|
-
receiver = new Receiver(definition, fixtures.local, fixtures.bridge)
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
it('should test condition', async () => {
|
|
86
|
-
const payload = { foo: 'bar' }
|
|
87
|
-
await receiver.receive({ payload })
|
|
88
|
-
|
|
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
|
-
)
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
it('should not apply if condition is false', async () => {
|
|
106
|
-
const payload = { reject: true }
|
|
107
|
-
await receiver.receive({ payload })
|
|
108
|
-
|
|
109
|
-
assert.strictEqual(fixtures.local.invoke.mock.callCount(), 0)
|
|
110
|
-
})
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
describe('adaptive', () => {
|
|
114
|
-
beforeEach(() => {
|
|
115
|
-
definition.adaptive = true
|
|
116
|
-
receiver = new Receiver(definition, fixtures.local, fixtures.bridge)
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
it('should apply', async () => {
|
|
120
|
-
const payload = { reject: true }
|
|
121
|
-
await receiver.receive({ payload })
|
|
122
|
-
|
|
123
|
-
const request = await fixtures.bridge.request.mock.calls[0].result
|
|
124
|
-
|
|
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
|
-
)
|
|
133
|
-
})
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
function resetCalls(target = [assert, clone, fixtures], seen = new Set()) {
|
|
137
|
-
if (target === null || typeof target !== 'object' || seen.has(target)) return
|
|
138
|
-
|
|
139
|
-
seen.add(target)
|
|
140
|
-
|
|
141
|
-
for (const value of Object.values(target))
|
|
142
|
-
if (typeof value === 'function' && value.mock !== undefined) value.mock.resetCalls()
|
|
143
|
-
else resetCalls(value, seen)
|
|
144
|
-
}
|
package/test/reflection.test.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { it, beforeEach } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
|
|
4
|
-
import { generate } from 'randomstring'
|
|
5
|
-
import { Reflection, Connector } from '../source/index.js'
|
|
6
|
-
|
|
7
|
-
it('should export', () => {
|
|
8
|
-
assert.notStrictEqual(Reflection, undefined)
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
/** @type {import('@toa.io/core').Reflection<string>} */
|
|
12
|
-
let reflection
|
|
13
|
-
|
|
14
|
-
const value = generate()
|
|
15
|
-
|
|
16
|
-
/** @type {import('@toa.io/core').ReflectionSource<string>} */
|
|
17
|
-
const source = async () => value
|
|
18
|
-
|
|
19
|
-
beforeEach(() => {
|
|
20
|
-
reflection = new Reflection(source)
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
it('should be a Connector', () => {
|
|
24
|
-
assert.ok(reflection instanceof Connector)
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
it('should reflect', async () => {
|
|
28
|
-
await reflection.connect()
|
|
29
|
-
|
|
30
|
-
assert.deepStrictEqual(reflection.value, value)
|
|
31
|
-
})
|