Skip to content

Commit

Permalink
fix: connect after client.end not working (#1902)
Browse files Browse the repository at this point in the history
* fix: publish after connect manually

* feat: add new cover tests

* fix: lint style

* feat: remove setTimeout from test

* feat: reduce indented in test

* feat: close clock and client after test
  • Loading branch information
MaximoLiberata authored Jul 17, 2024
1 parent cd0b044 commit fbe5294
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/lib/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,13 @@ export default class MqttClient extends TypedEventEmitter<MqttClientEventCallbac
this.log('connect :: calling method to clear reconnect')
this._clearReconnect()

if (this.disconnected && !this.reconnecting) {
this.incomingStore = this.options.incomingStore || new Store()
this.outgoingStore = this.options.outgoingStore || new Store()
this.disconnecting = false
this.disconnected = false
}

this.log(
'connect :: using streamBuilder provided to client to create stream',
)
Expand Down Expand Up @@ -1459,6 +1466,11 @@ export default class MqttClient extends TypedEventEmitter<MqttClientEventCallbac
})
if (this._deferredReconnect) {
this._deferredReconnect()
} else if (
this.options.reconnectPeriod === 0 ||
this.options.manualConnect
) {
this.disconnecting = false
}
}

Expand Down
166 changes: 166 additions & 0 deletions test/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,172 @@ describe('MqttClient', () => {
},
)

describe('connect manually', () => {
it(
'should not throw an error when publish after second connect',
{
timeout: 10000,
},
async function _test(t) {
const clock = useFakeTimers({
shouldClearNativeTimers: true,
toFake: ['setTimeout'],
})

t.after(async () => {
clock.restore()
if (client) {
await client.endAsync(true)
}
})

const fail = await new Promise<boolean>((resolveParent) => {
let countConnects = 0

const publishInterval = (
repetible: number,
timeout: number,
callback: (threwError: boolean) => void,
): void => {
const method = () =>
new Promise<boolean>((resolve) => {
client.publish('test', 'test', (err) => {
if (
err?.message.toLocaleLowerCase() ===
'client disconnecting'
) {
resolve(true)
} else {
resolve(false)
}
})
})

if (repetible <= 0) {
callback(false)
return
}

method().then((threwError) => {
clock.tick(timeout)

if (threwError) {
callback(true)
return
}

publishInterval(repetible - 1, timeout, callback)
})
}

client = mqtt.connect(config)

client.on('connect', () => {
++countConnects

const intervalRepetible = 4
const intervalTimeout = 250
const connectTimeout =
intervalRepetible * intervalTimeout

publishInterval(
intervalRepetible,
intervalTimeout,
(threwError) => {
if (countConnects === 2) {
resolveParent(threwError)
}
},
)

if (countConnects === 1) {
clock.setTimeout(() => {
client.end(() => client.connect())
}, connectTimeout)
}
})
})

assert.isFalse(fail, 'disconnecting variable was not reset')
},
)

it(
'reset disconnecting variable to false after disconnect when option reconnectPeriod=0',
{
timeout: 10000,
},
async function _test(t) {
client = await mqtt.connectAsync({
...config,
reconnectPeriod: 0,
})

assert.isFalse(
client.disconnecting,
'disconnecting should be false after connect',
)

const endPromise = client.endAsync()

assert.isTrue(
client.disconnecting,
'disconnecting should be true processing end',
)

await endPromise

assert.isFalse(
client.disconnecting,
'disconnecting should be false after end',
)
},
)

it(
'reset disconnecting variable to false after disconnect when option manualConnect=true',
{
timeout: 10000,
},
async function _test(t) {
client = mqtt.connect({
...config,
manualConnect: true,
})

await new Promise((resolve, reject) => {
client
.connect()
.on('error', (err) => {
reject(err)
})
.once('connect', () => {
resolve(undefined)
})
})

assert.isFalse(
client.disconnecting,
'disconnecting should be false after connect',
)

const endPromise = client.endAsync()

assert.isTrue(
client.disconnecting,
'disconnecting should be true processing end',
)

await endPromise

assert.isFalse(
client.disconnecting,
'disconnecting should be false after end',
)
},
)
})

describe('async methods', () => {
it(
'connect-subscribe-unsubscribe-end',
Expand Down

0 comments on commit fbe5294

Please sign in to comment.