fix: Do not call start() on extensions twice when starting (#27032)

This commit is contained in:
[pʲɵs]
2025-04-09 21:31:33 +02:00
committed by GitHub
parent 850f0820ac
commit 7fb10b1dcb
3 changed files with 23 additions and 3 deletions
+2 -1
View File
@@ -144,7 +144,8 @@ export class Controller {
return await this.exit(1);
}
for (const extension of this.extensions) {
// copy current Set of extensions to ignore possible external extensions added while looping
for (const extension of new Set(this.extensions)) {
await this.startExtension(extension);
}
@@ -2,13 +2,16 @@ export default class Example {
constructor(zigbee, mqtt, state, publishEntityState, eventBus) {
this.mqtt = mqtt;
this.mqtt.publish('example/extension', 'call from constructor');
this.counter = 0;
}
start() {
this.mqtt.publish('example/extension', 'call from start');
this.mqtt.publish('example/extension/counter', `start ${this.counter++}`);
}
stop() {
this.mqtt.publish('example/extension', 'call from stop');
this.mqtt.publish('example/extension/counter', `stop ${--this.counter}`);
}
}
+18 -2
View File
@@ -126,6 +126,16 @@ describe('Extension: ExternalExtensions', () => {
);
});
it('starts extensions only once', async () => {
useAssets('mjs');
await controller.start();
await flushPromises();
expect(mockMQTTPublishAsync).toHaveBeenCalledWith('zigbee2mqtt/example/extension/counter', 'start 0', {retain: false, qos: 0});
expect(mockMQTTPublishAsync).not.toHaveBeenCalledWith('zigbee2mqtt/example/extension/counter', 'start 1', {retain: false, qos: 0});
});
it('loads all valid extensions, relocates & skips ones with errors', async () => {
useAssets('mjs');
@@ -169,7 +179,9 @@ describe('Extension: ExternalExtensions', () => {
{retain: true, qos: 0},
);
extensionCode = extensionCode.replace("'call from start'", "'call from start - edited'");
extensionCode = extensionCode
.replace("'call from start'", "'call from start - edited'")
.replace("'call from stop'", "'call from stop - edited'");
mockMQTTPublishAsync.mockClear();
await (controller.getExtension('ExternalExtensions')! as ExternalExtensions).onMQTTMessage({
@@ -177,6 +189,7 @@ describe('Extension: ExternalExtensions', () => {
message: {name: extensionName, code: extensionCode},
});
expect(mockMQTTPublishAsync).toHaveBeenCalledWith('zigbee2mqtt/example/extension', 'call from stop', {retain: false, qos: 0});
expect(mockMQTTPublishAsync).toHaveBeenCalledWith('zigbee2mqtt/example/extension', 'call from start - edited', {retain: false, qos: 0});
expect(mockMQTTPublishAsync).toHaveBeenCalledWith(
'zigbee2mqtt/bridge/extensions',
@@ -187,7 +200,9 @@ describe('Extension: ExternalExtensions', () => {
{retain: true, qos: 0},
);
extensionCode = extensionCode.replace("'call from start - edited'", "'call from start'");
extensionCode = extensionCode
.replace("'call from start - edited'", "'call from start'")
.replace("'call from stop - edited'", "'call from stop'");
mockMQTTPublishAsync.mockClear();
await (controller.getExtension('ExternalExtensions')! as ExternalExtensions).onMQTTMessage({
@@ -195,6 +210,7 @@ describe('Extension: ExternalExtensions', () => {
message: {name: 'exampleExtension.1.js', code: extensionCode},
});
expect(mockMQTTPublishAsync).toHaveBeenCalledWith('zigbee2mqtt/example/extension', 'call from stop - edited', {retain: false, qos: 0});
expect(mockMQTTPublishAsync).toHaveBeenCalledWith('zigbee2mqtt/example/extension', 'call from start', {retain: false, qos: 0});
expect(mockMQTTPublishAsync).toHaveBeenCalledWith(
'zigbee2mqtt/bridge/extensions',