@toa.io/bindings.amqp 0.2.1-dev.3 → 0.2.1-dev.4

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.
@@ -0,0 +1,21 @@
1
+ 'use strict'
2
+
3
+ const { generate } = require('randomstring')
4
+
5
+ /**
6
+ * @return {jest.MockedObject<comq.IO>}
7
+ */
8
+ const io = () => (/** @type {jest.MockedObject<comq.IO>} */ {
9
+ request: jest.fn(async () => generate()),
10
+ reply: jest.fn(async () => undefined),
11
+ emit: jest.fn(async () => undefined),
12
+ consume: jest.fn(async () => undefined),
13
+ seal: jest.fn(async () => undefined),
14
+ close: jest.fn(async () => undefined)
15
+ })
16
+
17
+ const comq = {
18
+ connect: jest.fn(async () => io())
19
+ }
20
+
21
+ exports.comq = comq
@@ -0,0 +1,51 @@
1
+ 'use strict'
2
+
3
+ const { generate } = require('randomstring')
4
+ const { Connector } = require('@toa.io/core')
5
+
6
+ const mock = {
7
+ communication: require('./communication.mock').communication,
8
+ queues: require('./queues.mock')
9
+ }
10
+
11
+ jest.mock('../source/queues', () => mock.queues)
12
+
13
+ const { Consumer } = require('../source/consumer')
14
+
15
+ it('should be', async () => {
16
+ expect(Consumer).toBeDefined()
17
+ })
18
+
19
+ const comm = mock.communication()
20
+ const locator = /** @type {toa.core.Locator} */ { name: generate(), namespace: generate() }
21
+ const endpoint = generate()
22
+
23
+ /** @type {toa.core.bindings.Consumer} */
24
+ let consumer
25
+
26
+ beforeEach(() => {
27
+ jest.clearAllMocks()
28
+
29
+ consumer = new Consumer(comm, locator, endpoint)
30
+ })
31
+
32
+ it('should be instance of Connector', async () => {
33
+ expect(consumer).toBeInstanceOf(Connector)
34
+ })
35
+
36
+ it('should depend on communication', async () => {
37
+ expect(comm.link).toHaveBeenCalledWith(consumer)
38
+ })
39
+
40
+ it('should send request', async () => {
41
+ const request = generate()
42
+
43
+ const reply = await consumer.request(request)
44
+
45
+ expect(mock.queues.name).toHaveBeenCalledWith(locator, endpoint)
46
+
47
+ const queue = mock.queues.name.mock.results[0].value
48
+
49
+ expect(comm.request).toHaveBeenCalledWith(queue, request)
50
+ expect(reply).toStrictEqual(await comm.request.mock.results[0].value)
51
+ })
@@ -0,0 +1,54 @@
1
+ 'use strict'
2
+
3
+ // region setup
4
+
5
+ const { generate } = require('randomstring')
6
+ const { Connector } = require('@toa.io/core')
7
+
8
+ const mock = {
9
+ communication: require('./communication.mock').communication,
10
+ queues: require('./queues.mock')
11
+ }
12
+
13
+ jest.mock('../source/queues', () => mock.queues)
14
+
15
+ const { Emitter } = require('../source/emitter')
16
+
17
+ it('should be', async () => {
18
+ expect(Emitter).toBeDefined()
19
+ })
20
+
21
+ const comm = mock.communication()
22
+ const locator = /** @type {toa.core.Locator} */ { name: generate(), namespace: generate() }
23
+ const label = generate()
24
+
25
+ /** @type {toa.core.bindings.Emitter} */
26
+ let emitter
27
+
28
+ beforeEach(() => {
29
+ jest.clearAllMocks()
30
+
31
+ emitter = new Emitter(comm, locator, label)
32
+ })
33
+
34
+ // endregion
35
+
36
+ it('should be instance of Connector', async () => {
37
+ expect(emitter).toBeInstanceOf(Connector)
38
+ })
39
+
40
+ it('should depend on communication', async () => {
41
+ expect(comm.link).toHaveBeenCalledWith(emitter)
42
+ })
43
+
44
+ it('should emit', async () => {
45
+ const message = generate()
46
+
47
+ await emitter.emit(message)
48
+
49
+ expect(mock.queues.name).toHaveBeenCalledWith(locator, label)
50
+
51
+ const exchange = mock.queues.name.mock.results[0].value
52
+
53
+ expect(comm.emit).toHaveBeenCalledWith(exchange, message)
54
+ })
@@ -0,0 +1,201 @@
1
+ 'use strict'
2
+
3
+ // region setup
4
+
5
+ const { generate } = require('randomstring')
6
+ const { Locator } = require('@toa.io/core')
7
+
8
+ jest.mock('../source/pointer')
9
+ jest.mock('../source/communication')
10
+ jest.mock('../source/producer')
11
+ jest.mock('../source/consumer')
12
+ jest.mock('../source/emitter')
13
+ jest.mock('../source/receiver')
14
+ jest.mock('../source/broadcast')
15
+
16
+ const {
17
+ /** @type {jest.MockedClass<Communication>} */
18
+ Communication
19
+ } = require('../source/communication')
20
+
21
+ const {
22
+ /** @type {jest.MockedClass<Pointer>} */
23
+ Pointer
24
+ } = require('../source/pointer')
25
+
26
+ const {
27
+ /** @type {jest.MockedClass<Producer>} */
28
+ Producer
29
+ } = require('../source/producer')
30
+
31
+ const {
32
+ /** @type {jest.MockedClass<Consumer>} */
33
+ Consumer
34
+ } = require('../source/consumer')
35
+
36
+ const {
37
+ /** @type {jest.MockedClass<Emitter>} */
38
+ Emitter
39
+ } = require('../source/emitter')
40
+
41
+ const {
42
+ /** @type {jest.MockedClass<Receiver>} */
43
+ Receiver
44
+ } = require('../source/receiver')
45
+
46
+ const {
47
+ /** @type {jest.MockedClass<Broadcast>} */
48
+ Broadcast
49
+ } = require('../source/broadcast')
50
+
51
+ const { Factory } = require('../')
52
+
53
+ it('should be', async () => {
54
+ expect(Factory).toBeDefined()
55
+ })
56
+
57
+ /** @type {toa.core.bindings.Factory} */
58
+ let factory
59
+
60
+ beforeEach(() => {
61
+ jest.clearAllMocks()
62
+
63
+ factory = new Factory()
64
+ })
65
+
66
+ const locator = /** @type {toa.core.Locator} */ { name: generate(), namespace: generate() }
67
+ const endpoints = [generate(), generate()]
68
+ const endpoint = generate()
69
+ const name = generate()
70
+ const group = generate()
71
+ const component = /** @type {toa.core.Component} */ {}
72
+ const processor = /** @type {toa.core.Receiver} */ {}
73
+
74
+ /** @type {jest.MockedObject<toa.amqp.Communication>} */
75
+ let comm
76
+
77
+ /** @type {toa.core.Connector} */
78
+ let producer
79
+
80
+ /** @type {toa.core.bindings.Consumer} */
81
+ let consumer
82
+
83
+ /** @type {toa.core.Connector} */
84
+ let receiver
85
+
86
+ /** @type {toa.core.bindings.Emitter} */
87
+ let emitter
88
+
89
+ /** @type {toa.core.bindings.Broadcast} */
90
+ let broadcast
91
+
92
+ // endregion
93
+
94
+ describe.each(['Producer', 'Consumer', 'Emitter', 'Receiver', 'Broadcast'])('%s assets', (classname) => {
95
+ const method = classname.toLowerCase()
96
+
97
+ it('should be', async () => {
98
+ expect(factory[method]).toBeDefined()
99
+ })
100
+
101
+ beforeEach(() => {
102
+ jest.clearAllMocks()
103
+
104
+ switch (method) {
105
+ case 'producer':
106
+ factory.producer(locator, endpoints, component)
107
+ break
108
+ case 'consumer':
109
+ factory.consumer(locator, endpoint)
110
+ break
111
+ case 'emitter':
112
+ factory.emitter(locator, endpoint)
113
+ break
114
+ case 'receiver':
115
+ factory.receiver(locator, endpoint, group, processor)
116
+ break
117
+ case 'broadcast':
118
+ factory.broadcast(name, group)
119
+ break
120
+ }
121
+ })
122
+
123
+ if (method !== 'broadcast') {
124
+ it('should create Pointer', async () => {
125
+ expect(Pointer).toHaveBeenCalledWith(locator)
126
+ })
127
+ }
128
+
129
+ it('should create Communication', async () => {
130
+ const pointer = Pointer.mock.instances[0]
131
+
132
+ expect(Communication).toHaveBeenCalledWith(pointer)
133
+ })
134
+ })
135
+
136
+ describe('Producer', () => {
137
+ beforeEach(() => {
138
+ producer = factory.producer(locator, endpoints, component)
139
+ comm = Communication.mock.instances[0]
140
+ })
141
+
142
+ it('should create instance', async () => {
143
+ expect(Producer).toHaveBeenCalledWith(comm, locator, endpoints, component)
144
+ expect(producer).toStrictEqual(Producer.mock.instances[0])
145
+ })
146
+ })
147
+
148
+ describe('Consumer', () => {
149
+ beforeEach(() => {
150
+ consumer = factory.consumer(locator, endpoint)
151
+ comm = Communication.mock.instances[0]
152
+ })
153
+
154
+ it('should create instance', async () => {
155
+ expect(Consumer).toHaveBeenCalledWith(comm, locator, endpoint)
156
+ expect(consumer).toStrictEqual(Consumer.mock.instances[0])
157
+ })
158
+ })
159
+
160
+ describe('Emitter', () => {
161
+ beforeEach(() => {
162
+ emitter = factory.emitter(locator, endpoint)
163
+ comm = Communication.mock.instances[0]
164
+ })
165
+
166
+ it('should create instance', async () => {
167
+ expect(Emitter).toHaveBeenCalledWith(comm, locator, endpoint)
168
+ expect(emitter).toStrictEqual(Emitter.mock.instances[0])
169
+ })
170
+ })
171
+
172
+ describe('Receiver', () => {
173
+ beforeEach(() => {
174
+ receiver = factory.receiver(locator, endpoint, group, processor)
175
+ comm = Communication.mock.instances[0]
176
+ })
177
+
178
+ it('should create instance', async () => {
179
+ expect(Receiver).toHaveBeenCalledWith(comm, locator, endpoint, group, processor)
180
+ expect(receiver).toStrictEqual(Receiver.mock.instances[0])
181
+ })
182
+ })
183
+
184
+ describe('Broadcast', () => {
185
+ beforeEach(() => {
186
+ broadcast = factory.broadcast(name, group)
187
+ comm = Communication.mock.instances[0]
188
+ })
189
+
190
+ it('should create Locator', async () => {
191
+ const locator = Broadcast.mock.calls[0][1]
192
+
193
+ expect(locator.namespace).toStrictEqual('system')
194
+ expect(locator.name).toStrictEqual(name)
195
+ })
196
+
197
+ it('should create instance', async () => {
198
+ expect(Broadcast).toHaveBeenCalledWith(comm, expect.any(Locator), group)
199
+ expect(broadcast).toStrictEqual(Broadcast.mock.instances[0])
200
+ })
201
+ })
@@ -2,15 +2,14 @@
2
2
 
