matterbridge-roborock-vacuum-plugin
Version:
Matterbridge Roborock Vacuum Plugin
536 lines • 27.7 kB
JavaScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { createDefaultAdvancedFeature, } from '../../model/RoborockPluginPlatformConfig.js';
import { PlatformConfigManager } from '../../platform/platformConfigManager.js';
import { asPartial, asType } from '../helpers/testUtils.js';
function createMockLogger() {
return asType({
debug: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
notice: vi.fn(),
log: vi.fn(),
});
}
function createMockConfig(overrides = {}) {
return {
authentication: {
username: 'testuser',
region: 'US',
forceAuthentication: false,
authenticationMethod: 'Password',
password: 'pass',
},
pluginConfiguration: {
whiteList: [],
enableServerMode: false,
enableMultipleMap: false,
sanitizeSensitiveLogs: true,
refreshInterval: 60,
debug: false,
unregisterOnShutdown: false,
},
advancedFeature: createDefaultAdvancedFeature(),
...overrides,
};
}
describe('PlatformConfigManager', () => {
let mockLogger;
let config;
let manager;
beforeEach(() => {
mockLogger = createMockLogger();
config = createMockConfig();
manager = PlatformConfigManager.create(config, mockLogger);
});
afterEach(() => {
vi.clearAllMocks();
});
describe('validateConfig', () => {
it('should return true for valid config', () => {
expect(manager.validateConfig()).toBe(true);
});
it('should return false and log error if username is missing', () => {
config.authentication.username = '';
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.validateConfig()).toBe(false);
});
});
describe('validateAuthentication', () => {
it('should return true for valid password auth', () => {
expect(manager.validateAuthentication()).toBe(true);
});
it('should return false and log error if authentication is missing', () => {
config = asPartial({ ...config, authentication: undefined });
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.validateAuthentication()).toBe(false);
expect(mockLogger.error).toHaveBeenCalledWith('Platform config validation failed: "authentication" object is required');
});
it('should return false and log info if password is missing', () => {
config.authentication = asPartial({ authenticationMethod: 'Password' });
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.validateAuthentication()).toBe(false);
expect(mockLogger.info).toHaveBeenCalledWith('Platform config validation: password not provided');
});
it('should return false and log info if verificationCode is missing for VerificationCode method', () => {
config.authentication = asPartial({ authenticationMethod: 'VerificationCode' });
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.validateAuthentication()).toBe(false);
expect(mockLogger.info).toHaveBeenCalledWith('Platform config validation: verification code not provided');
});
it('should return true if verificationCode is present for VerificationCode method', () => {
config.authentication = asPartial({
authenticationMethod: 'VerificationCode',
verificationCode: '1234',
});
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.validateAuthentication()).toBe(true);
});
});
describe('getters', () => {
it('should return username, password, verificationCode, authenticationMethod', () => {
expect(manager.username).toBe('testuser');
expect(manager.password).toBe('pass');
expect(manager.verificationCode).toBe('');
expect(manager.authenticationMethod).toBe('Password');
});
it('should return region in uppercase or default to US', () => {
expect(manager.region).toBe('US');
config.authentication.region = 'EU';
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.region).toBe('EU');
});
it('should return refreshInterval or default', () => {
expect(manager.refreshInterval).toBe(60);
config.pluginConfiguration = asPartial({
...config.pluginConfiguration,
refreshInterval: undefined,
});
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.refreshInterval).toBeDefined();
});
it('should return unregisterOnShutdown, rawConfig', () => {
expect(manager.unregisterOnShutdown).toBe(false);
expect(manager.rawConfig).toBe(config);
});
});
describe('experimental features', () => {
it('should return experimental feature flags and settings', () => {
expect(manager.isAdvancedFeatureEnabled).toBe(manager.rawConfig.advancedFeature.enableAdvancedFeature);
expect(manager.advancedFeatureSettings).toBe(manager.rawConfig.advancedFeature.settings);
});
it('should return cleanModeSettings in all cases when enabled', () => {
expect(manager.cleanModeSettings).not.toBeUndefined();
config.advancedFeature.enableAdvancedFeature = true;
config.advancedFeature.settings = {
clearStorageOnStartup: false,
showRoutinesAsRoom: false,
forceRunAtDefault: false,
includeDockStationStatus: false,
includeVacuumErrorStatus: false,
enableCleanModeMapping: true,
useVacationModeToSendVacuumToDock: false,
cleanModeSettings: createDefaultAdvancedFeature().settings.cleanModeSettings,
overrideMatterConfiguration: false,
matterOverrideSettings: {
matterVendorName: 'xxx',
matterVendorId: 123,
matterProductName: 'yy',
matterProductId: 456,
},
enableEmailNotification: false,
emailNotificationSettings: {},
};
config.advancedFeature.enableAdvancedFeature = true;
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.cleanModeSettings).toBeDefined();
});
it('should return correct advanced feature flags', () => {
config.advancedFeature = {
enableAdvancedFeature: true,
settings: {
clearStorageOnStartup: true,
showRoutinesAsRoom: true,
forceRunAtDefault: true,
includeDockStationStatus: true,
includeVacuumErrorStatus: false,
enableCleanModeMapping: false,
useVacationModeToSendVacuumToDock: false,
cleanModeSettings: createDefaultAdvancedFeature().settings.cleanModeSettings,
overrideMatterConfiguration: false,
matterOverrideSettings: {
matterVendorName: 'xxx',
matterVendorId: 123,
matterProductName: 'yy',
matterProductId: 456,
},
enableEmailNotification: false,
emailNotificationSettings: {},
},
};
config.pluginConfiguration.enableServerMode = true;
config.pluginConfiguration.enableMultipleMap = false;
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.isServerModeEnabled).toBe(true);
expect(manager.isMultipleMapEnabled).toBe(false);
expect(manager.showRoutinesAsRoom).toBe(true);
expect(manager.forceRunAtDefault).toBe(true);
expect(manager.alwaysExecuteAuthentication).toBe(false);
expect(manager.includeDockStationStatus).toBe(true);
});
it('should return includeVacuumErrorStatus from settings when advanced feature is enabled', () => {
config.advancedFeature = {
enableAdvancedFeature: true,
settings: { ...createDefaultAdvancedFeature().settings, includeVacuumErrorStatus: true },
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.includeVacuumErrorStatus).toBe(true);
});
it('should return false for includeVacuumErrorStatus when advanced feature is disabled', () => {
config.advancedFeature = {
enableAdvancedFeature: false,
settings: { ...createDefaultAdvancedFeature().settings, includeVacuumErrorStatus: true },
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.includeVacuumErrorStatus).toBe(false);
});
it('should return false for useVacationModeToSendVacuumToDock when advanced feature is disabled', () => {
config.advancedFeature = {
enableAdvancedFeature: false,
settings: { ...createDefaultAdvancedFeature().settings, useVacationModeToSendVacuumToDock: true },
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.useVacationModeToSendVacuumToDock).toBe(false);
});
it('should return true for useVacationModeToSendVacuumToDock when advanced feature is enabled', () => {
config.advancedFeature = {
enableAdvancedFeature: true,
settings: { ...createDefaultAdvancedFeature().settings, useVacationModeToSendVacuumToDock: true },
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.useVacationModeToSendVacuumToDock).toBe(true);
});
it('should return false for overrideMatterConfiguration when advanced feature is disabled', () => {
config.advancedFeature = {
enableAdvancedFeature: false,
settings: { ...createDefaultAdvancedFeature().settings, overrideMatterConfiguration: true },
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.overrideMatterConfiguration).toBe(false);
});
it('should return true for overrideMatterConfiguration when advanced feature is enabled', () => {
config.advancedFeature = {
enableAdvancedFeature: true,
settings: { ...createDefaultAdvancedFeature().settings, overrideMatterConfiguration: true },
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.overrideMatterConfiguration).toBe(true);
});
it('should return custom matterOverrideSettings when advanced feature is enabled and override is true', () => {
const customSettings = {
matterVendorName: 'MyVendor',
matterVendorId: 9999,
matterProductName: 'MyProduct',
matterProductId: 8888,
};
config.advancedFeature = {
enableAdvancedFeature: true,
settings: {
...createDefaultAdvancedFeature().settings,
overrideMatterConfiguration: true,
matterOverrideSettings: customSettings,
},
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.matterOverrideSettings).toEqual(customSettings);
});
it('should return default matterOverrideSettings when advanced feature is disabled', () => {
config.advancedFeature = {
enableAdvancedFeature: false,
settings: { ...createDefaultAdvancedFeature().settings, overrideMatterConfiguration: true },
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.matterOverrideSettings).toBeDefined();
});
it('should return default matterOverrideSettings when overrideMatterConfiguration is false', () => {
config.advancedFeature = {
enableAdvancedFeature: true,
settings: { ...createDefaultAdvancedFeature().settings, overrideMatterConfiguration: false },
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.matterOverrideSettings).toBeDefined();
});
it('should return default matterOverrideSettings when enabled+override but matterOverrideSettings is null', () => {
config.advancedFeature = {
enableAdvancedFeature: true,
settings: {
...createDefaultAdvancedFeature().settings,
overrideMatterConfiguration: true,
matterOverrideSettings: null,
},
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.matterOverrideSettings).toBeDefined();
});
it('should return false for isClearStorageOnStartupEnabled when advanced feature is disabled', () => {
config.advancedFeature = {
enableAdvancedFeature: false,
settings: { ...createDefaultAdvancedFeature().settings, clearStorageOnStartup: true },
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.isClearStorageOnStartupEnabled).toBe(false);
});
it('should return true for isClearStorageOnStartupEnabled when advanced feature is enabled', () => {
config.advancedFeature = {
enableAdvancedFeature: true,
settings: { ...createDefaultAdvancedFeature().settings, clearStorageOnStartup: true },
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.isClearStorageOnStartupEnabled).toBe(true);
});
it('should return false for isCustomCleanModeMappingEnabled when advanced feature is disabled', () => {
config.advancedFeature = {
enableAdvancedFeature: false,
settings: { ...createDefaultAdvancedFeature().settings, enableCleanModeMapping: true },
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.isCustomCleanModeMappingEnabled).toBe(false);
});
describe('getProductNameForDevice', () => {
it('should return undefined when advanced feature is disabled', () => {
config.advancedFeature = {
enableAdvancedFeature: false,
settings: {
...createDefaultAdvancedFeature().settings,
overrideMatterConfiguration: true,
matterOverrideSettings: {
...createDefaultAdvancedFeature().settings.matterOverrideSettings,
deviceProductNames: [{ serialNumber: 'SN123', productName: 'My Vacuum' }],
},
},
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.getProductNameForDevice('SN123')).toBeUndefined();
});
it('should return undefined when overrideMatterConfiguration is false', () => {
config.advancedFeature = {
enableAdvancedFeature: true,
settings: {
...createDefaultAdvancedFeature().settings,
overrideMatterConfiguration: false,
matterOverrideSettings: {
...createDefaultAdvancedFeature().settings.matterOverrideSettings,
deviceProductNames: [{ serialNumber: 'SN123', productName: 'My Vacuum' }],
},
},
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.getProductNameForDevice('SN123')).toBeUndefined();
});
it('should return undefined when serial number does not match', () => {
config.advancedFeature = {
enableAdvancedFeature: true,
settings: {
...createDefaultAdvancedFeature().settings,
overrideMatterConfiguration: true,
matterOverrideSettings: {
...createDefaultAdvancedFeature().settings.matterOverrideSettings,
deviceProductNames: [{ serialNumber: 'SN123', productName: 'My Vacuum' }],
},
},
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.getProductNameForDevice('SN999')).toBeUndefined();
});
it('should return per-device product name when serial number matches', () => {
config.advancedFeature = {
enableAdvancedFeature: true,
settings: {
...createDefaultAdvancedFeature().settings,
overrideMatterConfiguration: true,
matterOverrideSettings: {
...createDefaultAdvancedFeature().settings.matterOverrideSettings,
deviceProductNames: [
{ serialNumber: 'SN123', productName: 'Living Room Vacuum' },
{ serialNumber: 'SN456', productName: 'Bedroom Vacuum' },
],
},
},
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.getProductNameForDevice('SN123')).toBe('Living Room Vacuum');
expect(manager.getProductNameForDevice('SN456')).toBe('Bedroom Vacuum');
});
it('should return undefined when deviceProductNames is empty', () => {
config.advancedFeature = {
enableAdvancedFeature: true,
settings: {
...createDefaultAdvancedFeature().settings,
overrideMatterConfiguration: true,
matterOverrideSettings: {
...createDefaultAdvancedFeature().settings.matterOverrideSettings,
deviceProductNames: [],
},
},
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.getProductNameForDevice('SN123')).toBeUndefined();
});
it('should return undefined when deviceProductNames is not set', () => {
config.advancedFeature = {
enableAdvancedFeature: true,
settings: {
...createDefaultAdvancedFeature().settings,
overrideMatterConfiguration: true,
matterOverrideSettings: {
matterVendorName: 'Matterbridge',
matterVendorId: 65521,
matterProductName: 'Default Vacuum',
matterProductId: 32768,
},
},
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.getProductNameForDevice('SN123')).toBeUndefined();
});
});
describe('ensureDeviceProductNameEntry', () => {
beforeEach(() => {
config.advancedFeature = {
enableAdvancedFeature: true,
settings: {
...createDefaultAdvancedFeature().settings,
overrideMatterConfiguration: true,
matterOverrideSettings: {
...createDefaultAdvancedFeature().settings.matterOverrideSettings,
deviceProductNames: [],
},
},
};
manager = PlatformConfigManager.create(config, mockLogger);
});
it('should return false when advanced feature is disabled', () => {
config.advancedFeature.enableAdvancedFeature = false;
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.ensureDeviceProductNameEntry('SN123', 'Vacuum Model')).toBe(false);
});
it('should return false when overrideMatterConfiguration is false', () => {
config.advancedFeature.settings.overrideMatterConfiguration = false;
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.ensureDeviceProductNameEntry('SN123', 'Vacuum Model')).toBe(false);
});
it('should return false when matterOverrideSettings is undefined', () => {
config.advancedFeature = {
enableAdvancedFeature: true,
settings: {
...createDefaultAdvancedFeature().settings,
overrideMatterConfiguration: true,
matterOverrideSettings: undefined,
},
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.ensureDeviceProductNameEntry('SN123', 'Vacuum Model')).toBe(false);
});
it('should add entry and return true when serial number not present', () => {
const result = manager.ensureDeviceProductNameEntry('SN123', 'Vacuum Model');
expect(result).toBe(true);
expect(manager.getProductNameForDevice('SN123')).toBe('Vacuum Model');
});
it('should return false and not duplicate when entry already exists', () => {
manager.ensureDeviceProductNameEntry('SN123', 'Vacuum Model');
const result = manager.ensureDeviceProductNameEntry('SN123', 'Other Name');
expect(result).toBe(false);
expect(manager.getProductNameForDevice('SN123')).toBe('Vacuum Model');
});
it('should add multiple entries for different serial numbers', () => {
manager.ensureDeviceProductNameEntry('SN123', 'Living Room');
manager.ensureDeviceProductNameEntry('SN456', 'Bedroom');
expect(manager.getProductNameForDevice('SN123')).toBe('Living Room');
expect(manager.getProductNameForDevice('SN456')).toBe('Bedroom');
});
});
});
describe('email notification', () => {
it('should return false for isEmailNotificationEnabled when advanced feature is disabled', () => {
config.advancedFeature = {
enableAdvancedFeature: false,
settings: { ...createDefaultAdvancedFeature().settings, enableEmailNotification: true },
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.isEmailNotificationEnabled).toBe(false);
});
it('should return false for isEmailNotificationEnabled when enabled flag is false', () => {
config.advancedFeature = {
enableAdvancedFeature: true,
settings: { ...createDefaultAdvancedFeature().settings, enableEmailNotification: false },
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.isEmailNotificationEnabled).toBe(false);
});
it('should return true for isEmailNotificationEnabled when advanced feature and email are both enabled', () => {
config.advancedFeature = {
enableAdvancedFeature: true,
settings: { ...createDefaultAdvancedFeature().settings, enableEmailNotification: true },
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.isEmailNotificationEnabled).toBe(true);
});
it('should return undefined for emailNotificationSettings when email notification is disabled', () => {
config.advancedFeature = {
enableAdvancedFeature: false,
settings: {
...createDefaultAdvancedFeature().settings,
enableEmailNotification: true,
emailNotificationSettings: {
smtpHost: 'smtp.example.com',
smtpUser: 'u',
smtpPassword: 'p',
recipient: 'r@r.com',
},
},
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.emailNotificationSettings).toBeUndefined();
});
it('should return emailNotificationSettings when email notification is enabled', () => {
const emailSettings = {
smtpHost: 'smtp.example.com',
smtpPort: 587,
smtpUser: 'user@example.com',
smtpPassword: 'secret',
recipient: 'alert@example.com',
};
config.advancedFeature = {
enableAdvancedFeature: true,
settings: {
...createDefaultAdvancedFeature().settings,
enableEmailNotification: true,
emailNotificationSettings: emailSettings,
},
};
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.emailNotificationSettings).toEqual(emailSettings);
});
});
describe('device filtering', () => {
it('should allow device if whitelist is empty', () => {
expect(manager.isDeviceAllowed({ duid: 'abc' })).toBe(true);
});
it('should allow device if whitelisted by duid', () => {
config.pluginConfiguration.whiteList = ['abc'];
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.isDeviceAllowed({ duid: 'abc' })).toBe(true);
});
it('should deny device if duid is not in whitelist', () => {
config.pluginConfiguration.whiteList = ['abc'];
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.isDeviceAllowed({ duid: 'xyz' })).toBe(false);
});
it('should deny device if whitelist has entries but duid is undefined', () => {
config.pluginConfiguration.whiteList = ['abc'];
manager = PlatformConfigManager.create(config, mockLogger);
expect(manager.isDeviceAllowed({})).toBe(false);
});
});
});
//# sourceMappingURL=platformConfig.test.js.map