Files
homeassistant-mcp/__tests__/context/index.test.ts
jango-blockchained 585b8d1f91 Enhance security middleware and package dependencies
- Updated security headers configuration with stricter settings
- Modified rate limiting and helmet middleware setup
- Added TypeScript type definitions for Express, rate-limit, and Helmet
- Refined referrer policy and HSTS configuration
- Improved security middleware chain for better protection
2025-01-30 09:27:22 +01:00

272 lines
9.2 KiB
TypeScript

import { jest } from '@jest/globals';
import { ContextManager, ResourceType, RelationType, ResourceState, ResourceRelationship } from '../../src/context/index.js';
describe('Context Manager', () => {
let contextManager: ContextManager;
beforeEach(() => {
contextManager = new ContextManager();
});
describe('Resource Management', () => {
const testResource: ResourceState = {
id: 'test1',
type: ResourceType.DEVICE,
state: 'on',
attributes: { name: 'Test Device' },
lastUpdated: Date.now()
};
it('should add resources', () => {
const addHandler = jest.fn();
contextManager.on('resource_added', addHandler);
contextManager.addResource(testResource);
const resource = contextManager.getResource('test1');
expect(resource).toEqual(testResource);
expect(addHandler).toHaveBeenCalledWith(testResource);
});
it('should update resources', () => {
const updateHandler = jest.fn();
contextManager.on('resource_updated', updateHandler);
contextManager.addResource(testResource);
contextManager.updateResource('test1', {
state: 'off',
attributes: { ...testResource.attributes, brightness: 50 }
});
const resource = contextManager.getResource('test1');
expect(resource?.state).toBe('off');
expect(resource?.attributes.brightness).toBe(50);
expect(updateHandler).toHaveBeenCalled();
});
it('should remove resources', () => {
const removeHandler = jest.fn();
contextManager.on('resource_removed', removeHandler);
contextManager.addResource(testResource);
contextManager.removeResource('test1');
expect(contextManager.getResource('test1')).toBeUndefined();
expect(removeHandler).toHaveBeenCalledWith(testResource);
});
it('should get resources by type', () => {
const resources = [
testResource,
{
id: 'test2',
type: ResourceType.DEVICE,
state: 'off',
attributes: {},
lastUpdated: Date.now()
},
{
id: 'area1',
type: ResourceType.AREA,
state: 'active',
attributes: {},
lastUpdated: Date.now()
}
];
resources.forEach(r => contextManager.addResource(r));
const devices = contextManager.getResourcesByType(ResourceType.DEVICE);
expect(devices).toHaveLength(2);
expect(devices.every((d: ResourceState) => d.type === ResourceType.DEVICE)).toBe(true);
});
});
describe('Relationship Management', () => {
const testRelationship: ResourceRelationship = {
sourceId: 'device1',
targetId: 'area1',
type: RelationType.CONTAINS
};
beforeEach(() => {
// Add test resources
contextManager.addResource({
id: 'device1',
type: ResourceType.DEVICE,
state: 'on',
attributes: {},
lastUpdated: Date.now()
});
contextManager.addResource({
id: 'area1',
type: ResourceType.AREA,
state: 'active',
attributes: {},
lastUpdated: Date.now()
});
});
it('should add relationships', () => {
const addHandler = jest.fn();
contextManager.on('relationship_added', addHandler);
contextManager.addRelationship(testRelationship);
const related = contextManager.getRelatedResources('device1');
expect(related).toHaveLength(2);
expect(related.some(r => r.id === 'area1')).toBe(true);
expect(addHandler).toHaveBeenCalledWith(testRelationship);
});
it('should remove relationships', () => {
const removeHandler = jest.fn();
contextManager.on('relationship_removed', removeHandler);
contextManager.addRelationship(testRelationship);
contextManager.removeRelationship(
'device1',
'area1',
RelationType.CONTAINS
);
const related = contextManager.getRelatedResources('device1');
expect(related).toHaveLength(0);
expect(removeHandler).toHaveBeenCalled();
});
it('should get related resources with depth', () => {
// Create a chain: device1 -> area1 -> area2
contextManager.addResource({
id: 'area2',
type: ResourceType.AREA,
state: 'active',
attributes: {},
lastUpdated: Date.now()
});
contextManager.addRelationship({
sourceId: 'device1',
targetId: 'area1',
type: RelationType.CONTAINS
});
contextManager.addRelationship({
sourceId: 'area1',
targetId: 'area2',
type: RelationType.CONTAINS
});
const relatedDepth1 = contextManager.getRelatedResources('device1', undefined, 1);
expect(relatedDepth1).toHaveLength(3);
const relatedDepth2 = contextManager.getRelatedResources('device1', undefined, 2);
expect(relatedDepth2).toHaveLength(3);
});
});
describe('Resource Analysis', () => {
beforeEach(() => {
// Setup test resources and relationships
const resources = [
{
id: 'device1',
type: ResourceType.DEVICE,
state: 'on',
attributes: {},
lastUpdated: Date.now()
},
{
id: 'automation1',
type: ResourceType.AUTOMATION,
state: 'on',
attributes: {},
lastUpdated: Date.now()
},
{
id: 'group1',
type: ResourceType.GROUP,
state: 'on',
attributes: {},
lastUpdated: Date.now()
}
];
resources.forEach(r => contextManager.addResource(r));
const relationships = [
{
sourceId: 'automation1',
targetId: 'device1',
type: RelationType.CONTROLS
},
{
sourceId: 'device1',
targetId: 'group1',
type: RelationType.DEPENDS_ON
},
{
sourceId: 'group1',
targetId: 'device1',
type: RelationType.GROUPS
}
];
relationships.forEach(r => contextManager.addRelationship(r));
});
it('should analyze resource usage', () => {
const analysis = contextManager.analyzeResourceUsage('device1');
expect(analysis.dependencies).toHaveLength(1);
expect(analysis.dependencies[0]).toBe('group1');
expect(analysis.dependents).toHaveLength(0);
expect(analysis.groups).toHaveLength(1);
expect(analysis.usage.controlCount).toBe(0);
expect(analysis.usage.triggerCount).toBe(0);
expect(analysis.usage.groupCount).toBe(1);
});
});
describe('Event Subscriptions', () => {
it('should handle resource subscriptions', () => {
const callback = jest.fn();
const unsubscribe = contextManager.subscribeToResource('test1', callback);
contextManager.addResource({
id: 'test1',
type: ResourceType.DEVICE,
state: 'on',
attributes: {},
lastUpdated: Date.now()
});
contextManager.updateResource('test1', { state: 'off' });
expect(callback).toHaveBeenCalled();
unsubscribe();
contextManager.updateResource('test1', { state: 'on' });
expect(callback).toHaveBeenCalledTimes(1);
});
it('should handle type subscriptions', () => {
const callback = jest.fn();
const unsubscribe = contextManager.subscribeToType(ResourceType.DEVICE, callback);
const resource = {
id: 'test1',
type: ResourceType.DEVICE,
state: 'on',
attributes: {},
lastUpdated: Date.now()
};
contextManager.addResource(resource);
contextManager.updateResource('test1', { state: 'off' });
expect(callback).toHaveBeenCalled();
unsubscribe();
contextManager.updateResource('test1', { state: 'on' });
expect(callback).toHaveBeenCalledTimes(1);
});
});
});