3
3
  const { generate } = require('randomstring')
4
4
  const { Locator } = require('@toa.io/core')
5
- const { encode, letters: { up } } = require('@toa.io/generic')
5
+ const { encode } = require('@toa.io/generic')
6
6
 
7
- const { Pointer } = require('../src/pointer')
8
- const { PREFIX } = require('../src/constants')
7
+ const { Pointer } = require('../source/pointer')
9
8
 
10
9
  /** @type {toa.core.Locator} */
11
10
  let locator
12
11
 
13
- /** @type {toa.amqp.Pointer} */
12
+ /** @type {Pointer} */
14
13
  let pointer
15
14
 
16
15
  const protocol = 'amqp:'
@@ -35,7 +34,7 @@ beforeEach(() => {
35
34
  const namespace = generate()
36
35
  const uris = { default: url.href }
37
36
  const value = encode(uris)
38
- const key = `TOA_${up(PREFIX)}_POINTER`
37
+ const key = 'TOA_BINDINGS_AMQP_POINTER'
39
38
 
40
39
  process.env[key] = value
41
40
 
@@ -0,0 +1,69 @@
1
+ 'use strict'
2
+
3
+ const { generate } = require('randomstring')
4
+ const { each } = require('@toa.io/generic')
5
+
6
+ const mock = {
7
+ communication: require('./communication.mock').communication,
8
+ queues: require('./queues.mock')
9
+ }
10
+
11
+ jest.mock('../source/queues', () => mock.queues)
12
+
13
+ const { Producer } = require('../source/producer')
14
+
15
+ it('should be', async () => {
16
+ expect(Producer).toBeDefined()
17
+ })
18
+
19
+ /** @type {jest.MockedObject<toa.amqp.Communication>} */
20
+ let comm
21
+
22
+ const locator = /** @type {toa.core.Locator} */ generate()
23
+ const endpoints = [generate(), generate()]
24
+
25
+ const component = /** @type {jest.MockedObject<toa.core.Component>} */ {
26
+ connect: jest.fn(async () => undefined),
27
+ link: jest.fn(),
28
+ invoke: jest.fn(async () => generate())
29
+ }
30
+
31
+ /** @type {Producer} */
32
+ let producer
33
+
34
+ beforeEach(() => {
35
+ jest.clearAllMocks()
36
+
37
+ comm = mock.communication()
38
+ producer = new Producer(comm, locator, endpoints, component)
39
+ })
40
+
41
+ it('should depend on Communication', async () => {
42
+ expect(comm.link).toHaveBeenCalled()
43
+ })
44
+
45
+ it('should depend onComponent', async () => {
46
+ expect(component.link).toHaveBeenCalled()
47
+ })
48
+
49
+ it('should bind endpoints', async () => {
50
+ await producer.connect()
51
+
52
+ await each(endpoints, async (endpoint, i) => {
53
+ const n = i + 1
54
+
55
+ expect(mock.queues.name).toHaveBeenNthCalledWith(n, locator, endpoint)
56
+
57
+ const queue = mock.queues.name.mock.results[i].value
58
+
59
+ expect(comm.reply).toHaveBeenNthCalledWith(n, queue, expect.any(Function))
60
+
61
+ const process = comm.reply.mock.calls[i][1]
62
+
63
+ const request = generate()
64
+
65
+ await process(request)
66
+
67
+ expect(component.invoke).toHaveBeenNthCalledWith(n, endpoint, request)
68
+ })
69
+ })
@@ -0,0 +1,7 @@
1
+ 'use strict'
2
+
3
+ const { properties } = require('../')
4
+
5
+ it('should export properties', async () => {
6
+ expect(properties).toStrictEqual({ async: true })
7
+ })
@@ -0,0 +1,7 @@
1
+ 'use strict'
2
+
3
+ const { generate } = require('randomstring')
4
+
5
+ const name = jest.fn(() => generate())
6
+
7
+ exports.name = name
@@ -0,0 +1,35 @@
1
+ 'use strict'
2
+
3
+ const { generate } = require('randomstring')
4
+
5
+ const { name } = require('../source/queues')
6
+
7
+ /** @type {toa.core.Locator} */
8
+ let locator
9
+
10
+ const endpoint = generate()
11
+
12
+ beforeEach(() => {
13
+ locator = /** @type {toa.core.Locator} */ {
14
+ name: generate(),
15
+ namespace: generate()
16
+ }
17
+ })
18
+
19
+ it('should be', async () => {
20
+ expect(name).toBeInstanceOf(Function)
21
+ })
22
+
23
+ it('should name a queue', async () => {
24
+ const queue = name(locator, endpoint)
25
+
26
+ expect(queue).toStrictEqual(`${locator.namespace}.${locator.name}.${endpoint}`)
27
+ })
28
+
29
+ it('should name a queue with nameless locator', async () => {
30
+ delete locator.name
31
+
32
+ const queue = name(locator, endpoint)
33
+
34
+ expect(queue).toStrictEqual(`${locator.namespace}.${endpoint}`)
35
+ })
@@ -0,0 +1,64 @@
1
+ 'use strict'
2
+
3
+ const { generate } = require('randomstring')
4
+ const { Connector } = require('@toa.io/core')
5
+
6
+ const mock = {
7
+ communication: require('./communication.mock').communication,
8
+ queues: require('./queues.mock')
9
+ }
10
+
11
+ jest.mock('../source/queues', () => mock.queues)
12
+
13
+ const { Receiver } = require('../source/receiver')
14
+
15
+ it('should be', async () => {
16
+ expect(Receiver).toBeDefined()
17
+ })
18
+
19
+ /** @type {jest.MockedObject<toa.amqp.Communication>} */
20
+ const comm = mock.communication()
21
+
22
+ const locator = /** @type {toa.core.Locator} */ { name: generate(), namespace: generate() }
23
+ const group = generate()
24
+ const label = generate()
25
+
26
+ const processor = /** @type {jest.MockedObject<toa.core.Receiver>} */ {
27
+ connect: jest.fn(async () => undefined),
28
+ link: jest.fn(),
29
+ receive: jest.fn(async () => undefined)
30
+ }
31
+
32
+ /** @type {Receiver} */
33
+ let receiver
34
+
35
+ beforeEach(() => {
36
+ jest.clearAllMocks()
37
+
38
+ receiver = new Receiver(comm, locator, label, group, processor)
39
+ })
40
+
41
+ it('should be instance of Connector', async () => {
42
+ expect(receiver).toBeInstanceOf(Connector)
43
+ })
44
+
45
+ it('should depend on communication', async () => {
46
+ expect(comm.link).toHaveBeenCalledWith(receiver)
47
+ })
48
+
49
+ it('should consume events', async () => {
50
+ await receiver.open()
51
+
52
+ expect(mock.queues.name).toHaveBeenCalledWith(locator, label)
53
+
54
+ const exchange = mock.queues.name.mock.results[0].value
55
+
56
+ expect(comm.consume).toHaveBeenCalledWith(exchange, group, expect.any(Function))
57
+
58
+ const callback = comm.consume.mock.calls[0][2]
59
+ const message = generate()
60
+
61
+ await callback(message)
62
+
63
+ expect(processor.receive).toHaveBeenCalledWith(message)
64
+ })
@@ -0,0 +1,16 @@
1
+ import { Connector } from '@toa.io/core/types'
2
+ import * as comq from 'comq'
3
+
4
+ declare namespace toa.amqp {
5
+
6
+ interface Communication extends Connector {
7
+ request(queue: string, request: any): Promise<any>
8
+
9
+ reply(queue: string, process: comq.producer): Promise<void>
10
+
11
+ emit(exchange: string, message: any): Promise<void>
12
+
13
+ consume(exchange: string, group: string, callback: comq.consumer): Promise<void>
14
+ }
15
+
16
+ }
@@ -1,37 +0,0 @@
1
- 'use strict'
2
-
3
- const { Connector } = require('@toa.io/core')
4
- const { newid } = require('@toa.io/generic')
5
-
6
- /**
7
- * @implements {toa.core.bindings.Broadcaster}
8
- */
9
- class Broadcaster extends Connector {
10
- #group
11
- #channel
12
- #prefix
13
-
14
- constructor (channel, prefix, group) {
15
- super()
16
-
17
- this.#group = group === undefined ? newid() : group
18
-
19
- this.#channel = channel
20
- this.#prefix = prefix + '.'
21
-
22
- this.depends(channel)
23
- }
24
-
25
- async send (label, payload) {
26
- await this.#channel.publish(this.#prefix + label, payload, {
27
- expiration: 10,
28
- persistent: false
29
- })
30
- }
31
-
32
- async receive (label, callback) {
33
- await this.#channel.subscribe(this.#prefix + label, this.#group, callback)
34
- }
35
- }
36
-
37
- exports.Broadcaster = Broadcaster