aedes 0.51.3 → 1.0.1
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/.claude/settings.local.json +12 -0
- package/.github/actions/sticky-pr-comment/action.yml +55 -0
- package/.github/workflows/benchmark-compare-serial.yml +60 -0
- package/.github/workflows/ci.yml +12 -17
- package/.release-it.json +18 -0
- package/.taprc +15 -6
- package/README.md +6 -4
- package/aedes.d.ts +0 -6
- package/aedes.js +270 -242
- package/benchmarks/README.md +33 -0
- package/benchmarks/pingpong.js +94 -25
- package/benchmarks/receiver.js +77 -0
- package/benchmarks/report.js +150 -0
- package/benchmarks/runBenchmarks.js +118 -0
- package/benchmarks/sender.js +86 -0
- package/benchmarks/server.js +19 -18
- package/checkVersion.js +20 -0
- package/docs/Aedes.md +66 -8
- package/docs/Client.md +3 -4
- package/docs/Examples.md +39 -22
- package/docs/MIGRATION.md +50 -0
- package/eslint.config.js +8 -0
- package/example.js +51 -40
- package/examples/clusters/index.js +28 -23
- package/examples/clusters/package.json +10 -6
- package/lib/client.js +405 -306
- package/lib/handlers/connect.js +42 -38
- package/lib/handlers/index.js +9 -11
- package/lib/handlers/ping.js +2 -3
- package/lib/handlers/puback.js +5 -5
- package/lib/handlers/publish.js +29 -14
- package/lib/handlers/pubrec.js +9 -17
- package/lib/handlers/pubrel.js +34 -25
- package/lib/handlers/subscribe.js +47 -43
- package/lib/handlers/unsubscribe.js +16 -19
- package/lib/qos-packet.js +14 -17
- package/lib/utils.js +5 -12
- package/lib/write.js +4 -5
- package/package.json +139 -136
- package/test/auth.js +468 -804
- package/test/basic.js +613 -575
- package/test/bridge.js +44 -40
- package/test/client-pub-sub.js +531 -504
- package/test/close_socket_by_other_party.js +137 -102
- package/test/connect.js +487 -484
- package/test/drain-timeout.js +593 -0
- package/test/drain-toxiproxy.js +620 -0
- package/test/events.js +173 -145
- package/test/helper.js +351 -73
- package/test/keep-alive.js +40 -67
- package/test/meta.js +257 -210
- package/test/not-blocking.js +93 -197
- package/test/qos1.js +464 -554
- package/test/qos2.js +308 -393
- package/test/regr-21.js +39 -21
- package/test/require.cjs +22 -0
- package/test/retain.js +349 -398
- package/test/topics.js +176 -183
- package/test/types/aedes.test-d.ts +4 -8
- package/test/will.js +310 -428
- package/types/instance.d.ts +40 -35
- package/types/packet.d.ts +10 -10
- package/.coveralls.yml +0 -1
- package/benchmarks/bombing.js +0 -34
- package/benchmarks/bombingQoS1.js +0 -36
- package/benchmarks/throughputCounter.js +0 -23
- package/benchmarks/throughputCounterQoS1.js +0 -33
- package/types/.eslintrc.json +0 -47
package/test/retain.js
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { test } from 'node:test'
|
|
2
|
+
import { once } from 'node:events'
|
|
3
|
+
import {
|
|
4
|
+
brokerPublish,
|
|
5
|
+
checkNoPacket,
|
|
6
|
+
connect,
|
|
7
|
+
createAndConnect,
|
|
8
|
+
createPubSub,
|
|
9
|
+
delay,
|
|
10
|
+
nextPacket,
|
|
11
|
+
publish,
|
|
12
|
+
setup,
|
|
13
|
+
subscribe,
|
|
14
|
+
} from './helper.js'
|
|
15
|
+
import { Aedes } from '../aedes.js'
|
|
8
16
|
|
|
9
17
|
// [MQTT-3.3.1-9]
|
|
10
|
-
test('live retain packets',
|
|
18
|
+
test('live retain packets', async (t) => {
|
|
11
19
|
t.plan(5)
|
|
12
20
|
const expected = {
|
|
13
21
|
cmd: 'publish',
|
|
@@ -19,36 +27,28 @@ test('live retain packets', function (t) {
|
|
|
19
27
|
qos: 0
|
|
20
28
|
}
|
|
21
29
|
|
|
22
|
-
const s =
|
|
23
|
-
t.teardown(s.broker.close.bind(s.broker))
|
|
30
|
+
const s = await createAndConnect(t)
|
|
24
31
|
|
|
25
|
-
subscribe(t, s, 'hello', 0
|
|
26
|
-
s.outStream.on('data', function (packet) {
|
|
27
|
-
t.same(packet, expected)
|
|
28
|
-
})
|
|
32
|
+
await subscribe(t, s, 'hello', 0)
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}, function () {
|
|
39
|
-
t.pass('publish finished')
|
|
40
|
-
})
|
|
34
|
+
await brokerPublish(s, {
|
|
35
|
+
cmd: 'publish',
|
|
36
|
+
topic: 'hello',
|
|
37
|
+
payload: Buffer.from('world'),
|
|
38
|
+
retain: true,
|
|
39
|
+
dup: false,
|
|
40
|
+
length: 12,
|
|
41
|
+
qos: 0
|
|
41
42
|
})
|
|
43
|
+
t.assert.ok(true, 'publish finished')
|
|
44
|
+
const packet = await nextPacket(s)
|
|
45
|
+
t.assert.deepEqual(structuredClone(packet), expected)
|
|
42
46
|
})
|
|
43
47
|
|
|
44
|
-
test('retain messages',
|
|
48
|
+
test('retain messages', async (t) => {
|
|
45
49
|
t.plan(4)
|
|
46
50
|
|
|
47
|
-
const broker =
|
|
48
|
-
t.teardown(broker.close.bind(broker))
|
|
49
|
-
|
|
50
|
-
const publisher = connect(setup(broker))
|
|
51
|
-
const subscriber = connect(setup(broker))
|
|
51
|
+
const { broker, publisher, subscriber } = await createPubSub(t)
|
|
52
52
|
const expected = {
|
|
53
53
|
cmd: 'publish',
|
|
54
54
|
topic: 'hello',
|
|
@@ -59,28 +59,31 @@ test('retain messages', function (t) {
|
|
|
59
59
|
retain: true
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
setImmediate(function () {
|
|
68
|
-
subscribe(t, subscriber, 'hello', 0, function () {
|
|
69
|
-
subscriber.outStream.once('data', function (packet) {
|
|
70
|
-
t.same(packet, expected, 'packet must match')
|
|
71
|
-
})
|
|
62
|
+
const doSubscribe = async () => {
|
|
63
|
+
await new Promise((resolve) => {
|
|
64
|
+
broker.subscribe('hello', (packet, cb) => {
|
|
65
|
+
cb()
|
|
66
|
+
resolve()
|
|
72
67
|
})
|
|
73
68
|
})
|
|
74
|
-
|
|
69
|
+
await subscribe(t, subscriber, 'hello', 0)
|
|
70
|
+
}
|
|
75
71
|
|
|
76
|
-
|
|
72
|
+
// run parallel
|
|
73
|
+
await Promise.all([
|
|
74
|
+
doSubscribe(),
|
|
75
|
+
publisher.inStream.write(expected)
|
|
76
|
+
])
|
|
77
|
+
|
|
78
|
+
const packet = await nextPacket(subscriber)
|
|
79
|
+
t.assert.deepEqual(structuredClone(packet), expected, 'packet must match')
|
|
77
80
|
})
|
|
78
81
|
|
|
79
|
-
test('retain messages propagates through broker subscriptions',
|
|
82
|
+
test('retain messages propagates through broker subscriptions', async (t) => {
|
|
80
83
|
t.plan(1)
|
|
81
84
|
|
|
82
|
-
const broker =
|
|
83
|
-
t.
|
|
85
|
+
const broker = await Aedes.createBroker()
|
|
86
|
+
t.after(() => broker.close())
|
|
84
87
|
|
|
85
88
|
const expected = {
|
|
86
89
|
cmd: 'publish',
|
|
@@ -91,29 +94,28 @@ test('retain messages propagates through broker subscriptions', function (t) {
|
|
|
91
94
|
retain: true
|
|
92
95
|
}
|
|
93
96
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
97
|
+
await new Promise((resolve) => {
|
|
98
|
+
const subscriberFunc = (packet, cb) => {
|
|
99
|
+
packet = Object.assign({}, packet)
|
|
100
|
+
delete packet.brokerId
|
|
101
|
+
delete packet.brokerCounter
|
|
102
|
+
cb()
|
|
103
|
+
setImmediate(() => {
|
|
104
|
+
t.assert.deepEqual(structuredClone(packet), expected, 'packet must not have been modified')
|
|
105
|
+
resolve()
|
|
106
|
+
})
|
|
107
|
+
}
|
|
103
108
|
|
|
104
|
-
|
|
105
|
-
|
|
109
|
+
broker.subscribe('hello', subscriberFunc, () => {
|
|
110
|
+
broker.publish(expected)
|
|
111
|
+
})
|
|
106
112
|
})
|
|
107
113
|
})
|
|
108
114
|
|
|
109
|
-
test('avoid wrong deduping of retain messages',
|
|
110
|
-
t.plan(
|
|
111
|
-
|
|
112
|
-
const broker = aedes()
|
|
113
|
-
t.teardown(broker.close.bind(broker))
|
|
115
|
+
test('avoid wrong deduping of retain messages', async (t) => {
|
|
116
|
+
t.plan(8)
|
|
114
117
|
|
|
115
|
-
const publisher =
|
|
116
|
-
const subscriber = connect(setup(broker))
|
|
118
|
+
const { broker, publisher, subscriber } = await createPubSub(t)
|
|
117
119
|
const expected = {
|
|
118
120
|
cmd: 'publish',
|
|
119
121
|
topic: 'hello',
|
|
@@ -124,41 +126,46 @@ test('avoid wrong deduping of retain messages', function (t) {
|
|
|
124
126
|
retain: true
|
|
125
127
|
}
|
|
126
128
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
publisher.inStream.write({
|
|
134
|
-
cmd: 'publish',
|
|
135
|
-
topic: 'hello2',
|
|
136
|
-
payload: Buffer.from('world'),
|
|
137
|
-
qos: 0,
|
|
138
|
-
dup: false
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
subscriber.outStream.once('data', function (packet) {
|
|
142
|
-
subscribe(t, subscriber, 'hello', 0, function () {
|
|
143
|
-
subscriber.outStream.once('data', function (packet) {
|
|
144
|
-
t.same(packet, expected, 'packet must match')
|
|
145
|
-
})
|
|
146
|
-
})
|
|
129
|
+
const doSubscribe = async () => {
|
|
130
|
+
await new Promise((resolve) => {
|
|
131
|
+
broker.subscribe('hello', (packet, cb) => {
|
|
132
|
+
cb()
|
|
133
|
+
resolve()
|
|
147
134
|
})
|
|
148
135
|
})
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
136
|
+
// subscribe and publish another topic
|
|
137
|
+
await subscribe(t, subscriber, 'hello2', 0, 10)
|
|
138
|
+
publisher.inStream.write({
|
|
139
|
+
cmd: 'publish',
|
|
140
|
+
topic: 'hello2',
|
|
141
|
+
payload: Buffer.from('world'),
|
|
142
|
+
qos: 0,
|
|
143
|
+
dup: false
|
|
144
|
+
})
|
|
145
|
+
// receive publish and verify topic
|
|
146
|
+
const packet = await nextPacket(subscriber)
|
|
147
|
+
t.assert.deepEqual(packet.topic, 'hello2', 'packet must match')
|
|
148
|
+
}
|
|
149
|
+
// run parallel
|
|
150
|
+
await Promise.all([
|
|
151
|
+
doSubscribe(),
|
|
152
|
+
publisher.inStream.write(expected)
|
|
153
|
+
])
|
|
154
|
+
|
|
155
|
+
// get the retained message
|
|
156
|
+
await subscribe(t, subscriber, 'hello', 0)
|
|
157
|
+
const packet = await nextPacket(subscriber)
|
|
158
|
+
t.assert.deepEqual(structuredClone(packet), expected, 'packet must match')
|
|
152
159
|
})
|
|
153
160
|
|
|
154
|
-
test('reconnected subscriber will not receive retained messages when QoS 0 and clean',
|
|
155
|
-
t.plan(
|
|
161
|
+
test('reconnected subscriber will not receive retained messages when QoS 0 and clean', async (t) => {
|
|
162
|
+
t.plan(5)
|
|
156
163
|
|
|
157
|
-
const broker =
|
|
158
|
-
|
|
164
|
+
const { broker, publisher, subscriber } = await createPubSub(t, {
|
|
165
|
+
publisher: { clean: true },
|
|
166
|
+
subscriber: { clean: true }
|
|
167
|
+
})
|
|
159
168
|
|
|
160
|
-
const publisher = connect(setup(broker), { clean: true })
|
|
161
|
-
let subscriber = connect(setup(broker), { clean: true })
|
|
162
169
|
const expected = {
|
|
163
170
|
cmd: 'publish',
|
|
164
171
|
topic: 'hello',
|
|
@@ -168,37 +175,37 @@ test('reconnected subscriber will not receive retained messages when QoS 0 and c
|
|
|
168
175
|
dup: false,
|
|
169
176
|
length: 12
|
|
170
177
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
subscriber.outStream.once('data', function (packet) {
|
|
180
|
-
t.same(packet, expected, 'packet must match')
|
|
181
|
-
subscriber.inStream.end()
|
|
182
|
-
publisher.inStream.write({
|
|
183
|
-
cmd: 'publish',
|
|
184
|
-
topic: 'hello',
|
|
185
|
-
payload: 'foo',
|
|
186
|
-
qos: 0,
|
|
187
|
-
retain: true
|
|
188
|
-
})
|
|
189
|
-
subscriber = connect(setup(broker), { clean: true })
|
|
190
|
-
subscriber.outStream.on('data', function (packet) {
|
|
191
|
-
t.fail('should not received retain message')
|
|
192
|
-
})
|
|
193
|
-
})
|
|
178
|
+
|
|
179
|
+
await subscribe(t, subscriber, 'hello', 0)
|
|
180
|
+
publisher.inStream.write({
|
|
181
|
+
cmd: 'publish',
|
|
182
|
+
topic: 'hello',
|
|
183
|
+
payload: 'world',
|
|
184
|
+
qos: 0,
|
|
185
|
+
retain: false
|
|
194
186
|
})
|
|
187
|
+
const packet = await nextPacket(subscriber)
|
|
188
|
+
t.assert.deepEqual(structuredClone(packet), expected, 'packet must match')
|
|
189
|
+
subscriber.inStream.end()
|
|
190
|
+
publisher.inStream.write({
|
|
191
|
+
cmd: 'publish',
|
|
192
|
+
topic: 'hello',
|
|
193
|
+
payload: 'foo',
|
|
194
|
+
qos: 0,
|
|
195
|
+
retain: true
|
|
196
|
+
})
|
|
197
|
+
const subscriber2 = setup(broker)
|
|
198
|
+
await connect(subscriber2, { connect: { clean: true } })
|
|
199
|
+
await checkNoPacket(t, subscriber2, 10)
|
|
195
200
|
})
|
|
196
201
|
|
|
197
|
-
test('subscriber will not receive retained messages when QoS is 128',
|
|
198
|
-
t.plan(
|
|
202
|
+
test('subscriber will not receive retained messages when QoS is 128', async (t) => {
|
|
203
|
+
t.plan(5)
|
|
199
204
|
|
|
200
|
-
const broker =
|
|
201
|
-
|
|
205
|
+
const { broker, publisher, subscriber } = await createPubSub(t, {
|
|
206
|
+
publisher: { clean: true },
|
|
207
|
+
subscriber: { clean: true }
|
|
208
|
+
})
|
|
202
209
|
|
|
203
210
|
const pubPacket = {
|
|
204
211
|
cmd: 'publish',
|
|
@@ -209,7 +216,7 @@ test('subscriber will not receive retained messages when QoS is 128', function (
|
|
|
209
216
|
messageId: 42
|
|
210
217
|
}
|
|
211
218
|
|
|
212
|
-
broker.authorizeSubscribe =
|
|
219
|
+
broker.authorizeSubscribe = (client, sub, callback) => {
|
|
213
220
|
if (sub.topic === pubPacket.topic) {
|
|
214
221
|
callback(null, null)
|
|
215
222
|
} else {
|
|
@@ -217,32 +224,20 @@ test('subscriber will not receive retained messages when QoS is 128', function (
|
|
|
217
224
|
}
|
|
218
225
|
}
|
|
219
226
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
publisher.outStream.on('data', function (packet) {
|
|
225
|
-
const subscriber = connect(setup(broker), { clean: true })
|
|
226
|
-
subscribe(t, subscriber, pubPacket.topic, 128, function () {
|
|
227
|
-
subscriber.outStream.on('data', function (packet) {
|
|
228
|
-
t.fail('should not received retain message')
|
|
229
|
-
})
|
|
230
|
-
})
|
|
231
|
-
})
|
|
227
|
+
await publish(t, publisher, pubPacket)
|
|
228
|
+
await subscribe(t, subscriber, pubPacket.topic, 128)
|
|
229
|
+
await checkNoPacket(t, subscriber, 10)
|
|
232
230
|
})
|
|
233
231
|
|
|
234
232
|
// [MQTT-3.3.1-6]
|
|
235
|
-
test('new QoS 0 subscribers receive QoS 0 retained messages when clean',
|
|
233
|
+
test('new QoS 0 subscribers receive QoS 0 retained messages when clean', async (t) => {
|
|
236
234
|
t.plan(9)
|
|
237
235
|
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
clock.reset()
|
|
242
|
-
broker.close()
|
|
236
|
+
const { broker, publisher, subscriber: subscriber1 } = await createPubSub(t, {
|
|
237
|
+
publisher: { clean: true },
|
|
238
|
+
subscriber: { clean: true }
|
|
243
239
|
})
|
|
244
240
|
|
|
245
|
-
const publisher = connect(setup(broker), { clean: true })
|
|
246
241
|
const expected = {
|
|
247
242
|
cmd: 'publish',
|
|
248
243
|
topic: 'hello/world',
|
|
@@ -259,33 +254,28 @@ test('new QoS 0 subscribers receive QoS 0 retained messages when clean', functio
|
|
|
259
254
|
qos: 0,
|
|
260
255
|
retain: true
|
|
261
256
|
})
|
|
262
|
-
const subscriber1 = connect(setup(broker), { clean: true })
|
|
263
|
-
subscribe(t, subscriber1, 'hello/world', 0, function () {
|
|
264
|
-
subscriber1.outStream.on('data', function (packet) {
|
|
265
|
-
t.same(packet, expected, 'packet must match')
|
|
266
|
-
clock.tick(100)
|
|
267
|
-
})
|
|
268
|
-
})
|
|
269
|
-
const subscriber2 = connect(setup(broker), { clean: true })
|
|
270
|
-
subscribe(t, subscriber2, 'hello/+', 0, function () {
|
|
271
|
-
subscriber2.outStream.on('data', function (packet) {
|
|
272
|
-
t.same(packet, expected, 'packet must match')
|
|
273
|
-
clock.tick(100)
|
|
274
|
-
})
|
|
275
|
-
})
|
|
276
257
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
258
|
+
await subscribe(t, subscriber1, 'hello/world', 0)
|
|
259
|
+
const packet1 = await nextPacket(subscriber1)
|
|
260
|
+
t.assert.deepEqual(structuredClone(packet1), expected, 'packet must match')
|
|
261
|
+
|
|
262
|
+
const subscriber2 = setup(broker)
|
|
263
|
+
await connect(subscriber2, { connect: { clean: true } })
|
|
264
|
+
await subscribe(t, subscriber2, 'hello/+', 0)
|
|
265
|
+
const packet2 = await nextPacket(subscriber2)
|
|
266
|
+
t.assert.deepEqual(structuredClone(packet2), expected, 'packet must match')
|
|
267
|
+
t.assert.equal(broker.counter, 9)
|
|
280
268
|
})
|
|
281
269
|
|
|
282
270
|
// [MQTT-3.3.1-5]
|
|
283
|
-
test('new QoS 0 subscribers receive downgraded QoS 1 retained messages when clean',
|
|
284
|
-
t.plan(
|
|
271
|
+
test('new QoS 0 subscribers receive downgraded QoS 1 retained messages when clean', async (t) => {
|
|
272
|
+
t.plan(7)
|
|
285
273
|
|
|
286
|
-
const
|
|
274
|
+
const publisher = await createAndConnect(t, {
|
|
275
|
+
connect: { clean: true },
|
|
276
|
+
})
|
|
277
|
+
const broker = publisher.broker
|
|
287
278
|
|
|
288
|
-
const publisher = connect(setup(broker), { clean: true })
|
|
289
279
|
const expected = {
|
|
290
280
|
cmd: 'publish',
|
|
291
281
|
topic: 'hello',
|
|
@@ -295,7 +285,7 @@ test('new QoS 0 subscribers receive downgraded QoS 1 retained messages when clea
|
|
|
295
285
|
dup: false,
|
|
296
286
|
length: 12
|
|
297
287
|
}
|
|
298
|
-
publisher
|
|
288
|
+
await publish(t, publisher, {
|
|
299
289
|
cmd: 'publish',
|
|
300
290
|
topic: 'hello',
|
|
301
291
|
payload: 'world',
|
|
@@ -303,30 +293,29 @@ test('new QoS 0 subscribers receive downgraded QoS 1 retained messages when clea
|
|
|
303
293
|
retain: true,
|
|
304
294
|
messageId: 42
|
|
305
295
|
})
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
broker.
|
|
318
|
-
t.equal(broker.counter, 8)
|
|
319
|
-
})
|
|
296
|
+
|
|
297
|
+
const subscriber = setup(broker)
|
|
298
|
+
await connect(subscriber, { connect: { clean: true } })
|
|
299
|
+
await subscribe(t, subscriber, 'hello', 0)
|
|
300
|
+
const packet = await nextPacket(subscriber)
|
|
301
|
+
t.assert.ok(packet.messageId !== 42, 'messageId should not be the same')
|
|
302
|
+
delete packet.messageId
|
|
303
|
+
t.assert.deepEqual(structuredClone(packet), expected, 'packet must match')
|
|
304
|
+
broker.close()
|
|
305
|
+
|
|
306
|
+
await once(broker, 'closed')
|
|
307
|
+
t.assert.equal(broker.counter, 9)
|
|
320
308
|
})
|
|
321
309
|
|
|
322
310
|
// [MQTT-3.3.1-10]
|
|
323
|
-
test('clean retained messages',
|
|
324
|
-
t.plan(
|
|
311
|
+
test('clean retained messages', async (t) => {
|
|
312
|
+
t.plan(4)
|
|
325
313
|
|
|
326
|
-
const
|
|
327
|
-
|
|
314
|
+
const publisher = await createAndConnect(t, {
|
|
315
|
+
connect: { clean: true },
|
|
316
|
+
})
|
|
317
|
+
const broker = publisher.broker
|
|
328
318
|
|
|
329
|
-
const publisher = connect(setup(broker), { clean: true })
|
|
330
319
|
publisher.inStream.write({
|
|
331
320
|
cmd: 'publish',
|
|
332
321
|
topic: 'hello',
|
|
@@ -341,47 +330,48 @@ test('clean retained messages', function (t) {
|
|
|
341
330
|
qos: 0,
|
|
342
331
|
retain: true
|
|
343
332
|
})
|
|
344
|
-
const subscriber =
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
})
|
|
349
|
-
})
|
|
333
|
+
const subscriber = setup(broker)
|
|
334
|
+
await connect(subscriber, { connect: { clean: true } })
|
|
335
|
+
await subscribe(t, subscriber, 'hello', 0)
|
|
336
|
+
await checkNoPacket(t, subscriber, 10)
|
|
350
337
|
})
|
|
351
338
|
|
|
352
339
|
// [MQTT-3.3.1-11]
|
|
353
|
-
test('broker not store zero-byte retained messages',
|
|
354
|
-
t.plan(
|
|
355
|
-
|
|
356
|
-
const broker = aedes()
|
|
357
|
-
t.teardown(broker.close.bind(broker))
|
|
358
|
-
|
|
359
|
-
const s = connect(setup(broker))
|
|
340
|
+
test('broker not store zero-byte retained messages', async (t) => {
|
|
341
|
+
t.plan(1)
|
|
360
342
|
|
|
343
|
+
const s = await createAndConnect(t)
|
|
361
344
|
s.inStream.write({
|
|
362
345
|
cmd: 'publish',
|
|
363
346
|
topic: 'hello',
|
|
364
347
|
payload: '',
|
|
365
348
|
retain: true
|
|
366
349
|
})
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
350
|
+
|
|
351
|
+
await new Promise(resolve => {
|
|
352
|
+
s.broker.on('publish', async (packet, client) => {
|
|
353
|
+
if (packet.topic.startsWith('$SYS/')) {
|
|
354
|
+
return
|
|
355
|
+
}
|
|
356
|
+
const stream = s.broker.persistence.createRetainedStream(packet.topic)
|
|
357
|
+
const result = await stream.toArray()
|
|
358
|
+
if (result?.[0] === undefined) {
|
|
359
|
+
t.assert.ok(true, 'no zero-byte retained messages stored')
|
|
360
|
+
} else {
|
|
361
|
+
t.assert.fail('zero-byte retained messages should not be stored')
|
|
362
|
+
}
|
|
363
|
+
resolve()
|
|
364
|
+
})
|
|
375
365
|
})
|
|
376
366
|
})
|
|
377
367
|
|
|
378
|
-
test('fail to clean retained messages without retain flag',
|
|
368
|
+
test('fail to clean retained messages without retain flag', async (t) => {
|
|
379
369
|
t.plan(4)
|
|
380
370
|
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
const
|
|
371
|
+
const publisher = await createAndConnect(t, {
|
|
372
|
+
connect: { clean: true },
|
|
373
|
+
})
|
|
374
|
+
const broker = publisher.broker
|
|
385
375
|
const expected = {
|
|
386
376
|
cmd: 'publish',
|
|
387
377
|
topic: 'hello',
|
|
@@ -405,21 +395,20 @@ test('fail to clean retained messages without retain flag', function (t) {
|
|
|
405
395
|
qos: 0,
|
|
406
396
|
retain: false
|
|
407
397
|
})
|
|
408
|
-
const subscriber =
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
})
|
|
398
|
+
const subscriber = setup(broker)
|
|
399
|
+
await connect(subscriber, { connect: { clean: true } })
|
|
400
|
+
await subscribe(t, subscriber, 'hello', 0)
|
|
401
|
+
const packet = await nextPacket(subscriber)
|
|
402
|
+
t.assert.deepEqual(structuredClone(packet), expected, 'packet must match')
|
|
414
403
|
})
|
|
415
404
|
|
|
416
|
-
test('only get the last retained messages in same topic',
|
|
405
|
+
test('only get the last retained messages in same topic', async (t) => {
|
|
417
406
|
t.plan(4)
|
|
418
407
|
|
|
419
|
-
const
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
const
|
|
408
|
+
const publisher = await createAndConnect(t, {
|
|
409
|
+
connect: { clean: true },
|
|
410
|
+
})
|
|
411
|
+
const broker = publisher.broker
|
|
423
412
|
const expected = {
|
|
424
413
|
cmd: 'publish',
|
|
425
414
|
topic: 'hello',
|
|
@@ -443,22 +432,21 @@ test('only get the last retained messages in same topic', function (t) {
|
|
|
443
432
|
qos: 0,
|
|
444
433
|
retain: true
|
|
445
434
|
})
|
|
446
|
-
const subscriber =
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
})
|
|
435
|
+
const subscriber = setup(broker)
|
|
436
|
+
await connect(subscriber, { connect: { clean: true } })
|
|
437
|
+
await subscribe(t, subscriber, 'hello', 0)
|
|
438
|
+
const packet = await nextPacket(subscriber)
|
|
439
|
+
t.assert.deepEqual(structuredClone(packet), expected, 'packet must match')
|
|
452
440
|
})
|
|
453
441
|
|
|
454
|
-
test('deliver QoS 1 retained messages to new subscriptions',
|
|
455
|
-
t.plan(
|
|
442
|
+
test('deliver QoS 1 retained messages to new subscriptions', async (t) => {
|
|
443
|
+
t.plan(5)
|
|
456
444
|
|
|
457
|
-
const
|
|
458
|
-
|
|
445
|
+
const { publisher, subscriber } = await createPubSub(t, {
|
|
446
|
+
publisher: { clean: true },
|
|
447
|
+
subscriber: { clean: true }
|
|
448
|
+
})
|
|
459
449
|
|
|
460
|
-
const publisher = connect(setup(broker))
|
|
461
|
-
const subscriber = connect(setup(broker))
|
|
462
450
|
const expected = {
|
|
463
451
|
cmd: 'publish',
|
|
464
452
|
topic: 'hello',
|
|
@@ -469,7 +457,7 @@ test('deliver QoS 1 retained messages to new subscriptions', function (t) {
|
|
|
469
457
|
retain: true
|
|
470
458
|
}
|
|
471
459
|
|
|
472
|
-
publisher
|
|
460
|
+
await publish(t, publisher, {
|
|
473
461
|
cmd: 'publish',
|
|
474
462
|
topic: 'hello',
|
|
475
463
|
payload: 'world',
|
|
@@ -478,24 +466,17 @@ test('deliver QoS 1 retained messages to new subscriptions', function (t) {
|
|
|
478
466
|
retain: true
|
|
479
467
|
})
|
|
480
468
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
})
|
|
487
|
-
})
|
|
488
|
-
})
|
|
469
|
+
await delay(10) // give Aedes some time to process the publish
|
|
470
|
+
await subscribe(t, subscriber, 'hello', 1)
|
|
471
|
+
const packet = await nextPacket(subscriber)
|
|
472
|
+
delete packet.messageId
|
|
473
|
+
t.assert.deepEqual(structuredClone(packet), expected, 'packet must match')
|
|
489
474
|
})
|
|
490
475
|
|
|
491
|
-
test('deliver QoS 1 retained messages to established subscriptions',
|
|
476
|
+
test('deliver QoS 1 retained messages to established subscriptions', async (t) => {
|
|
492
477
|
t.plan(4)
|
|
493
478
|
|
|
494
|
-
const
|
|
495
|
-
t.teardown(broker.close.bind(broker))
|
|
496
|
-
|
|
497
|
-
const publisher = connect(setup(broker))
|
|
498
|
-
const subscriber = connect(setup(broker))
|
|
479
|
+
const { publisher, subscriber } = await createPubSub(t)
|
|
499
480
|
const expected = {
|
|
500
481
|
cmd: 'publish',
|
|
501
482
|
topic: 'hello',
|
|
@@ -506,30 +487,25 @@ test('deliver QoS 1 retained messages to established subscriptions', function (t
|
|
|
506
487
|
retain: false
|
|
507
488
|
}
|
|
508
489
|
|
|
509
|
-
subscribe(t, subscriber, 'hello', 1
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
qos: 1,
|
|
519
|
-
messageId: 42,
|
|
520
|
-
retain: true
|
|
521
|
-
})
|
|
490
|
+
await subscribe(t, subscriber, 'hello', 1)
|
|
491
|
+
|
|
492
|
+
publisher.inStream.write({
|
|
493
|
+
cmd: 'publish',
|
|
494
|
+
topic: 'hello',
|
|
495
|
+
payload: 'world',
|
|
496
|
+
qos: 1,
|
|
497
|
+
messageId: 42,
|
|
498
|
+
retain: true
|
|
522
499
|
})
|
|
500
|
+
const packet = await nextPacket(subscriber)
|
|
501
|
+
delete packet.messageId
|
|
502
|
+
t.assert.deepEqual(structuredClone(packet), expected, 'packet must match')
|
|
523
503
|
})
|
|
524
504
|
|
|
525
|
-
test('deliver QoS 0 retained message with QoS 1 subscription',
|
|
505
|
+
test('deliver QoS 0 retained message with QoS 1 subscription', async (t) => {
|
|
526
506
|
t.plan(4)
|
|
527
507
|
|
|
528
|
-
const broker =
|
|
529
|
-
t.teardown(broker.close.bind(broker))
|
|
530
|
-
|
|
531
|
-
const publisher = connect(setup(broker))
|
|
532
|
-
const subscriber = connect(setup(broker))
|
|
508
|
+
const { broker, publisher, subscriber } = await createPubSub(t)
|
|
533
509
|
const expected = {
|
|
534
510
|
cmd: 'publish',
|
|
535
511
|
topic: 'hello',
|
|
@@ -540,37 +516,45 @@ test('deliver QoS 0 retained message with QoS 1 subscription', function (t) {
|
|
|
540
516
|
retain: true
|
|
541
517
|
}
|
|
542
518
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
subscriber.outStream.once('data', function (packet) {
|
|
551
|
-
t.same(packet, expected, 'packet must match')
|
|
552
|
-
})
|
|
519
|
+
const checkOnBroker = async () => {
|
|
520
|
+
await new Promise(resolve => {
|
|
521
|
+
broker.mq.on('hello', (msg, cb) => {
|
|
522
|
+
cb()
|
|
523
|
+
// defer this or it will receive the message which
|
|
524
|
+
// is being published
|
|
525
|
+
resolve()
|
|
553
526
|
})
|
|
554
527
|
})
|
|
555
|
-
|
|
528
|
+
await subscribe(t, subscriber, 'hello', 1)
|
|
529
|
+
const packet = await nextPacket(subscriber)
|
|
530
|
+
t.assert.deepEqual(structuredClone(packet), expected, 'packet must match')
|
|
531
|
+
}
|
|
556
532
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
533
|
+
const doPublish = () => {
|
|
534
|
+
publisher.inStream.write({
|
|
535
|
+
cmd: 'publish',
|
|
536
|
+
topic: 'hello',
|
|
537
|
+
payload: Buffer.from('world'),
|
|
538
|
+
qos: 0,
|
|
539
|
+
messageId: 42,
|
|
540
|
+
retain: true
|
|
541
|
+
})
|
|
542
|
+
}
|
|
543
|
+
// run parallel
|
|
544
|
+
await Promise.all([
|
|
545
|
+
checkOnBroker(),
|
|
546
|
+
doPublish()
|
|
547
|
+
])
|
|
565
548
|
})
|
|
566
549
|
|
|
567
|
-
test('disconnect and retain messages with QoS 1 [clean=false]',
|
|
568
|
-
t.plan(
|
|
550
|
+
test('disconnect and retain messages with QoS 1 [clean=false]', async (t) => {
|
|
551
|
+
t.plan(8)
|
|
569
552
|
|
|
570
|
-
const broker =
|
|
571
|
-
|
|
553
|
+
const { broker, publisher, subscriber } = await createPubSub(t, {
|
|
554
|
+
publisher: { clean: false },
|
|
555
|
+
subscriber: { clean: false, clientId: 'abcde' }
|
|
556
|
+
})
|
|
572
557
|
|
|
573
|
-
let subscriber = noError(connect(setup(broker), { clean: false, clientId: 'abcde' }), t)
|
|
574
558
|
const expected = {
|
|
575
559
|
cmd: 'publish',
|
|
576
560
|
topic: 'hello',
|
|
@@ -581,56 +565,41 @@ test('disconnect and retain messages with QoS 1 [clean=false]', function (t) {
|
|
|
581
565
|
retain: true
|
|
582
566
|
}
|
|
583
567
|
|
|
584
|
-
subscribe(t, subscriber, 'hello', 1
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
subscriber.outStream.on('data', function (packet) {
|
|
590
|
-
console.log('original', packet)
|
|
591
|
-
})
|
|
592
|
-
|
|
593
|
-
const publisher = noError(connect(setup(broker)), t)
|
|
594
|
-
|
|
595
|
-
publisher.inStream.write({
|
|
596
|
-
cmd: 'publish',
|
|
597
|
-
topic: 'hello',
|
|
598
|
-
payload: 'world',
|
|
599
|
-
qos: 1,
|
|
600
|
-
messageId: 42,
|
|
601
|
-
retain: true
|
|
602
|
-
})
|
|
603
|
-
|
|
604
|
-
publisher.outStream.once('data', function (packet) {
|
|
605
|
-
t.equal(packet.cmd, 'puback')
|
|
606
|
-
|
|
607
|
-
subscriber = connect(setup(broker), { clean: false, clientId: 'abcde' }, function (connect) {
|
|
608
|
-
t.equal(connect.sessionPresent, true, 'session present is set to true')
|
|
609
|
-
})
|
|
568
|
+
await subscribe(t, subscriber, 'hello', 1)
|
|
569
|
+
subscriber.inStream.write({
|
|
570
|
+
cmd: 'disconnect'
|
|
571
|
+
})
|
|
610
572
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
// there should be no messages come from restored subscriptions
|
|
619
|
-
subscriber.outStream.once('data', function (packet) {
|
|
620
|
-
t.fail('should not receive any more messages')
|
|
621
|
-
})
|
|
622
|
-
})
|
|
623
|
-
})
|
|
573
|
+
await publish(t, publisher, {
|
|
574
|
+
cmd: 'publish',
|
|
575
|
+
topic: 'hello',
|
|
576
|
+
payload: 'world',
|
|
577
|
+
qos: 1,
|
|
578
|
+
messageId: 42,
|
|
579
|
+
retain: true
|
|
624
580
|
})
|
|
581
|
+
|
|
582
|
+
const subscriber2 = setup(broker)
|
|
583
|
+
const connack = await connect(subscriber2, { connect: { clean: false, clientId: 'abcde' } })
|
|
584
|
+
t.assert.equal(connack.sessionPresent, true, 'session present is set to true')
|
|
585
|
+
|
|
586
|
+
const packet = await nextPacket(subscriber2)
|
|
587
|
+
// receive any queued messages (no matter they are retained messages) at the disconnected time
|
|
588
|
+
t.assert.ok(packet.messageId !== 42, 'messageId must differ')
|
|
589
|
+
delete packet.messageId
|
|
590
|
+
packet.length = 14
|
|
591
|
+
t.assert.deepEqual(structuredClone(packet), expected, 'packet must match')
|
|
592
|
+
// expect no more packets
|
|
593
|
+
await checkNoPacket(t, subscriber2, 10)
|
|
625
594
|
})
|
|
626
595
|
|
|
627
|
-
test('disconnect and two retain messages with QoS 1 [clean=false]',
|
|
596
|
+
test('disconnect and two retain messages with QoS 1 [clean=false]', async (t) => {
|
|
628
597
|
t.plan(15)
|
|
629
598
|
|
|
630
|
-
const broker =
|
|
631
|
-
|
|
599
|
+
const { broker, publisher, subscriber } = await createPubSub(t, {
|
|
600
|
+
subscriber: { clean: false, clientId: 'abcde' }
|
|
601
|
+
})
|
|
632
602
|
|
|
633
|
-
let subscriber = noError(connect(setup(broker), { clean: false, clientId: 'abcde' }), t)
|
|
634
603
|
const expected = {
|
|
635
604
|
cmd: 'publish',
|
|
636
605
|
topic: 'hello',
|
|
@@ -640,74 +609,56 @@ test('disconnect and two retain messages with QoS 1 [clean=false]', function (t)
|
|
|
640
609
|
retain: true
|
|
641
610
|
}
|
|
642
611
|
|
|
643
|
-
subscribe(t, subscriber, 'hello', 1
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
subscriber.outStream.on('data', function (packet) {
|
|
649
|
-
console.log('original', packet)
|
|
650
|
-
})
|
|
651
|
-
|
|
652
|
-
const publisher = noError(connect(setup(broker)), t)
|
|
653
|
-
|
|
654
|
-
publisher.inStream.write({
|
|
655
|
-
cmd: 'publish',
|
|
656
|
-
topic: 'hello',
|
|
657
|
-
payload: 'world',
|
|
658
|
-
qos: 1,
|
|
659
|
-
messageId: 41,
|
|
660
|
-
retain: true
|
|
661
|
-
})
|
|
662
|
-
|
|
663
|
-
publisher.outStream.once('data', function (packet) {
|
|
664
|
-
t.equal(packet.cmd, 'puback')
|
|
612
|
+
await subscribe(t, subscriber, 'hello', 1)
|
|
613
|
+
await delay(10)
|
|
614
|
+
subscriber.inStream.write({
|
|
615
|
+
cmd: 'disconnect'
|
|
616
|
+
})
|
|
665
617
|
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
618
|
+
await publish(t, publisher, {
|
|
619
|
+
cmd: 'publish',
|
|
620
|
+
topic: 'hello',
|
|
621
|
+
payload: 'world',
|
|
622
|
+
qos: 1,
|
|
623
|
+
messageId: 41,
|
|
624
|
+
retain: true
|
|
625
|
+
})
|
|
674
626
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
subscriber.outStream.once('data', function (packet) {
|
|
683
|
-
// receive any queued messages (included retained messages) at the disconnected time
|
|
684
|
-
t.not(packet.messageId, 41, 'messageId must differ')
|
|
685
|
-
delete packet.messageId
|
|
686
|
-
packet.length = 14
|
|
687
|
-
expected.payload = Buffer.from('world')
|
|
688
|
-
t.same(packet, expected, 'packet must match')
|
|
689
|
-
|
|
690
|
-
// receive any queued messages (included retained messages) at the disconnected time
|
|
691
|
-
subscriber.outStream.once('data', function (packet) {
|
|
692
|
-
t.not(packet.messageId, 42, 'messageId must differ')
|
|
693
|
-
delete packet.messageId
|
|
694
|
-
packet.length = 14
|
|
695
|
-
expected.payload = Buffer.from('world2')
|
|
696
|
-
t.same(packet, expected, 'packet must match')
|
|
697
|
-
|
|
698
|
-
// should get the last retained message when we do a subscribe
|
|
699
|
-
subscribe(t, subscriber, 'hello', 1, function () {
|
|
700
|
-
subscriber.outStream.on('data', function (packet) {
|
|
701
|
-
t.not(packet.messageId, 42, 'messageId must differ')
|
|
702
|
-
delete packet.messageId
|
|
703
|
-
packet.length = 14
|
|
704
|
-
expected.payload = Buffer.from('world2')
|
|
705
|
-
t.same(packet, expected, 'packet must match')
|
|
706
|
-
})
|
|
707
|
-
})
|
|
708
|
-
})
|
|
709
|
-
})
|
|
710
|
-
})
|
|
711
|
-
})
|
|
627
|
+
await publish(t, publisher, {
|
|
628
|
+
cmd: 'publish',
|
|
629
|
+
topic: 'hello',
|
|
630
|
+
payload: 'world2',
|
|
631
|
+
qos: 1,
|
|
632
|
+
messageId: 42,
|
|
633
|
+
retain: true
|
|
712
634
|
})
|
|
635
|
+
|
|
636
|
+
const subscriber2 = setup(broker)
|
|
637
|
+
const connack = await connect(subscriber2, { connect: { clean: false, clientId: 'abcde' } })
|
|
638
|
+
t.assert.equal(connack.sessionPresent, true, 'session present is set to true')
|
|
639
|
+
|
|
640
|
+
const packet = await nextPacket(subscriber2)
|
|
641
|
+
// receive any queued messages (included retained messages) at the disconnected time
|
|
642
|
+
t.assert.ok(packet.messageId !== 41, 'messageId must differ')
|
|
643
|
+
delete packet.messageId
|
|
644
|
+
packet.length = 14
|
|
645
|
+
expected.payload = Buffer.from('world')
|
|
646
|
+
t.assert.deepEqual(structuredClone(packet), expected, 'packet must match')
|
|
647
|
+
|
|
648
|
+
// receive any queued messages (included retained messages) at the disconnected time
|
|
649
|
+
const packet2 = await nextPacket(subscriber2)
|
|
650
|
+
t.assert.ok(packet2.messageId !== 42, 'messageId must differ')
|
|
651
|
+
delete packet2.messageId
|
|
652
|
+
packet2.length = 14
|
|
653
|
+
expected.payload = Buffer.from('world2')
|
|
654
|
+
t.assert.deepEqual(structuredClone(packet2), expected, 'packet must match')
|
|
655
|
+
|
|
656
|
+
// should get the last retained message when we do a subscribe
|
|
657
|
+
await subscribe(t, subscriber2, 'hello', 1)
|
|
658
|
+
const packet3 = await nextPacket(subscriber2)
|
|
659
|
+
t.assert.ok(packet3.messageId !== 42, 'messageId must differ')
|
|
660
|
+
delete packet3.messageId
|
|
661
|
+
packet3.length = 14
|
|
662
|
+
expected.payload = Buffer.from('world2')
|
|
663
|
+
t.assert.deepEqual(structuredClone(packet3), expected, 'packet must match')
|
|
713
664
|
})
|