@toa.io/core 0.1.0-alpha.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/package.json +28 -0
- package/src/assignment.js +22 -0
- package/src/call.js +29 -0
- package/src/cascade.js +32 -0
- package/src/composition.js +26 -0
- package/src/connector.js +122 -0
- package/src/context.js +43 -0
- package/src/contract/conditions.js +21 -0
- package/src/contract/index.js +7 -0
- package/src/contract/reply.js +22 -0
- package/src/contract/request.js +49 -0
- package/src/contract/schemas/error.yaml +7 -0
- package/src/contract/schemas/index.js +7 -0
- package/src/contract/schemas/query.yaml +31 -0
- package/src/discovery.js +33 -0
- package/src/emission.js +23 -0
- package/src/entities/changeset.js +46 -0
- package/src/entities/entity.js +48 -0
- package/src/entities/factory.js +33 -0
- package/src/entities/index.js +5 -0
- package/src/entities/set.js +15 -0
- package/src/event.js +33 -0
- package/src/exceptions.js +88 -0
- package/src/exposition.js +24 -0
- package/src/index.js +43 -0
- package/src/locator.js +49 -0
- package/src/observation.js +19 -0
- package/src/operation.js +61 -0
- package/src/query/criteria.js +41 -0
- package/src/query/options.js +40 -0
- package/src/query.js +36 -0
- package/src/receiver.js +36 -0
- package/src/remote.js +17 -0
- package/src/runtime.js +38 -0
- package/src/state.js +95 -0
- package/src/transition.js +50 -0
- package/src/transmission.js +33 -0
- package/test/call.fixtures.js +25 -0
- package/test/call.test.js +52 -0
- package/test/cascade.fixtures.js +11 -0
- package/test/cascade.test.js +42 -0
- package/test/connector.fixtures.js +40 -0
- package/test/connector.test.js +199 -0
- package/test/contract/conditions.test.js +26 -0
- package/test/contract/contract.fixtures.js +27 -0
- package/test/contract/request.test.js +99 -0
- package/test/emission.fixtures.js +16 -0
- package/test/emission.test.js +35 -0
- package/test/entities/entity.fixtures.js +26 -0
- package/test/entities/entity.test.js +64 -0
- package/test/entities/factory.fixtures.js +18 -0
- package/test/entities/factory.test.js +48 -0
- package/test/entities/set.fixtures.js +11 -0
- package/test/entities/set.test.js +12 -0
- package/test/event.fixtures.js +28 -0
- package/test/event.test.js +106 -0
- package/test/locator.test.js +34 -0
- package/test/query.fixtures.js +100 -0
- package/test/query.test.js +86 -0
- package/test/receiver.fixtures.js +22 -0
- package/test/receiver.test.js +66 -0
- package/test/runtime.fixtures.js +19 -0
- package/test/runtime.test.js +40 -0
- package/test/state.fixtures.js +46 -0
- package/test/state.test.js +54 -0
- package/test/transmission.fixtures.js +15 -0
- package/test/transmission.test.js +46 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { Connector } = require('./connector')
|
|
4
|
+
const { TransmissionException } = require('./exceptions')
|
|
5
|
+
|
|
6
|
+
class Transmission extends Connector {
|
|
7
|
+
#bindings
|
|
8
|
+
|
|
9
|
+
constructor (bindings) {
|
|
10
|
+
super()
|
|
11
|
+
|
|
12
|
+
this.#bindings = bindings
|
|
13
|
+
this.depends(bindings)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async request (request) {
|
|
17
|
+
let reply = false
|
|
18
|
+
let i = 0
|
|
19
|
+
|
|
20
|
+
while (reply === false && i < this.#bindings.length) {
|
|
21
|
+
reply = await this.#bindings[i].request(request)
|
|
22
|
+
i++
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (reply === false) {
|
|
26
|
+
throw new TransmissionException(`All (${this.#bindings.length}) bindings rejected.`)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return reply
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
exports.Transmission = Transmission
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { generate } = require('randomstring')
|
|
4
|
+
|
|
5
|
+
const transmission = {
|
|
6
|
+
request: jest.fn((request) => ({ [request.invalid ? 'exception' : generate()]: generate() }))
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const contract = {
|
|
10
|
+
fit: jest.fn(() => null)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const request = () => ({
|
|
14
|
+
ok: {
|
|
15
|
+
input: { [generate()]: generate() },
|
|
16
|
+
query: { [generate()]: generate() }
|
|
17
|
+
},
|
|
18
|
+
bad: {
|
|
19
|
+
invalid: true
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
exports.transmission = transmission
|
|
24
|
+
exports.contract = contract
|
|
25
|
+
exports.request = request
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { Call } = require('../src/call')
|
|
4
|
+
const fixtures = require('./call.fixtures')
|
|
5
|
+
|
|
6
|
+
jest.mock('../src/connector')
|
|
7
|
+
|
|
8
|
+
const { Connector } = require('../src/connector')
|
|
9
|
+
|
|
10
|
+
let call
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
jest.clearAllMocks()
|
|
14
|
+
|
|
15
|
+
call = new Call(fixtures.transmission, fixtures.contract)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('should depend on transmission', () => {
|
|
19
|
+
expect(call).toBeInstanceOf(Connector)
|
|
20
|
+
expect(call).toBe(Connector.mock.instances[0])
|
|
21
|
+
expect(Connector.mock.instances[0].depends).toHaveBeenCalledWith(fixtures.transmission)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('should call transmission', async () => {
|
|
25
|
+
const request = fixtures.request().ok
|
|
26
|
+
|
|
27
|
+
await call.invoke(request)
|
|
28
|
+
|
|
29
|
+
expect(fixtures.transmission.request).toHaveBeenCalledWith(request)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('should fit request', async () => {
|
|
33
|
+
const request = fixtures.request().ok
|
|
34
|
+
|
|
35
|
+
await call.invoke(request)
|
|
36
|
+
|
|
37
|
+
expect(fixtures.contract.fit).toHaveBeenLastCalledWith(request)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('should return reply', async () => {
|
|
41
|
+
const request = fixtures.request().ok
|
|
42
|
+
|
|
43
|
+
const reply = await call.invoke(request)
|
|
44
|
+
|
|
45
|
+
expect(reply).toStrictEqual(fixtures.transmission.request.mock.results[0].value)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('should throw received exceptions', async () => {
|
|
49
|
+
const request = fixtures.request().bad
|
|
50
|
+
|
|
51
|
+
await expect(call.invoke(request)).rejects.toBeDefined()
|
|
52
|
+
})
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
jest.mock('../src/connector')
|
|
4
|
+
|
|
5
|
+
const clone = require('clone-deep')
|
|
6
|
+
|
|
7
|
+
const { Connector } = require('../src/connector')
|
|
8
|
+
const { Cascade } = require('../src/cascade')
|
|
9
|
+
const fixtures = require('./cascade.fixtures')
|
|
10
|
+
|
|
11
|
+
let cascade
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
jest.clearAllMocks()
|
|
15
|
+
|
|
16
|
+
cascade = new Cascade(clone(fixtures.bridges))
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('should depend on bridges', () => {
|
|
20
|
+
expect(cascade).toBeInstanceOf(Connector)
|
|
21
|
+
expect(Connector.mock.instances[0].depends).toHaveBeenCalledWith(fixtures.bridges)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('should call bridges.run', async () => {
|
|
25
|
+
const args = [1, 2]
|
|
26
|
+
await cascade.run(...args)
|
|
27
|
+
|
|
28
|
+
for (const bridge of fixtures.bridges) expect(bridge.run).toHaveBeenCalledWith(...args)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('should merge output', async () => {
|
|
32
|
+
const reply = await cascade.run()
|
|
33
|
+
|
|
34
|
+
expect(reply).toStrictEqual({ output: { a: true, b: true, c: true } })
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('should interrupt on error', async () => {
|
|
38
|
+
const reply = await cascade.run({ error: 'b' })
|
|
39
|
+
|
|
40
|
+
expect(reply).toStrictEqual({ error: 'b' })
|
|
41
|
+
expect(fixtures.bridges[2].run).not.toHaveBeenCalled()
|
|
42
|
+
})
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { random, timeout } = require('@toa.io/gears')
|
|
4
|
+
const { Connector } = require('../src/connector')
|
|
5
|
+
|
|
6
|
+
class TestConnector extends Connector {
|
|
7
|
+
#label
|
|
8
|
+
#seq
|
|
9
|
+
|
|
10
|
+
constructor (label, seq) {
|
|
11
|
+
super()
|
|
12
|
+
|
|
13
|
+
this.#seq = seq
|
|
14
|
+
this.#label = label
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async connection () {
|
|
18
|
+
await timeout(random(10))
|
|
19
|
+
this.#seq.push(`+${this.#label}`)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async disconnection () {
|
|
23
|
+
await timeout(random(10))
|
|
24
|
+
this.#seq.push(`-${this.#label}`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
disconnected () {
|
|
28
|
+
this.#seq.push(`*${this.#label}`)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
class FailingConnector extends Connector {
|
|
33
|
+
async connection () {
|
|
34
|
+
await timeout(random(10))
|
|
35
|
+
throw new Error('FailingConnector')
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
exports.TestConnector = TestConnector
|
|
40
|
+
exports.FailingConnector = FailingConnector
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const fixtures = require('./connector.fixtures')
|
|
4
|
+
|
|
5
|
+
let sequence
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
sequence = []
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
describe('callbacks', () => {
|
|
12
|
+
let a
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
a = new fixtures.TestConnector('a', sequence)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('should call connection', async () => {
|
|
19
|
+
await a.connect()
|
|
20
|
+
expect(sequence).toEqual(['+a'])
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('should call disconnection', async () => {
|
|
24
|
+
await a.connect()
|
|
25
|
+
await a.disconnect()
|
|
26
|
+
|
|
27
|
+
expect(sequence.indexOf('+a')).toBeLessThan(sequence.indexOf('-a'))
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('should reconnect', async () => {
|
|
31
|
+
await a.connect()
|
|
32
|
+
await a.disconnect()
|
|
33
|
+
await a.connect()
|
|
34
|
+
await a.disconnect()
|
|
35
|
+
await a.connect()
|
|
36
|
+
|
|
37
|
+
expect(sequence).toEqual(['+a', '-a', '*a', '+a', '-a', '*a', '+a'])
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
describe('dependencies', () => {
|
|
42
|
+
let a
|
|
43
|
+
let b
|
|
44
|
+
let c
|
|
45
|
+
let d
|
|
46
|
+
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
a = new fixtures.TestConnector('a', sequence)
|
|
49
|
+
b = new fixtures.TestConnector('b', sequence)
|
|
50
|
+
c = new fixtures.TestConnector('c', sequence)
|
|
51
|
+
d = new fixtures.TestConnector('d', sequence)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('should wait dependencies on connection', async () => {
|
|
55
|
+
a.depends(b).depends(c)
|
|
56
|
+
a.depends(d)
|
|
57
|
+
|
|
58
|
+
await a.connect()
|
|
59
|
+
|
|
60
|
+
expect(sequence.indexOf('+c')).toBeLessThan(sequence.indexOf('+b'))
|
|
61
|
+
expect(sequence.indexOf('+b')).toBeLessThan(sequence.indexOf('+a'))
|
|
62
|
+
expect(sequence.indexOf('+d')).toBeLessThan(sequence.indexOf('+a'))
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('should wait array of connectors', async () => {
|
|
66
|
+
a.depends([b, d])
|
|
67
|
+
b.depends(c)
|
|
68
|
+
d.depends(c)
|
|
69
|
+
|
|
70
|
+
await a.connect()
|
|
71
|
+
|
|
72
|
+
expect(sequence.indexOf('+c')).toBeLessThan(sequence.indexOf('+b'))
|
|
73
|
+
expect(sequence.indexOf('+c')).toBeLessThan(sequence.indexOf('+d'))
|
|
74
|
+
expect(sequence.indexOf('+b')).toBeLessThan(sequence.indexOf('+a'))
|
|
75
|
+
expect(sequence.indexOf('+d')).toBeLessThan(sequence.indexOf('+a'))
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('should wait array(1) of connectors', async () => {
|
|
79
|
+
a.depends([b])
|
|
80
|
+
b.depends(c)
|
|
81
|
+
|
|
82
|
+
await a.connect()
|
|
83
|
+
|
|
84
|
+
expect(sequence.indexOf('+c')).toBeLessThan(sequence.indexOf('+b'))
|
|
85
|
+
expect(sequence.indexOf('+b')).toBeLessThan(sequence.indexOf('+a'))
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it('should not throw on empty array', async () => {
|
|
89
|
+
a.depends([])
|
|
90
|
+
|
|
91
|
+
await a.connect()
|
|
92
|
+
|
|
93
|
+
expect(sequence).toStrictEqual(['+a'])
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('should await 2-way dependencies', async () => {
|
|
97
|
+
a.depends([b, c, d])
|
|
98
|
+
d.depends([b, c])
|
|
99
|
+
|
|
100
|
+
await a.connect()
|
|
101
|
+
|
|
102
|
+
expect(sequence.indexOf('+b')).toBeLessThan(sequence.indexOf('+a'))
|
|
103
|
+
expect(sequence.indexOf('+c')).toBeLessThan(sequence.indexOf('+a'))
|
|
104
|
+
expect(sequence.indexOf('+d')).toBeLessThan(sequence.indexOf('+a'))
|
|
105
|
+
|
|
106
|
+
expect(sequence.indexOf('+b')).toBeLessThan(sequence.indexOf('+d'))
|
|
107
|
+
expect(sequence.indexOf('+c')).toBeLessThan(sequence.indexOf('+d'))
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it('should disconnect before dependencies', async () => {
|
|
111
|
+
a.depends(b).depends(c)
|
|
112
|
+
b.depends(d)
|
|
113
|
+
|
|
114
|
+
await a.disconnect()
|
|
115
|
+
|
|
116
|
+
expect(sequence.indexOf('-a')).toBeLessThan(sequence.indexOf('-b'))
|
|
117
|
+
expect(sequence.indexOf('-b')).toBeLessThan(sequence.indexOf('-c'))
|
|
118
|
+
expect(sequence.indexOf('-b')).toBeLessThan(sequence.indexOf('-d'))
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('should call disconnected', async () => {
|
|
122
|
+
a.depends(b).depends(c)
|
|
123
|
+
b.depends(d)
|
|
124
|
+
|
|
125
|
+
await a.disconnect()
|
|
126
|
+
|
|
127
|
+
expect(sequence.indexOf('*c')).toBeLessThan(sequence.indexOf('*b'))
|
|
128
|
+
expect(sequence.indexOf('*b')).toBeLessThan(sequence.indexOf('*a'))
|
|
129
|
+
expect(sequence.indexOf('*d')).toBeLessThan(sequence.indexOf('*b'))
|
|
130
|
+
expect(sequence.indexOf('*a')).toBe(sequence.length - 1)
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
it('should disconnect if no parents left', async () => {
|
|
134
|
+
a.depends(c)
|
|
135
|
+
b.depends(c)
|
|
136
|
+
|
|
137
|
+
await a.connect()
|
|
138
|
+
await b.connect()
|
|
139
|
+
|
|
140
|
+
expect(sequence).toEqual(['+c', '+a', '+b'])
|
|
141
|
+
|
|
142
|
+
await a.disconnect()
|
|
143
|
+
|
|
144
|
+
expect(sequence).toEqual(['+c', '+a', '+b', '-a', '*a'])
|
|
145
|
+
|
|
146
|
+
await b.disconnect()
|
|
147
|
+
|
|
148
|
+
expect(sequence).toEqual(['+c', '+a', '+b', '-a', '*a', '-b', '-c', '*c', '*b'])
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it('should not throw if depends not on Connector', async () => {
|
|
152
|
+
a.depends({})
|
|
153
|
+
|
|
154
|
+
await expect((async () => {
|
|
155
|
+
await a.connect()
|
|
156
|
+
await a.disconnect()
|
|
157
|
+
})()).resolves.not.toThrow()
|
|
158
|
+
|
|
159
|
+
b.depends([undefined, c, {}])
|
|
160
|
+
|
|
161
|
+
await expect((async () => {
|
|
162
|
+
await b.connect()
|
|
163
|
+
await b.disconnect()
|
|
164
|
+
})()).resolves.not.toThrow()
|
|
165
|
+
|
|
166
|
+
expect(sequence).toStrictEqual([
|
|
167
|
+
'+a', '-a', '*a',
|
|
168
|
+
'+c', '+b', '-b', '-c', '*c', '*b'
|
|
169
|
+
])
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
describe('errors', () => {
|
|
173
|
+
let f
|
|
174
|
+
|
|
175
|
+
beforeEach(() => {
|
|
176
|
+
f = new fixtures.FailingConnector()
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
it('should disconnect on fail', async () => {
|
|
180
|
+
f.depends(b).depends(c)
|
|
181
|
+
|
|
182
|
+
await expect(f.connect()).rejects.toThrow('FailingConnector')
|
|
183
|
+
expect(sequence).toEqual(['+c', '+b', '-b', '-c', '*c', '*b'])
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('should interrupt connection chain', async () => {
|
|
187
|
+
a.depends(f).depends(c)
|
|
188
|
+
f.depends(d)
|
|
189
|
+
|
|
190
|
+
await expect(a.connect()).rejects.toThrow('FailingConnector')
|
|
191
|
+
|
|
192
|
+
expect(sequence.indexOf('+c')).toBeLessThan(sequence.indexOf('-c'))
|
|
193
|
+
expect(sequence.indexOf('+d')).toBeLessThan(sequence.indexOf('-d'))
|
|
194
|
+
|
|
195
|
+
expect(sequence.indexOf('+a')).toBe(-1)
|
|
196
|
+
expect(sequence.indexOf('-a')).toBe(-1)
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
})
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { generate } = require('randomstring')
|
|
4
|
+
|
|
5
|
+
const { Conditions } = require('../../src/contract/conditions')
|
|
6
|
+
const fixtures = require('./contract.fixtures')
|
|
7
|
+
|
|
8
|
+
let conditions
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
conditions = new Conditions(fixtures.schema)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('should fit value', () => {
|
|
15
|
+
const value = { foo: generate() }
|
|
16
|
+
|
|
17
|
+
conditions.fit(value)
|
|
18
|
+
|
|
19
|
+
expect(fixtures.schema.fit).toHaveBeenCalledWith(value)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('should throw on invalid value', () => {
|
|
23
|
+
const value = { invalid: true }
|
|
24
|
+
|
|
25
|
+
expect(() => conditions.fit(value)).toThrow()
|
|
26
|
+
})
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { generate } = require('randomstring')
|
|
4
|
+
const { yaml } = require('@toa.io/gears')
|
|
5
|
+
const { resolve } = require('path')
|
|
6
|
+
|
|
7
|
+
const schema = {
|
|
8
|
+
fit: jest.fn((input) => (input.invalid ? { message: generate() } : null))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const query = {
|
|
12
|
+
parse: jest.fn(() => ({ [generate()]: generate() }))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const declaration = {}
|
|
16
|
+
|
|
17
|
+
const schemas = {
|
|
18
|
+
request: {
|
|
19
|
+
properties: { query: yaml.sync(resolve(__dirname, '../../src/contract/schemas/query.yaml')) },
|
|
20
|
+
additionalProperties: false
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
exports.schema = schema
|
|
25
|
+
exports.query = query
|
|
26
|
+
exports.declaration = declaration
|
|
27
|
+
exports.schemas = schemas
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const clone = require('clone-deep')
|
|
4
|
+
const { generate } = require('randomstring')
|
|
5
|
+
|
|
6
|
+
jest.mock('../../src/contract/conditions')
|
|
7
|
+
|
|
8
|
+
const { Request } = require('../../src/contract/request')
|
|
9
|
+
const { Conditions } = require('../../src/contract/conditions')
|
|
10
|
+
const fixtures = require('./contract.fixtures')
|
|
11
|
+
|
|
12
|
+
let contract
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
jest.clearAllMocks()
|
|
16
|
+
|
|
17
|
+
contract = new Request(fixtures.schema)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('should extend Conditions', () => {
|
|
21
|
+
expect(contract).toBeInstanceOf(Conditions)
|
|
22
|
+
expect(Conditions).toHaveBeenCalledWith(fixtures.schema)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('should fit request', () => {
|
|
26
|
+
const request = { [generate()]: generate() }
|
|
27
|
+
|
|
28
|
+
contract.fit(request)
|
|
29
|
+
|
|
30
|
+
expect(Conditions.mock.instances[0].fit).toHaveBeenCalledWith(request)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
describe('schema', () => {
|
|
34
|
+
let schema
|
|
35
|
+
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
schema = clone(fixtures.schemas.request)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('should provide schema', () => {
|
|
41
|
+
expect(Request.schema({})).toBeDefined()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('should add required input', () => {
|
|
45
|
+
const input = { type: 'number' }
|
|
46
|
+
|
|
47
|
+
expect(Request.schema({ input }).properties.input).toStrictEqual(input)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('should contain query if declaration.query is not defined', () => {
|
|
51
|
+
expect(Request.schema({}).properties.query).toBeDefined()
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('should not contain query if declaration.query is false', () => {
|
|
55
|
+
delete schema.properties.query
|
|
56
|
+
expect(Request.schema({ query: false })).toStrictEqual(schema)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('should require query if declaration.query is true', () => {
|
|
60
|
+
schema.required = ['query']
|
|
61
|
+
expect(Request.schema({ query: true }).required).toStrictEqual(expect.arrayContaining(['query']))
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('should forbid projection for non observations', () => {
|
|
65
|
+
expect(Request.schema({ type: 'transition' }).properties.query.properties.projection)
|
|
66
|
+
.toBe(undefined)
|
|
67
|
+
|
|
68
|
+
expect(Request.schema({ type: 'assignment' }).properties.query.properties.projection)
|
|
69
|
+
.toBe(undefined)
|
|
70
|
+
|
|
71
|
+
expect(Request.schema({ type: 'observation' }).properties.query.properties.projection)
|
|
72
|
+
.toBeDefined()
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('should forbid version for observations', () => {
|
|
76
|
+
expect(Request.schema({ type: 'transition' }).properties.query.properties.version)
|
|
77
|
+
.toBeDefined()
|
|
78
|
+
|
|
79
|
+
expect(Request.schema({ type: 'observation' }).properties.query.properties.version)
|
|
80
|
+
.toBe(undefined)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('should allow omit, limit only for set observations', () => {
|
|
84
|
+
const transition = Request.schema({ type: 'transition' }).properties.query.properties
|
|
85
|
+
|
|
86
|
+
expect(transition.omit).toBeUndefined()
|
|
87
|
+
expect(transition.limit).toBeUndefined()
|
|
88
|
+
|
|
89
|
+
const entity = Request.schema({ type: 'observation', subject: 'entity' }).properties.query.properties
|
|
90
|
+
|
|
91
|
+
expect(entity.omit).toBeUndefined()
|
|
92
|
+
expect(entity.limit).toBeUndefined()
|
|
93
|
+
|
|
94
|
+
const set = Request.schema({ type: 'observation', subject: 'set' }).properties.query.properties
|
|
95
|
+
|
|
96
|
+
expect(set.omit).toBeDefined()
|
|
97
|
+
expect(set.limit).toBeDefined()
|
|
98
|
+
})
|
|
99
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { generate } = require('randomstring')
|
|
4
|
+
|
|
5
|
+
const events = [0, 1, 2].map((index) => ({
|
|
6
|
+
emit: jest.fn(async (state) => ({ ...state, event: index }))
|
|
7
|
+
}))
|
|
8
|
+
|
|
9
|
+
const event = {
|
|
10
|
+
origin: { [generate()]: generate() },
|
|
11
|
+
state: { [generate()]: generate() },
|
|
12
|
+
changeset: { [generate()]: generate() }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
exports.events = events
|
|
16
|
+
exports.event = event
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
jest.mock('../src/connector')
|
|
4
|
+
|
|
5
|
+
const clone = require('clone-deep')
|
|
6
|
+
|
|
7
|
+
const { Connector } = require('../src/connector')
|
|
8
|
+
const { Emission } = require('../src/emission')
|
|
9
|
+
const fixtures = require('./emission.fixtures')
|
|
10
|
+
|
|
11
|
+
let emission, event
|
|
12
|
+
|
|
13
|
+
beforeEach(async () => {
|
|
14
|
+
jest.clearAllMocks()
|
|
15
|
+
|
|
16
|
+
emission = new Emission(fixtures.events)
|
|
17
|
+
event = clone(fixtures.event)
|
|
18
|
+
|
|
19
|
+
await emission.connection()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('should depend on events', () => {
|
|
23
|
+
expect(emission).toBeInstanceOf(Connector)
|
|
24
|
+
expect(Connector.mock.instances[0].depends).toHaveBeenCalledWith(fixtures.events)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('should emit events', async () => {
|
|
28
|
+
expect.assertions(fixtures.events.length)
|
|
29
|
+
|
|
30
|
+
await emission.emit(event)
|
|
31
|
+
|
|
32
|
+
for (const evt of fixtures.events) {
|
|
33
|
+
expect(evt.emit).toHaveBeenCalledWith(event)
|
|
34
|
+
}
|
|
35
|
+
})
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { generate } = require('randomstring')
|
|
4
|
+
const clone = require('clone-deep')
|
|
5
|
+
|
|
6
|
+
const schema = {
|
|
7
|
+
fit: jest.fn((object) =>
|
|
8
|
+
(object.fail ? { [generate()]: generate() } : undefined)),
|
|
9
|
+
|
|
10
|
+
defaults: jest.fn(() => ({ [generate()]: generate() }))
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const state = () => clone({
|
|
14
|
+
id: generate(),
|
|
15
|
+
foo: generate(),
|
|
16
|
+
_created: generate(),
|
|
17
|
+
_updated: generate(),
|
|
18
|
+
_deleted: generate(),
|
|
19
|
+
_version: generate()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const failed = () => clone({ ...state(), fail: true })
|
|
23
|
+
|
|
24
|
+
exports.schema = schema
|
|
25
|
+
exports.state = state
|
|
26
|
+
exports.failed = failed
|