comq 0.10.0 → 0.10.2
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/.github/workflows/release.yaml +1 -1
- package/features/rpc.streams.feature +9 -9
- package/features/rpc.streams.shards.feature +3 -3
- package/features/steps/broker.js +3 -3
- package/features/steps/events.js +2 -1
- package/features/steps/rpc.js +6 -6
- package/lerna.json +1 -1
- package/package.json +10 -9
- package/readme.md +4 -17
- package/source/.io/ReplyStream.js +12 -15
- package/source/channel.js +11 -10
- package/source/connection.js +7 -14
- package/source/io.js +56 -36
- package/source/shards/channel.js +6 -6
- package/types/io.d.ts +1 -4
- package/features/steps/.test/backpressure.test.js +0 -79
- package/features/steps/.test/broker.test.js +0 -101
- package/features/steps/.test/command.mock.js +0 -5
- package/features/steps/.test/comq.mock.js +0 -10
- package/features/steps/.test/connection.test.js +0 -285
- package/features/steps/.test/context.mock.js +0 -14
- package/features/steps/.test/context.test.js +0 -74
- package/features/steps/.test/events.test.js +0 -279
- package/features/steps/.test/io.mock.js +0 -14
- package/features/steps/.test/poison.test.js +0 -40
- package/features/steps/.test/rpc.test.js +0 -261
package/source/shards/channel.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { Promex } = require('promex')
|
|
4
4
|
const events = require('../events')
|
|
5
5
|
const emitter = require('../emitter')
|
|
6
6
|
|
|
@@ -22,13 +22,13 @@ class Channel {
|
|
|
22
22
|
/** @type {Set<Promise<comq.Channel>>} */
|
|
23
23
|
#pending = new Set()
|
|
24
24
|
|
|
25
|
-
/** @type {Map<comq.Channel,
|
|
25
|
+
/** @type {Map<comq.Channel, Promex>} */
|
|
26
26
|
#bench = new Map()
|
|
27
27
|
|
|
28
28
|
/** @type {comq.topology.type} */
|
|
29
29
|
#type
|
|
30
30
|
|
|
31
|
-
#recovery =
|
|
31
|
+
#recovery = new Promex()
|
|
32
32
|
|
|
33
33
|
#diagnostics = emitter.create()
|
|
34
34
|
|
|
@@ -134,7 +134,7 @@ class Channel {
|
|
|
134
134
|
#remove (channel) {
|
|
135
135
|
if (!this.#channels.has(channel)) return
|
|
136
136
|
|
|
137
|
-
this.#bench.set(channel,
|
|
137
|
+
this.#bench.set(channel, new Promex())
|
|
138
138
|
this.#channels.delete(channel)
|
|
139
139
|
this.#update()
|
|
140
140
|
this.#diagnostics.emit('remove', channel.index)
|
|
@@ -162,7 +162,7 @@ class Channel {
|
|
|
162
162
|
this.#add(channel)
|
|
163
163
|
|
|
164
164
|
this.#recovery.resolve()
|
|
165
|
-
this.#recovery =
|
|
165
|
+
this.#recovery = new Promex()
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
#comeback (channel) {
|
|
@@ -209,7 +209,7 @@ class Channel {
|
|
|
209
209
|
async #one (fn) {
|
|
210
210
|
if (this.#pool.length === 0) await this.#recovery
|
|
211
211
|
|
|
212
|
-
const channel =
|
|
212
|
+
const channel = this.#pool[Math.floor(Math.random() * this.#pool.length)]
|
|
213
213
|
|
|
214
214
|
try {
|
|
215
215
|
return await fn(channel)
|
package/types/io.d.ts
CHANGED
|
@@ -22,18 +22,15 @@ declare namespace comq {
|
|
|
22
22
|
buffer: Buffer
|
|
23
23
|
emitter: ReplyEmitter
|
|
24
24
|
properties: _amqp.Properties
|
|
25
|
-
reply: any
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
interface IO extends _diagnostics.Diagnosable {
|
|
29
28
|
reply (queue: string, produce: Producer): Promise<void>
|
|
30
29
|
|
|
31
|
-
request<Reply = any, Request = any> (queue: string, payload: Request, encoding?: _encoding.Encoding): Promise<Reply>
|
|
30
|
+
request<Reply = any, Request = any> (queue: string, payload: Request, encoding?: _encoding.Encoding): Promise<Reply> | Promise<Readable>
|
|
32
31
|
|
|
33
32
|
request (queue: string, stream: Readable, encoding?: _encoding.Encoding): Promise<Readable>
|
|
34
33
|
|
|
35
|
-
fetch (queue: string, payload: any, encoding?: _encoding.Encoding): Promise<Readable>
|
|
36
|
-
|
|
37
34
|
consume<T = any> (exchange: string, group: string, consumer: Consumer<T>): Promise<void>
|
|
38
35
|
|
|
39
36
|
consume<T = any> (exchange: string, consumer: Consumer<T>): Promise<void>
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { AssertionError } = require('node:assert')
|
|
4
|
-
const { generate } = require('randomstring')
|
|
5
|
-
const { random, quantity } = require('@toa.io/generic')
|
|
6
|
-
const tomato = require('@toa.io/tomato')
|
|
7
|
-
const { io } = require('./io.mock')
|
|
8
|
-
const mock = { tomato }
|
|
9
|
-
|
|
10
|
-
jest.mock('@cucumber/cucumber', () => mock.tomato)
|
|
11
|
-
|
|
12
|
-
require('../backpressure')
|
|
13
|
-
|
|
14
|
-
/** @type {comq.features.Context} */
|
|
15
|
-
let context
|
|
16
|
-
|
|
17
|
-
describe('When I\'m sending {quantity}B requests to the {token} queue at {quantity}Hz for {number} second(s)', () => {
|
|
18
|
-
const step = tomato.steps.Wh('I\'m sending {quantity}B requests to the {token} queue at {quantity}Hz for {number} second(s)')
|
|
19
|
-
|
|
20
|
-
it('should be', async () => undefined)
|
|
21
|
-
|
|
22
|
-
const bytesQ = (random(5) + 1) + 'k'
|
|
23
|
-
const frequencyQ = String((random(5) + 1) / 10) + 'k' // not too high
|
|
24
|
-
const seconds = (random(3) + 1) / 10
|
|
25
|
-
const queue = generate()
|
|
26
|
-
|
|
27
|
-
const bytes = quantity(bytesQ)
|
|
28
|
-
const frequency = quantity(frequencyQ)
|
|
29
|
-
|
|
30
|
-
beforeAll(async () => {
|
|
31
|
-
jest.clearAllMocks()
|
|
32
|
-
|
|
33
|
-
context = /** @type {comq.features.Context} */ { io, requestCount: 0, replyCount: 0 }
|
|
34
|
-
|
|
35
|
-
await step.call(context, bytesQ, queue, frequencyQ, seconds)
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
it('should send request', async () => {
|
|
39
|
-
expect(io.request).toHaveBeenCalled()
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('should sent request to specified queue', async () => {
|
|
43
|
-
const call = io.request.mock.calls[0]
|
|
44
|
-
|
|
45
|
-
expect(call[0]).toStrictEqual(queue)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('should send buffer of given size', async () => {
|
|
49
|
-
const buffer = io.request.mock.calls[0][1]
|
|
50
|
-
|
|
51
|
-
expect(Buffer.byteLength(buffer)).toStrictEqual(bytes)
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
it('should send expected amount of requests', async () => {
|
|
55
|
-
const times = Math.ceil(seconds * frequency)
|
|
56
|
-
|
|
57
|
-
expect(io.request).toHaveBeenCalledTimes(times)
|
|
58
|
-
})
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
describe('Then back pressure was applied', () => {
|
|
62
|
-
const step = tomato.steps.Th('back pressure was applied')
|
|
63
|
-
|
|
64
|
-
beforeEach(() => {
|
|
65
|
-
context = /** @type {comq.features.Context} */ { io, events: {} }
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
it('should be', async () => undefined)
|
|
69
|
-
|
|
70
|
-
it('should fail if flag is not set', async () => {
|
|
71
|
-
expect(() => step.call(context)).toThrow(AssertionError)
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
it('should pass if flag is true', async () => {
|
|
75
|
-
context.events = { flow: true }
|
|
76
|
-
|
|
77
|
-
expect(() => step.call(context)).not.toThrow()
|
|
78
|
-
})
|
|
79
|
-
})
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { generate } = require('randomstring')
|
|
4
|
-
const tomato = require('@toa.io/tomato')
|
|
5
|
-
const { command } = require('./command.mock')
|
|
6
|
-
const mock = { tomato, command }
|
|
7
|
-
|
|
8
|
-
jest.mock('@cucumber/cucumber', () => mock.tomato)
|
|
9
|
-
jest.mock('@toa.io/command', () => mock.command)
|
|
10
|
-
|
|
11
|
-
jest.setTimeout(10000)
|
|
12
|
-
|
|
13
|
-
global.COMQ_TESTING_HEALTHCHECK_INTERVAL = 0
|
|
14
|
-
|
|
15
|
-
require('../broker')
|
|
16
|
-
|
|
17
|
-
const context = /** @type {comq.features.Context} */ {}
|
|
18
|
-
|
|
19
|
-
beforeEach(() => {
|
|
20
|
-
jest.clearAllMocks()
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
describe.each([false, true])('Given the broker is/has {status} #shards:%s', (sharded) => {
|
|
24
|
-
const step = tomato.steps.Gi('the broker is/has {status}')
|
|
25
|
-
|
|
26
|
-
const containerNumber = sharded ? 1 : 0
|
|
27
|
-
|
|
28
|
-
it('should be', async () => undefined)
|
|
29
|
-
|
|
30
|
-
beforeEach(() => {
|
|
31
|
-
context.io = generate()
|
|
32
|
-
|
|
33
|
-
if (sharded) {
|
|
34
|
-
context.sharded = true
|
|
35
|
-
context.shard = containerNumber
|
|
36
|
-
}
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
it('should start comq-rmq container', async () => {
|
|
40
|
-
command.execute.mockImplementationOnce(async () => undefined)
|
|
41
|
-
command.execute.mockImplementationOnce(async () => ({ output: 'healthy' }))
|
|
42
|
-
|
|
43
|
-
await step.call(context, 'up')
|
|
44
|
-
|
|
45
|
-
expect(command.execute).toHaveBeenCalledWith('docker start comq-rmq-' + containerNumber)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('should wait for healthy state', async () => {
|
|
49
|
-
let starting = false
|
|
50
|
-
let healthy = false
|
|
51
|
-
|
|
52
|
-
command.execute.mockImplementationOnce(async () => undefined)
|
|
53
|
-
|
|
54
|
-
command.execute.mockImplementationOnce(async () => {
|
|
55
|
-
starting = true
|
|
56
|
-
|
|
57
|
-
return { output: 'starting' }
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
command.execute.mockImplementationOnce(async () => {
|
|
61
|
-
healthy = true
|
|
62
|
-
|
|
63
|
-
return { output: 'healthy' }
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
await step.call(context, 'up')
|
|
67
|
-
|
|
68
|
-
expect(command.execute).toHaveBeenCalledTimes(3)
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it('should stop comq-rmq container', async () => {
|
|
72
|
-
await step.call(context, 'down')
|
|
73
|
-
|
|
74
|
-
expect(command.execute).toHaveBeenCalledWith('docker stop comq-rmq-' + containerNumber)
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('should kill comq-rmq-0 container', async () => {
|
|
78
|
-
await step.call(context, 'crashed')
|
|
79
|
-
|
|
80
|
-
expect(command.execute).toHaveBeenCalledWith('docker kill comq-rmq-' + containerNumber)
|
|
81
|
-
})
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
describe('Given one of the brokers is/has {status}', () => {
|
|
85
|
-
const step = tomato.steps.Gi('one of the brokers is/has {status}')
|
|
86
|
-
|
|
87
|
-
it('should store picked broker', async () => {
|
|
88
|
-
await step.call(context, 'down')
|
|
89
|
-
|
|
90
|
-
expect(context.shard).toStrictEqual(expect.any(Number))
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
it('should start one of the containers', async () => {
|
|
94
|
-
command.execute.mockImplementationOnce(async () => undefined)
|
|
95
|
-
command.execute.mockImplementationOnce(async () => ({ output: 'healthy' }))
|
|
96
|
-
|
|
97
|
-
await step.call(context, 'up')
|
|
98
|
-
|
|
99
|
-
expect(command.execute).toHaveBeenCalledWith('docker start comq-rmq-' + context.shard)
|
|
100
|
-
})
|
|
101
|
-
})
|
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { AssertionError } = require('node:assert')
|
|
4
|
-
const { generate } = require('randomstring')
|
|
5
|
-
const { random, promex } = require('@toa.io/generic')
|
|
6
|
-
const tomato = require('@toa.io/tomato')
|
|
7
|
-
const { comq } = require('./comq.mock')
|
|
8
|
-
const world = require('./context.mock')
|
|
9
|
-
const mock = { tomato, comq }
|
|
10
|
-
|
|
11
|
-
jest.mock('@cucumber/cucumber', () => mock.tomato)
|
|
12
|
-
jest.mock('comq', () => mock.comq)
|
|
13
|
-
|
|
14
|
-
require('../connection')
|
|
15
|
-
|
|
16
|
-
/** @type {jest.MockedObject<comq.features.Context>} */
|
|
17
|
-
let context
|
|
18
|
-
|
|
19
|
-
beforeEach(() => {
|
|
20
|
-
jest.clearAllMocks()
|
|
21
|
-
|
|
22
|
-
context = world.context()
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
describe('Given an active connection to the broker', () => {
|
|
26
|
-
const step = tomato.steps.Gi('an active connection to the broker')
|
|
27
|
-
|
|
28
|
-
it('should be', async () => undefined)
|
|
29
|
-
|
|
30
|
-
beforeEach(async () => {
|
|
31
|
-
await step.call(context)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
it('should connect', async () => {
|
|
35
|
-
expect(context.connect).toHaveBeenCalled()
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
it('should store promise', async () => {
|
|
39
|
-
expect(context.connecting).toBeInstanceOf(Promise)
|
|
40
|
-
})
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
describe('Given an active sharded connection', () => {
|
|
44
|
-
const step = tomato.steps.Gi('an active sharded connection')
|
|
45
|
-
|
|
46
|
-
it('should be', async () => undefined)
|
|
47
|
-
|
|
48
|
-
beforeEach(async () => {
|
|
49
|
-
await step.call(context)
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('should set sharded to true', async () => {
|
|
53
|
-
expect(context.sharded).toStrictEqual(true)
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('should connect', async () => {
|
|
57
|
-
expect(context.connect).toHaveBeenCalled()
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
it('should store promise', async () => {
|
|
61
|
-
expect(context.connecting).toStrictEqual(expect.any(Promise))
|
|
62
|
-
})
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
describe('When I attempt to connect to the broker for {number} second(s)', () => {
|
|
66
|
-
const step = tomato.steps.Wh('I attempt to connect to the broker for {number} second(s)')
|
|
67
|
-
|
|
68
|
-
it('should be', async () => undefined)
|
|
69
|
-
|
|
70
|
-
const interval = (random(2) + 1) / 10
|
|
71
|
-
|
|
72
|
-
describe('broker available', () => {
|
|
73
|
-
beforeEach(async () => {
|
|
74
|
-
await step.call(context, interval)
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('should call connect', async () => {
|
|
78
|
-
expect(context.connect).toHaveBeenCalled()
|
|
79
|
-
})
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
describe('broker unavailable', () => {
|
|
83
|
-
/** @type {toa.generic.Promex} */
|
|
84
|
-
let connection
|
|
85
|
-
|
|
86
|
-
beforeEach(() => {
|
|
87
|
-
connection = promex()
|
|
88
|
-
|
|
89
|
-
context.connect.mockImplementationOnce(async () => connection)
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
it('should quit after given interval', async () => {
|
|
93
|
-
const start = new Date().getTime()
|
|
94
|
-
|
|
95
|
-
await step.call(context, interval)
|
|
96
|
-
|
|
97
|
-
const end = new Date().getTime()
|
|
98
|
-
const inaccuracy = 1 // setTimeout is inaccurate
|
|
99
|
-
|
|
100
|
-
expect(end - start + inaccuracy).toBeGreaterThanOrEqual(interval * 1000)
|
|
101
|
-
})
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
describe('exceptions', () => {
|
|
105
|
-
it('should catch exception', async () => {
|
|
106
|
-
const exception = new Error(generate())
|
|
107
|
-
|
|
108
|
-
context.connect.mockImplementationOnce(async () => { throw exception })
|
|
109
|
-
|
|
110
|
-
await step.call(context, interval)
|
|
111
|
-
|
|
112
|
-
expect(context.exception).toStrictEqual(exception)
|
|
113
|
-
})
|
|
114
|
-
})
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
describe('When I attempt to connect to the broker', () => {
|
|
118
|
-
const step = tomato.steps.Wh('I attempt to connect to the broker')
|
|
119
|
-
|
|
120
|
-
it('should be', async () => undefined)
|
|
121
|
-
|
|
122
|
-
it('should connect', async () => {
|
|
123
|
-
await step.call(context)
|
|
124
|
-
|
|
125
|
-
expect(context.connect).toHaveBeenCalled()
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
it('should store exception', async () => {
|
|
129
|
-
const exception = new Error(generate())
|
|
130
|
-
|
|
131
|
-
context.connect.mockImplementationOnce(async () => { throw exception })
|
|
132
|
-
|
|
133
|
-
await step.call(context)
|
|
134
|
-
|
|
135
|
-
expect(context.exception).toStrictEqual(exception)
|
|
136
|
-
})
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
describe('When I attempt to connect to the broker as {string} with password {string}', () => {
|
|
140
|
-
const step = tomato.steps.Wh('I attempt to connect to the broker as {string} with password {string}')
|
|
141
|
-
|
|
142
|
-
it('should be', async () => undefined)
|
|
143
|
-
|
|
144
|
-
const user = generate()
|
|
145
|
-
const password = generate()
|
|
146
|
-
|
|
147
|
-
it('should connect with credentials', async () => {
|
|
148
|
-
await step.call(context, user, password)
|
|
149
|
-
|
|
150
|
-
expect(context.connect).toHaveBeenCalledWith(user, password)
|
|
151
|
-
})
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
describe('When I attempt to establish sharded connection', () => {
|
|
155
|
-
const step = tomato.steps.Wh('I attempt to establish sharded connection')
|
|
156
|
-
|
|
157
|
-
it('should be', async () => undefined)
|
|
158
|
-
|
|
159
|
-
it('should set context.sharded to true', async () => {
|
|
160
|
-
await step.call(context)
|
|
161
|
-
|
|
162
|
-
expect(context.sharded).toStrictEqual(true)
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
it('should connect', async () => {
|
|
166
|
-
await step.call(context)
|
|
167
|
-
|
|
168
|
-
expect(context.connect).toHaveBeenCalled()
|
|
169
|
-
})
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
describe('When I attempt to establish a sharded connection as {string} with password {string}', () => {
|
|
173
|
-
const step = tomato.steps.Wh('I attempt to establish a sharded connection as {string} with password {string}')
|
|
174
|
-
|
|
175
|
-
it('should be', async () => undefined)
|
|
176
|
-
|
|
177
|
-
const user = generate()
|
|
178
|
-
const password = generate()
|
|
179
|
-
|
|
180
|
-
it('should connect with credentials', async () => {
|
|
181
|
-
await step.call(context, user, password)
|
|
182
|
-
|
|
183
|
-
expect(context.sharded).toStrictEqual(true)
|
|
184
|
-
expect(context.connect).toHaveBeenCalledWith(user, password)
|
|
185
|
-
})
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
describe.each([['', true], [' not', false]])('Then the connection is%s established',
|
|
189
|
-
(not, connected) => {
|
|
190
|
-
const step = tomato.steps.Th(`the connection is${not} established`)
|
|
191
|
-
|
|
192
|
-
it('should be', async () => undefined)
|
|
193
|
-
|
|
194
|
-
it(`should fail if is${connected ? 'n\'t' : ''} connected`, async () => {
|
|
195
|
-
context.connected = !connected
|
|
196
|
-
|
|
197
|
-
await expect(step.call(context)).rejects.toThrow(AssertionError)
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
it(`should pass if is${connected ? '' : 'n\'t'} connected`, async () => {
|
|
201
|
-
context.connected = connected
|
|
202
|
-
|
|
203
|
-
await expect(step.call(context)).resolves.not.toThrow()
|
|
204
|
-
})
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
describe('Then no exceptions are thrown', () => {
|
|
208
|
-
const step = tomato.steps.Th('no exceptions are thrown')
|
|
209
|
-
|
|
210
|
-
it('should be', async () => undefined)
|
|
211
|
-
|
|
212
|
-
it(`should fail if exception is defined`, async () => {
|
|
213
|
-
context.exception = new Error()
|
|
214
|
-
|
|
215
|
-
expect(() => step.call(context)).toThrow(AssertionError)
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
it(`should pass if exception isn't defined`, async () => {
|
|
219
|
-
expect(() => step.call(context)).not.toThrow()
|
|
220
|
-
})
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
describe('Then an exception is thrown: {string}', () => {
|
|
224
|
-
const step = tomato.steps.Th('an exception is thrown: {string}')
|
|
225
|
-
|
|
226
|
-
const message = generate()
|
|
227
|
-
|
|
228
|
-
it('should be', async () => undefined)
|
|
229
|
-
|
|
230
|
-
it(`should pass if exception is defined and message matches`, async () => {
|
|
231
|
-
context.exception = new Error(message)
|
|
232
|
-
|
|
233
|
-
const slice = message.slice(2, 6)
|
|
234
|
-
|
|
235
|
-
expect(() => step.call(context, slice)).not.toThrow()
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
it(`should fail if exception isn't defined`, async () => {
|
|
239
|
-
expect(() => step.call(context)).toThrow(AssertionError)
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
it('should fail if message doesn\'t match', async () => {
|
|
243
|
-
context.exception = new Error(generate())
|
|
244
|
-
|
|
245
|
-
expect(() => step.call(context)).toThrow(AssertionError)
|
|
246
|
-
})
|
|
247
|
-
})
|
|
248
|
-
|
|
249
|
-
describe('Given the connection has started sealing', () => {
|
|
250
|
-
const step = tomato.steps.Gi('the connection has started sealing')
|
|
251
|
-
|
|
252
|
-
it('should be', async () => undefined)
|
|
253
|
-
|
|
254
|
-
it('should seal the connection', async () => {
|
|
255
|
-
context.io = /** @type {jest.MockedObject<comq.IO>} */ {
|
|
256
|
-
seal: jest.fn(async () => undefined)
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
await step.call(context)
|
|
260
|
-
|
|
261
|
-
expect(context.io.seal).toHaveBeenCalled()
|
|
262
|
-
expect(context.sealing).toBeInstanceOf(Promise)
|
|
263
|
-
})
|
|
264
|
-
})
|
|
265
|
-
|
|
266
|
-
describe('Then the connection is sealed', () => {
|
|
267
|
-
const step = tomato.steps.Th('the connection is sealed')
|
|
268
|
-
|
|
269
|
-
it('should be', async () => undefined)
|
|
270
|
-
|
|
271
|
-
it('should await for sealing', async () => {
|
|
272
|
-
context.sealing = promex()
|
|
273
|
-
|
|
274
|
-
let sealed = false
|
|
275
|
-
|
|
276
|
-
setImmediate(() => {
|
|
277
|
-
context.sealing.resolve()
|
|
278
|
-
sealed = true
|
|
279
|
-
})
|
|
280
|
-
|
|
281
|
-
await step.call(context)
|
|
282
|
-
|
|
283
|
-
expect(sealed).toStrictEqual(true)
|
|
284
|
-
})
|
|
285
|
-
})
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { comq } = require('./comq.mock')
|
|
4
|
-
|
|
5
|
-
const connect = jest.fn(() => comq.connect())
|
|
6
|
-
const disconnect = jest.fn(async () => undefined)
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @return {jest.MockedObject<comq.features.Context>}
|
|
10
|
-
*/
|
|
11
|
-
exports.context = () => (/** @type {jest.MockedObject<comq.features.Context>} */{
|
|
12
|
-
connect,
|
|
13
|
-
disconnect
|
|
14
|
-
})
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { generate } = require('randomstring')
|
|
4
|
-
const { comq } = require('./comq.mock')
|
|
5
|
-
const mock = { comq }
|
|
6
|
-
|
|
7
|
-
jest.mock('comq', () => mock.comq)
|
|
8
|
-
|
|
9
|
-
const { Context } = require('../context')
|
|
10
|
-
|
|
11
|
-
it('should be', async () => {
|
|
12
|
-
expect(Context).toBeDefined()
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
/** @type {comq.features.Context} */
|
|
16
|
-
let context
|
|
17
|
-
|
|
18
|
-
beforeAll(async () => {
|
|
19
|
-
const _ = {}
|
|
20
|
-
|
|
21
|
-
// noinspection JSValidateTypes
|
|
22
|
-
context = new Context(_)
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
describe.each([false, true])('connect (shards: %s)', (sharded) => {
|
|
26
|
-
it('should be', async () => {
|
|
27
|
-
expect(context.connect).toBeDefined()
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
/** @type {jest.MockedObject<comq.IO>} */
|
|
31
|
-
let io
|
|
32
|
-
|
|
33
|
-
beforeEach(async () => {
|
|
34
|
-
context.sharded = sharded
|
|
35
|
-
|
|
36
|
-
await context.connect()
|
|
37
|
-
|
|
38
|
-
io = await comq.connect.mock.results[0].value
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
it('should connect', async () => {
|
|
42
|
-
const shards = ['amqp://developer:secret@localhost:5673', 'amqp://developer:secret@localhost:5674']
|
|
43
|
-
|
|
44
|
-
if (sharded) expect(comq.connect).toHaveBeenCalledWith(...shards)
|
|
45
|
-
else expect(comq.connect).toHaveBeenCalledWith(shards[0])
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('should connect with credentials', async () => {
|
|
49
|
-
const user = generate()
|
|
50
|
-
const password = generate()
|
|
51
|
-
|
|
52
|
-
await context.connect(user, password)
|
|
53
|
-
|
|
54
|
-
const shards = [`amqp://${user}:${password}@localhost:5673`, `amqp://${user}:${password}@localhost:5674`]
|
|
55
|
-
|
|
56
|
-
if (sharded) expect(comq.connect).toHaveBeenCalledWith(...shards)
|
|
57
|
-
else expect(comq.connect).toHaveBeenCalledWith(shards[0])
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
it.each(['open', 'close', 'flow', 'discard'])('should store %s event',
|
|
61
|
-
/**
|
|
62
|
-
* @param {comq.diagnostics.Event} event
|
|
63
|
-
*/
|
|
64
|
-
async (event) => {
|
|
65
|
-
expect(io.diagnose).toHaveBeenCalledWith(event, expect.any(Function))
|
|
66
|
-
expect(context.events[event]).not.toStrictEqual(true)
|
|
67
|
-
|
|
68
|
-
const listener = io.diagnose.mock.calls.find((call) => call[0] === event)[1]
|
|
69
|
-
|
|
70
|
-
listener()
|
|
71
|
-
|
|
72
|
-
expect(context.events[event]).toStrictEqual(true)
|
|
73
|
-
})
|
|
74
|
-
})
|