refactor: Refactor entity register manager (#1597)
This commit is contained in:
@@ -2,10 +2,10 @@ import { describe, expect, it } from 'vitest';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import { BrowseMediaCamera } from '../../../src/camera-manager/browse-media/camera';
|
||||
import { CameraManagerEngine } from '../../../src/camera-manager/engine';
|
||||
import { EntityRegistryManager } from '../../../src/utils/ha/entity-registry';
|
||||
import { Entity } from '../../../src/utils/ha/entity-registry/types';
|
||||
import { createCameraConfig, createHASS } from '../../test-utils';
|
||||
import { StateWatcherSubscriptionInterface } from '../../../src/card-controller/hass/state-watcher';
|
||||
import { EntityRegistryManager } from '../../../src/utils/ha/registry/entity';
|
||||
import { Entity } from '../../../src/utils/ha/registry/entity/types';
|
||||
import { createCameraConfig, createHASS } from '../../test-utils';
|
||||
|
||||
describe('BrowseMediaCamera', () => {
|
||||
describe('should initialize', () => {
|
||||
|
||||
@@ -7,8 +7,10 @@ import { MotionEyeCameraManagerEngine } from '../../src/camera-manager/motioneye
|
||||
import { Engine } from '../../src/camera-manager/types.js';
|
||||
import { StateWatcherSubscriptionInterface } from '../../src/card-controller/hass/state-watcher.js';
|
||||
import { CardWideConfig } from '../../src/config/types.js';
|
||||
import { EntityRegistryManager } from '../../src/utils/ha/entity-registry';
|
||||
import { EntityCache } from '../../src/utils/ha/entity-registry/cache';
|
||||
import {
|
||||
createEntityRegistryCache,
|
||||
EntityRegistryManager,
|
||||
} from '../../src/utils/ha/registry/entity/index.js';
|
||||
import { ResolvedMediaCache } from '../../src/utils/ha/resolved-media';
|
||||
import {
|
||||
createCameraConfig,
|
||||
@@ -25,7 +27,8 @@ const createFactory = (options?: {
|
||||
cardWideConfig?: CardWideConfig;
|
||||
}): CameraManagerEngineFactory => {
|
||||
return new CameraManagerEngineFactory(
|
||||
options?.entityRegistryManager ?? new EntityRegistryManager(new EntityCache()),
|
||||
options?.entityRegistryManager ??
|
||||
new EntityRegistryManager(createEntityRegistryCache()),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -40,7 +43,9 @@ describe('getEngineForCamera()', () => {
|
||||
|
||||
it('from auto detection', async () => {
|
||||
const config = createCameraConfig({ engine: 'auto', camera_entity: 'camera.foo' });
|
||||
const entityRegistryManager = new EntityRegistryManager(new EntityCache());
|
||||
const entityRegistryManager = new EntityRegistryManager(
|
||||
createEntityRegistryCache(),
|
||||
);
|
||||
|
||||
entityRegistryManager.getEntity = vi
|
||||
.fn()
|
||||
@@ -75,7 +80,9 @@ describe('getEngineForCamera()', () => {
|
||||
|
||||
it('from auto detection', async () => {
|
||||
const config = createCameraConfig({ engine: 'auto', camera_entity: 'camera.foo' });
|
||||
const entityRegistryManager = new EntityRegistryManager(new EntityCache());
|
||||
const entityRegistryManager = new EntityRegistryManager(
|
||||
createEntityRegistryCache(),
|
||||
);
|
||||
|
||||
entityRegistryManager.getEntity = vi
|
||||
.fn()
|
||||
@@ -101,7 +108,9 @@ describe('getEngineForCamera()', () => {
|
||||
|
||||
it('from auto detection', async () => {
|
||||
const config = createCameraConfig({ engine: 'auto', camera_entity: 'camera.foo' });
|
||||
const entityRegistryManager = new EntityRegistryManager(new EntityCache());
|
||||
const entityRegistryManager = new EntityRegistryManager(
|
||||
createEntityRegistryCache(),
|
||||
);
|
||||
|
||||
entityRegistryManager.getEntity = vi
|
||||
.fn()
|
||||
@@ -121,9 +130,11 @@ describe('getEngineForCamera()', () => {
|
||||
engine: 'auto',
|
||||
webrtc_card: { entity: 'camera.foo' },
|
||||
});
|
||||
const entityRegistryManager = new EntityRegistryManager(new EntityCache());
|
||||
const entityRegistryManager = new EntityRegistryManager(
|
||||
createEntityRegistryCache(),
|
||||
);
|
||||
|
||||
entityRegistryManager.getEntity = vi.fn().mockRejectedValue(new Error());
|
||||
entityRegistryManager.getEntity = vi.fn().mockResolvedValue(null);
|
||||
|
||||
expect(
|
||||
await createFactory({
|
||||
@@ -137,6 +148,24 @@ describe('getEngineForCamera()', () => {
|
||||
).toBe(Engine.Generic);
|
||||
});
|
||||
|
||||
it('from entity not in registry and not in state', async () => {
|
||||
const config = createCameraConfig({
|
||||
engine: 'auto',
|
||||
webrtc_card: { entity: 'camera.foo' },
|
||||
});
|
||||
const entityRegistryManager = new EntityRegistryManager(
|
||||
createEntityRegistryCache(),
|
||||
);
|
||||
entityRegistryManager.getEntity = vi.fn().mockResolvedValue(null);
|
||||
|
||||
expect(
|
||||
async () =>
|
||||
await createFactory({
|
||||
entityRegistryManager: entityRegistryManager,
|
||||
}).getEngineForCamera(createHASS(), config),
|
||||
).rejects.toThrow(/Could not find camera entity/);
|
||||
});
|
||||
|
||||
it('from webrtc-card url', async () => {
|
||||
const config = createCameraConfig({
|
||||
engine: 'auto',
|
||||
@@ -167,7 +196,7 @@ describe('getEngineForCamera()', () => {
|
||||
|
||||
it('should throw error on invalid entity', async () => {
|
||||
const config = createCameraConfig({ engine: 'auto', camera_entity: 'camera.foo' });
|
||||
const entityRegistryManager = new EntityRegistryManager(new EntityCache());
|
||||
const entityRegistryManager = new EntityRegistryManager(createEntityRegistryCache());
|
||||
|
||||
entityRegistryManager.getEntity = vi.fn().mockRejectedValue(new Error());
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import { getPTZInfo } from '../../../src/camera-manager/frigate/requests';
|
||||
import { FrigateEventChange } from '../../../src/camera-manager/frigate/types';
|
||||
import { StateWatcher } from '../../../src/card-controller/hass/state-watcher';
|
||||
import { CameraTriggerEventType } from '../../../src/config/types';
|
||||
import { EntityRegistryManager } from '../../../src/utils/ha/entity-registry';
|
||||
import { Entity } from '../../../src/utils/ha/entity-registry/types';
|
||||
import { EntityRegistryManager } from '../../../src/utils/ha/registry/entity';
|
||||
import { Entity } from '../../../src/utils/ha/registry/entity/types';
|
||||
import { createCameraConfig, createHASS, createRegistryEntity } from '../../test-utils';
|
||||
|
||||
vi.mock('../../../src/camera-manager/frigate/requests');
|
||||
@@ -54,7 +54,7 @@ describe('FrigateCamera', () => {
|
||||
mock<CameraManagerEngine>(),
|
||||
);
|
||||
const entityRegistryManager = mock<EntityRegistryManager>();
|
||||
entityRegistryManager.getEntity.mockRejectedValue(null);
|
||||
entityRegistryManager.getEntity.mockResolvedValue(null);
|
||||
|
||||
expect(
|
||||
async () =>
|
||||
|
||||
@@ -5,10 +5,10 @@ import { Capabilities } from '../../src/camera-manager/capabilities.js';
|
||||
import { CameraManagerEngineFactory } from '../../src/camera-manager/engine-factory.js';
|
||||
import { CameraManagerStore } from '../../src/camera-manager/store.js';
|
||||
import { Engine } from '../../src/camera-manager/types.js';
|
||||
import { EntityRegistryManager } from '../../src/utils/ha/entity-registry/index.js';
|
||||
import { StateWatcherSubscriptionInterface } from '../../src/card-controller/hass/state-watcher.js';
|
||||
import { EntityRegistryManager } from '../../src/utils/ha/registry/entity/index.js';
|
||||
import { ResolvedMediaCache } from '../../src/utils/ha/resolved-media.js';
|
||||
import { TestViewMedia, createCameraConfig } from '../test-utils.js';
|
||||
import { StateWatcherSubscriptionInterface } from '../../src/card-controller/hass/state-watcher.js';
|
||||
|
||||
describe('CameraManagerStore', async () => {
|
||||
const configVisible = createCameraConfig({
|
||||
|
||||
@@ -28,7 +28,7 @@ import { StyleManager } from '../../src/card-controller/style-manager';
|
||||
import { TriggersManager } from '../../src/card-controller/triggers-manager';
|
||||
import { ViewManager } from '../../src/card-controller/view/view-manager';
|
||||
import { FrigateCardEditor } from '../../src/editor';
|
||||
import { EntityRegistryManager } from '../../src/utils/ha/entity-registry';
|
||||
import { EntityRegistryManager } from '../../src/utils/ha/registry/entity';
|
||||
import { ResolvedMediaCache } from '../../src/utils/ha/resolved-media';
|
||||
|
||||
vi.mock('../../src/camera-manager/manager');
|
||||
@@ -55,7 +55,7 @@ vi.mock('../../src/card-controller/status-bar-item-manager');
|
||||
vi.mock('../../src/card-controller/style-manager');
|
||||
vi.mock('../../src/card-controller/triggers-manager');
|
||||
vi.mock('../../src/card-controller/view/view-manager');
|
||||
vi.mock('../../src/utils/ha/entity-registry');
|
||||
vi.mock('../../src/utils/ha/registry/entity');
|
||||
vi.mock('../../src/utils/ha/resolved-media');
|
||||
|
||||
const createCardElement = (): CardHTMLElement => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { mock } from 'vitest-mock-extended';
|
||||
import { MediaPlayerManager } from '../../src/card-controller/media-player-manager';
|
||||
import { MEDIA_PLAYER_SUPPORT_BROWSE_MEDIA } from '../../src/const';
|
||||
import { ExtendedHomeAssistant } from '../../src/types';
|
||||
import { EntityRegistryManager } from '../../src/utils/ha/entity-registry';
|
||||
import { EntityRegistryManager } from '../../src/utils/ha/registry/entity';
|
||||
import {
|
||||
createCameraConfig,
|
||||
createCameraManager,
|
||||
|
||||
+2
-2
@@ -55,8 +55,8 @@ import {
|
||||
} from '../src/config/types';
|
||||
import { CapabilitiesRaw, ExtendedHomeAssistant, MediaLoadedInfo } from '../src/types';
|
||||
import { HassStateDifference } from '../src/utils/ha';
|
||||
import { EntityRegistryManager } from '../src/utils/ha/entity-registry';
|
||||
import { Entity } from '../src/utils/ha/entity-registry/types';
|
||||
import { EntityRegistryManager } from '../src/utils/ha/registry/entity';
|
||||
import { Entity } from '../src/utils/ha/registry/entity/types';
|
||||
import { ViewMedia, ViewMediaType } from '../src/view/media';
|
||||
import { MediaQueriesResults } from '../src/view/media-queries-results';
|
||||
import { View, ViewParameters } from '../src/view/view';
|
||||
|
||||
@@ -2,7 +2,7 @@ import { HassConfig } from 'home-assistant-js-websocket';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { getLanguage } from '../../src/localize/localize';
|
||||
import { getDiagnostics, getReleaseVersion } from '../../src/utils/diagnostics.js';
|
||||
import { getAllDevices } from '../../src/utils/ha/device-registry.js';
|
||||
import { getAllDevices } from '../../src/utils/ha/registry/device/index.js';
|
||||
import { createHASS } from '../test-utils';
|
||||
|
||||
vi.mock('../../package.json', () => ({
|
||||
@@ -14,7 +14,7 @@ vi.mock('../../package.json', () => ({
|
||||
}));
|
||||
vi.mock('../../src/utils/ha');
|
||||
vi.mock('../../src/localize/localize.js');
|
||||
vi.mock('../../src/utils/ha/device-registry');
|
||||
vi.mock('../../src/utils/ha/registry/device/index.js');
|
||||
|
||||
describe('getReleaseVersion', () => {
|
||||
it('should get release version', () => {
|
||||
@@ -37,6 +37,7 @@ describe('getDiagnostics', () => {
|
||||
|
||||
vi.mocked(getAllDevices).mockResolvedValue([
|
||||
{
|
||||
id: 'id',
|
||||
model: '4.0.0/0.13.0-aded314',
|
||||
config_entries: [
|
||||
'ac4e79d258449a83bc0cf6d47a021c46',
|
||||
@@ -97,6 +98,7 @@ describe('getDiagnostics', () => {
|
||||
it('should fetch diagnostics without device model', async () => {
|
||||
vi.mocked(getAllDevices).mockResolvedValue([
|
||||
{
|
||||
id: 'id',
|
||||
model: null,
|
||||
config_entries: [
|
||||
'ac4e79d258449a83bc0cf6d47a021c46',
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { RegistryCache } from '../../../../src/utils/ha/registry/cache';
|
||||
|
||||
interface TestCacheValue {
|
||||
id: string;
|
||||
val?: number;
|
||||
}
|
||||
|
||||
describe('RegistryCache', () => {
|
||||
describe('has', () => {
|
||||
it('positive', () => {
|
||||
const cache = new RegistryCache<TestCacheValue>((arg) => arg.id);
|
||||
cache.add({ id: 'test' });
|
||||
expect(cache.has('test')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('negative', () => {
|
||||
const cache = new RegistryCache<TestCacheValue>((arg) => arg.id);
|
||||
cache.add({ id: 'test' });
|
||||
expect(cache.has('absent')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
it('getMatches', () => {
|
||||
const cache = new RegistryCache<TestCacheValue>((arg) => arg.id);
|
||||
cache.add([
|
||||
{ id: 'test-1', val: 1 },
|
||||
{ id: 'test-5', val: 5 },
|
||||
{ id: 'test-8', val: 8 },
|
||||
]);
|
||||
expect(cache.getMatches((obj) => !!obj.val && obj.val >= 5)).toEqual([
|
||||
{ id: 'test-5', val: 5 },
|
||||
{ id: 'test-8', val: 8 },
|
||||
]);
|
||||
});
|
||||
|
||||
describe('get', () => {
|
||||
it('positive', () => {
|
||||
const cache = new RegistryCache<TestCacheValue>((arg) => arg.id);
|
||||
cache.add({ id: 'test', val: 42 });
|
||||
expect(cache.get('test')).toEqual({ id: 'test', val: 42 });
|
||||
});
|
||||
|
||||
it('negative', () => {
|
||||
const cache = new RegistryCache<TestCacheValue>((arg) => arg.id);
|
||||
expect(cache.get('test')).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,110 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { homeAssistantWSRequest } from '../../../../../src/utils/ha';
|
||||
import {
|
||||
createEntityRegistryCache,
|
||||
EntityRegistryManager,
|
||||
} from '../../../../../src/utils/ha/registry/entity';
|
||||
import { createHASS, createRegistryEntity } from '../../../../test-utils.js';
|
||||
|
||||
vi.mock('../../../../../src/utils/ha');
|
||||
|
||||
describe('EntityRegistryManager', () => {
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('getEntity', () => {
|
||||
it('should not fetch when cached', async () => {
|
||||
const cache = createEntityRegistryCache();
|
||||
const testEntity = createRegistryEntity({ entity_id: 'test' });
|
||||
|
||||
cache.add(testEntity);
|
||||
|
||||
const manager = new EntityRegistryManager(cache);
|
||||
expect(await manager.getEntity(createHASS(), 'test')).toEqual(testEntity);
|
||||
|
||||
expect(homeAssistantWSRequest).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should fetch and cache when not cached', async () => {
|
||||
const testEntity = createRegistryEntity({ entity_id: 'test' });
|
||||
|
||||
const manager = new EntityRegistryManager(createEntityRegistryCache());
|
||||
vi.mocked(homeAssistantWSRequest).mockResolvedValueOnce(testEntity);
|
||||
|
||||
expect(await manager.getEntity(createHASS(), 'test')).toEqual(testEntity);
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
|
||||
expect(await manager.getEntity(createHASS(), 'test')).toEqual(testEntity);
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should return null when entity does not exist', async () => {
|
||||
vi.mocked(homeAssistantWSRequest).mockRejectedValueOnce(new Error('Not found'));
|
||||
|
||||
const manager = new EntityRegistryManager(createEntityRegistryCache());
|
||||
expect(await manager.getEntity(createHASS(), 'missing')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it('getEntities', () => {
|
||||
const cachedEntity = createRegistryEntity({ entity_id: 'cached' });
|
||||
const notCachedEntity = createRegistryEntity({ entity_id: 'not-cached' });
|
||||
|
||||
const cache = createEntityRegistryCache();
|
||||
cache.add(cachedEntity);
|
||||
|
||||
const manager = new EntityRegistryManager(cache);
|
||||
vi.mocked(homeAssistantWSRequest).mockResolvedValueOnce(notCachedEntity);
|
||||
vi.mocked(homeAssistantWSRequest).mockRejectedValueOnce(new Error('Not found'));
|
||||
|
||||
expect(
|
||||
manager.getEntities(createHASS(), ['cached', 'not-cached', 'missing']),
|
||||
).resolves.toEqual(
|
||||
new Map([
|
||||
['cached', cachedEntity],
|
||||
['not-cached', notCachedEntity],
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it('fetchEntityList', async () => {
|
||||
const hass = createHASS();
|
||||
const entity = createRegistryEntity({ entity_id: 'cached' });
|
||||
vi.mocked(homeAssistantWSRequest).mockResolvedValueOnce([entity]);
|
||||
|
||||
const manager = new EntityRegistryManager(createEntityRegistryCache());
|
||||
|
||||
await manager.fetchEntityList(hass);
|
||||
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
expect(homeAssistantWSRequest).toBeCalledWith(expect.anything(), expect.anything(), {
|
||||
type: 'config/entity_registry/list',
|
||||
});
|
||||
|
||||
expect(await manager.getEntity(hass, 'cached')).toEqual(entity);
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
|
||||
await manager.fetchEntityList(hass);
|
||||
expect(homeAssistantWSRequest).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('getMatchingEntities', async () => {
|
||||
const matchingEntity = createRegistryEntity({ entity_id: 'matching' });
|
||||
const notMatchingEntity = createRegistryEntity({ entity_id: 'not-matching' });
|
||||
const hass = createHASS();
|
||||
|
||||
vi.mocked(homeAssistantWSRequest).mockResolvedValueOnce([
|
||||
matchingEntity,
|
||||
notMatchingEntity,
|
||||
]);
|
||||
|
||||
const manager = new EntityRegistryManager(createEntityRegistryCache());
|
||||
expect(
|
||||
await manager.getMatchingEntities(
|
||||
hass,
|
||||
(entity) => entity.entity_id == 'matching',
|
||||
),
|
||||
).toEqual([matchingEntity]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user