@coffeerunhobby/mcp-ha-connect 2.2.1 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +1 -1
- package/README.md +24 -2
- package/dist/omadaClient/accessControl.d.ts +290 -0
- package/dist/omadaClient/accessControl.js +509 -0
- package/dist/omadaClient/accessControl.js.map +1 -0
- package/dist/omadaClient/client.d.ts +6 -1
- package/dist/omadaClient/client.js +12 -1
- package/dist/omadaClient/client.js.map +1 -1
- package/dist/omadaClient/diagnose.d.ts +68 -0
- package/dist/omadaClient/diagnose.js +164 -0
- package/dist/omadaClient/diagnose.js.map +1 -0
- package/dist/omadaClient/index.d.ts +9 -0
- package/dist/omadaClient/index.js +19 -0
- package/dist/omadaClient/index.js.map +1 -1
- package/dist/omadaClient/macGroups.d.ts +58 -0
- package/dist/omadaClient/macGroups.js +110 -0
- package/dist/omadaClient/macGroups.js.map +1 -0
- package/dist/omadaClient/serialize.d.ts +13 -0
- package/dist/omadaClient/serialize.js +29 -0
- package/dist/omadaClient/serialize.js.map +1 -0
- package/dist/omadaClient/timeRange.d.ts +41 -0
- package/dist/omadaClient/timeRange.js +109 -0
- package/dist/omadaClient/timeRange.js.map +1 -0
- package/dist/tools/infra/actions.d.ts +1 -1
- package/dist/tools/infra/actions.js +1 -1
- package/dist/tools/omada/accessControl.d.ts +151 -0
- package/dist/tools/omada/accessControl.js +158 -0
- package/dist/tools/omada/accessControl.js.map +1 -0
- package/dist/tools/omada/index.js +9 -0
- package/dist/tools/omada/index.js.map +1 -1
- package/dist/tools/omada/macGroups.d.ts +19 -0
- package/dist/tools/omada/macGroups.js +77 -0
- package/dist/tools/omada/macGroups.js.map +1 -0
- package/dist/tools/omada/namespace.js +16 -0
- package/dist/tools/omada/namespace.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -1
- package/.codex/review-rules.md +0 -16
- package/.dockerignore +0 -8
- package/.gitattributes +0 -30
- package/.github/workflows/ci.yml +0 -193
- package/AGENTS.md +0 -389
- package/Dockerfile +0 -50
- package/docker-compose.yml +0 -23
- package/docs/CHANGELOG.md +0 -341
- package/docs/COVERAGE.md +0 -219
- package/docs/QUICK_START.md +0 -240
- package/eslint.config.js +0 -33
- package/n8n/ai-agent-safety-monitor.json +0 -355
- package/openapi.json +0 -1259
- package/scripts/check-version-sync.mjs +0 -69
- package/scripts/generate-jwt.ts +0 -121
- package/src/config.ts +0 -440
- package/src/haClient/automations.ts +0 -261
- package/src/haClient/calendars.ts +0 -94
- package/src/haClient/config.ts +0 -52
- package/src/haClient/devices.ts +0 -653
- package/src/haClient/entities.ts +0 -128
- package/src/haClient/events.ts +0 -689
- package/src/haClient/history.ts +0 -73
- package/src/haClient/index.ts +0 -336
- package/src/haClient/request.ts +0 -142
- package/src/haClient/services.ts +0 -45
- package/src/haClient/states.ts +0 -60
- package/src/haClient/updates.ts +0 -58
- package/src/haClient/wsCommand.ts +0 -44
- package/src/index.ts +0 -164
- package/src/localAI/index.ts +0 -88
- package/src/localAI/prompts.ts +0 -50
- package/src/localAI/providers/base.ts +0 -120
- package/src/localAI/providers/ollama.ts +0 -78
- package/src/localAI/providers/openai.ts +0 -86
- package/src/localAI/types.ts +0 -67
- package/src/omadaClient/auth.ts +0 -178
- package/src/omadaClient/client.ts +0 -337
- package/src/omadaClient/device.ts +0 -118
- package/src/omadaClient/index.ts +0 -310
- package/src/omadaClient/network.ts +0 -284
- package/src/omadaClient/request.ts +0 -365
- package/src/omadaClient/security.ts +0 -51
- package/src/omadaClient/site.ts +0 -344
- package/src/ownerQuestions/service.ts +0 -536
- package/src/permissions/index.ts +0 -143
- package/src/resources/index.ts +0 -213
- package/src/server/auth.ts +0 -175
- package/src/server/chatFace.ts +0 -789
- package/src/server/chatSlice.ts +0 -57
- package/src/server/common.ts +0 -170
- package/src/server/eventSubscription.ts +0 -343
- package/src/server/http.ts +0 -626
- package/src/server/instructions.ts +0 -97
- package/src/server/rateLimiter.ts +0 -227
- package/src/server/stdio.ts +0 -41
- package/src/server/stream.ts +0 -205
- package/src/tools/ai/analyzeSensors.ts +0 -33
- package/src/tools/ai/index.ts +0 -20
- package/src/tools/common.ts +0 -442
- package/src/tools/homeassistant/askOwner.ts +0 -133
- package/src/tools/homeassistant/automationControls.ts +0 -66
- package/src/tools/homeassistant/calendar.ts +0 -97
- package/src/tools/homeassistant/callService.ts +0 -25
- package/src/tools/homeassistant/controlClimate.ts +0 -68
- package/src/tools/homeassistant/controlCover.ts +0 -48
- package/src/tools/homeassistant/controlFan.ts +0 -44
- package/src/tools/homeassistant/controlLight.ts +0 -38
- package/src/tools/homeassistant/controlMediaPlayer.ts +0 -50
- package/src/tools/homeassistant/createAutomation.ts +0 -35
- package/src/tools/homeassistant/deleteAutomation.ts +0 -24
- package/src/tools/homeassistant/entityAction.ts +0 -35
- package/src/tools/homeassistant/entityGuard.ts +0 -28
- package/src/tools/homeassistant/getAllSensors.ts +0 -46
- package/src/tools/homeassistant/getAutomationTrace.ts +0 -30
- package/src/tools/homeassistant/getDomainSummary.ts +0 -29
- package/src/tools/homeassistant/getEntitiesByDomain.ts +0 -56
- package/src/tools/homeassistant/getHistory.ts +0 -24
- package/src/tools/homeassistant/getState.ts +0 -24
- package/src/tools/homeassistant/getStates.ts +0 -46
- package/src/tools/homeassistant/getVersion.ts +0 -21
- package/src/tools/homeassistant/index.ts +0 -121
- package/src/tools/homeassistant/listAutomations.ts +0 -35
- package/src/tools/homeassistant/listEntities.ts +0 -44
- package/src/tools/homeassistant/listPersons.ts +0 -46
- package/src/tools/homeassistant/sceneAndScript.ts +0 -53
- package/src/tools/homeassistant/searchEntities.ts +0 -58
- package/src/tools/homeassistant/sendNotification.ts +0 -179
- package/src/tools/homeassistant/systemTools.ts +0 -52
- package/src/tools/homeassistant/triggerAutomation.ts +0 -24
- package/src/tools/index.ts +0 -78
- package/src/tools/infra/actions.ts +0 -95
- package/src/tools/infra/index.ts +0 -138
- package/src/tools/omada/blockClient.ts +0 -28
- package/src/tools/omada/cyclePoePort.ts +0 -32
- package/src/tools/omada/deleteClient.ts +0 -27
- package/src/tools/omada/disableClientRateLimit.ts +0 -23
- package/src/tools/omada/getClient.ts +0 -14
- package/src/tools/omada/getDevice.ts +0 -14
- package/src/tools/omada/getFirewallSetting.ts +0 -14
- package/src/tools/omada/getInternetInfo.ts +0 -14
- package/src/tools/omada/getLanNetworkList.ts +0 -14
- package/src/tools/omada/getLanProfileList.ts +0 -14
- package/src/tools/omada/getPortForwardingStatus.ts +0 -26
- package/src/tools/omada/getRateLimitProfiles.ts +0 -14
- package/src/tools/omada/getSiteNtpStatus.ts +0 -14
- package/src/tools/omada/getSsidDetail.ts +0 -22
- package/src/tools/omada/getSsidList.ts +0 -21
- package/src/tools/omada/getSwitchStackDetail.ts +0 -14
- package/src/tools/omada/getThreatList.ts +0 -42
- package/src/tools/omada/getWlanGroupList.ts +0 -14
- package/src/tools/omada/graph.ts +0 -187
- package/src/tools/omada/index.ts +0 -153
- package/src/tools/omada/listBlockedClients.ts +0 -17
- package/src/tools/omada/listClients.ts +0 -14
- package/src/tools/omada/listClientsActivity.ts +0 -25
- package/src/tools/omada/listClientsPastConnections.ts +0 -44
- package/src/tools/omada/listDevices.ts +0 -14
- package/src/tools/omada/listDevicesStats.ts +0 -41
- package/src/tools/omada/listMostActiveClients.ts +0 -14
- package/src/tools/omada/listSites.ts +0 -18
- package/src/tools/omada/namespace.ts +0 -1164
- package/src/tools/omada/searchDevices.ts +0 -20
- package/src/tools/omada/setClientRateLimit.ts +0 -26
- package/src/tools/omada/setClientRateLimitProfile.ts +0 -25
- package/src/tools/omada/setSiteNtpServers.ts +0 -36
- package/src/tools/omada/setSsidEnabled.ts +0 -38
- package/src/tools/omada/unblockClient.ts +0 -26
- package/src/tools/types.ts +0 -11
- package/src/tools/utils/pagination-schema.ts +0 -27
- package/src/types/ai/index.ts +0 -11
- package/src/types/ai/types.ts +0 -67
- package/src/types/homeassistant/automations.ts +0 -43
- package/src/types/homeassistant/calendars.ts +0 -26
- package/src/types/homeassistant/config.ts +0 -14
- package/src/types/homeassistant/entities.ts +0 -14
- package/src/types/homeassistant/errors.ts +0 -33
- package/src/types/homeassistant/haConfig.ts +0 -7
- package/src/types/homeassistant/history.ts +0 -13
- package/src/types/homeassistant/index.ts +0 -46
- package/src/types/homeassistant/request.ts +0 -6
- package/src/types/homeassistant/serviceCall.ts +0 -18
- package/src/types/homeassistant/states.ts +0 -58
- package/src/types/homeassistant/updates.ts +0 -28
- package/src/types/index.ts +0 -12
- package/src/types/omada/activeClientInfo.ts +0 -17
- package/src/types/omada/clientActivity.ts +0 -32
- package/src/types/omada/clientBlockStatus.ts +0 -11
- package/src/types/omada/clientPastConnection.ts +0 -82
- package/src/types/omada/index.ts +0 -14
- package/src/types/omada/omadaApiResponse.ts +0 -5
- package/src/types/omada/omadaClientInfo.ts +0 -11
- package/src/types/omada/omadaDeviceInfo.ts +0 -11
- package/src/types/omada/omadaDeviceStats.ts +0 -31
- package/src/types/omada/omadaSiteSummary.ts +0 -5
- package/src/types/omada/oswStackDetail.ts +0 -11
- package/src/types/omada/paginatedResult.ts +0 -6
- package/src/types/omada/rateLimitProfile.ts +0 -58
- package/src/types/omada/threatInfo.ts +0 -38
- package/src/types/omada/tokenResult.ts +0 -6
- package/src/types.ts +0 -2
- package/src/utils/config-validations.ts +0 -68
- package/src/utils/jwt.ts +0 -112
- package/src/utils/logger.ts +0 -121
- package/src/utils/plainText.ts +0 -48
- package/src/utils/redact.ts +0 -59
- package/src/utils/sanitizeError.ts +0 -18
- package/src/utils/tlsDispatcher.ts +0 -69
- package/src/version.ts +0 -5
- package/tests/bdd/automation-creation.spec.ts +0 -214
- package/tests/bdd/automation-management.spec.ts +0 -267
- package/tests/bdd/calendar.spec.ts +0 -190
- package/tests/bdd/configuration.spec.ts +0 -283
- package/tests/bdd/device-control.spec.ts +0 -344
- package/tests/bdd/entity-listing.spec.ts +0 -208
- package/tests/bdd/entity-search.spec.ts +0 -183
- package/tests/bdd/history-retrieval.spec.ts +0 -195
- package/tests/bdd/notifications.spec.ts +0 -238
- package/tests/bdd/service-calls.spec.ts +0 -144
- package/tests/bdd/state-retrieval.spec.ts +0 -204
- package/tests/bench/hotpaths.bench.ts +0 -68
- package/tests/config.test.ts +0 -355
- package/tests/features/automation-creation.feature +0 -36
- package/tests/features/automation-management.feature +0 -54
- package/tests/features/calendar.feature +0 -37
- package/tests/features/configuration.feature +0 -70
- package/tests/features/device-control.feature +0 -100
- package/tests/features/entity-listing.feature +0 -51
- package/tests/features/entity-search.feature +0 -44
- package/tests/features/history-retrieval.feature +0 -38
- package/tests/features/notifications.feature +0 -37
- package/tests/features/service-calls.feature +0 -35
- package/tests/features/state-retrieval.feature +0 -37
- package/tests/fixtures/openapi-default-slice.json +0 -290
- package/tests/haClient/automationTrace.test.ts +0 -59
- package/tests/haClient/automations.test.ts +0 -149
- package/tests/haClient/config.test.ts +0 -117
- package/tests/haClient/entities.test.ts +0 -188
- package/tests/haClient/events.test.ts +0 -455
- package/tests/haClient/eventsTls.test.ts +0 -52
- package/tests/haClient/history.test.ts +0 -228
- package/tests/haClient/index.test.ts +0 -243
- package/tests/haClient/request.test.ts +0 -217
- package/tests/haClient/services.test.ts +0 -120
- package/tests/haClient/states.test.ts +0 -119
- package/tests/haClient/updates.test.ts +0 -193
- package/tests/index.test.ts +0 -160
- package/tests/integration/homeassistant.test.ts +0 -144
- package/tests/integration/omada.test.ts +0 -167
- package/tests/integration/server.test.ts +0 -151
- package/tests/localAI/index.test.ts +0 -177
- package/tests/localAI/ollama.test.ts +0 -187
- package/tests/localAI/openai.test.ts +0 -257
- package/tests/omadaClient/actions.test.ts +0 -161
- package/tests/omadaClient/clientBlocks.test.ts +0 -170
- package/tests/omadaClient/ntp.test.ts +0 -381
- package/tests/omadaClient/site.test.ts +0 -37
- package/tests/ownerQuestions/service.test.ts +0 -499
- package/tests/ownerQuestions/tools.test.ts +0 -186
- package/tests/permissions/index.test.ts +0 -217
- package/tests/resources/index.test.ts +0 -288
- package/tests/scripts/generateJwt.test.ts +0 -44
- package/tests/security/accessControl.test.ts +0 -223
- package/tests/security/authentication.test.ts +0 -117
- package/tests/security/configuration.test.ts +0 -170
- package/tests/security/cryptoTransport.test.ts +0 -172
- package/tests/security/dependencies.test.ts +0 -152
- package/tests/security/injection.test.ts +0 -117
- package/tests/security/insecureDesign.test.ts +0 -121
- package/tests/security/logging.test.ts +0 -131
- package/tests/security/resourceConsumption.test.ts +0 -142
- package/tests/server/auth.test.ts +0 -249
- package/tests/server/chatFace.test.ts +0 -320
- package/tests/server/common.test.ts +0 -84
- package/tests/server/http.test.ts +0 -561
- package/tests/server/instructions.test.ts +0 -152
- package/tests/server/memoizeJsonSchema.test.ts +0 -71
- package/tests/server/stdio.test.ts +0 -99
- package/tests/server/stream.test.ts +0 -285
- package/tests/server/toolVisibility.http.test.ts +0 -111
- package/tests/server/toolVisibility.test.ts +0 -129
- package/tests/tools/ai/analyzeSensors.test.ts +0 -227
- package/tests/tools/common.test.ts +0 -123
- package/tests/tools/homeassistant/handlers.test.ts +0 -872
- package/tests/tools/infra/invokeAction.test.ts +0 -280
- package/tests/tools/omada/graph.test.ts +0 -385
- package/tests/tools/omada/handlers.test.ts +0 -897
- package/tests/tools/omada/namespace.test.ts +0 -483
- package/tests/tools/registry.test.ts +0 -168
- package/tests/utils/config-validations.test.ts +0 -352
- package/tests/utils/jwt.test.ts +0 -115
- package/tests/utils/logger.test.ts +0 -327
- package/tests/utils/redact.test.ts +0 -105
- package/tsconfig.json +0 -24
- package/vitest.config.ts +0 -38
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration tests for Home Assistant
|
|
3
|
-
* These tests run against a real Home Assistant instance
|
|
4
|
-
* Requires HA_URL and HA_TOKEN environment variables
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { describe, it, expect, beforeAll } from 'vitest';
|
|
8
|
-
import { HaClient } from '../../src/haClient/index.js';
|
|
9
|
-
|
|
10
|
-
describe('Home Assistant Integration', () => {
|
|
11
|
-
let client: HaClient;
|
|
12
|
-
|
|
13
|
-
beforeAll(() => {
|
|
14
|
-
const baseUrl = process.env.HA_URL;
|
|
15
|
-
const token = process.env.HA_TOKEN;
|
|
16
|
-
|
|
17
|
-
if (!baseUrl || !token) {
|
|
18
|
-
throw new Error('HA_URL and HA_TOKEN environment variables are required for integration tests');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
client = new HaClient({
|
|
22
|
-
baseUrl,
|
|
23
|
-
token,
|
|
24
|
-
strictSsl: process.env.HA_STRICT_SSL !== 'false',
|
|
25
|
-
timeout: parseInt(process.env.HA_TIMEOUT || '30000'),
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
describe('API Connection', () => {
|
|
30
|
-
it('should connect to Home Assistant API', async () => {
|
|
31
|
-
const result = await client.checkApi();
|
|
32
|
-
expect(result.message).toBe('API running.');
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('should get Home Assistant version', async () => {
|
|
36
|
-
const version = await client.getVersion();
|
|
37
|
-
expect(version).toHaveProperty('version');
|
|
38
|
-
expect(version.version).toMatch(/^\d+\.\d+\.\d+/);
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
describe('Entity States', () => {
|
|
43
|
-
it('should get all states', async () => {
|
|
44
|
-
const states = await client.getStates();
|
|
45
|
-
expect(Array.isArray(states)).toBe(true);
|
|
46
|
-
expect(states.length).toBeGreaterThan(0);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('should get state of a specific entity', async () => {
|
|
50
|
-
// First get all states to find a valid entity_id
|
|
51
|
-
const states = await client.getStates();
|
|
52
|
-
expect(states.length).toBeGreaterThan(0);
|
|
53
|
-
|
|
54
|
-
const entity = await client.getState(states[0].entity_id);
|
|
55
|
-
expect(entity).not.toBeNull();
|
|
56
|
-
expect(entity).toHaveProperty('entity_id');
|
|
57
|
-
expect(entity).toHaveProperty('state');
|
|
58
|
-
expect(entity).toHaveProperty('attributes');
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
describe('Entity Search', () => {
|
|
63
|
-
it('should search entities by query', async () => {
|
|
64
|
-
const results = await client.searchEntities('sensor');
|
|
65
|
-
expect(Array.isArray(results)).toBe(true);
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
describe('Domain Operations', () => {
|
|
70
|
-
it('should get entities by domain', async () => {
|
|
71
|
-
const entities = await client.getEntitiesByDomain('sensor');
|
|
72
|
-
expect(Array.isArray(entities)).toBe(true);
|
|
73
|
-
entities.forEach((entity) => {
|
|
74
|
-
expect(entity.entity_id).toMatch(/^sensor\./);
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('should get domain summary', async () => {
|
|
79
|
-
const result = await client.getDomainSummary('sensor');
|
|
80
|
-
expect(result).toHaveProperty('domain');
|
|
81
|
-
expect(result).toHaveProperty('count');
|
|
82
|
-
expect(result).toHaveProperty('states');
|
|
83
|
-
expect(result.domain).toBe('sensor');
|
|
84
|
-
expect(result.count).toBeGreaterThan(0);
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
describe('Sensors', () => {
|
|
89
|
-
it('should get all sensors', async () => {
|
|
90
|
-
const sensors = await client.getAllSensors();
|
|
91
|
-
expect(Array.isArray(sensors)).toBe(true);
|
|
92
|
-
sensors.forEach((entity) => {
|
|
93
|
-
expect(entity.entity_id).toMatch(/^(sensor|binary_sensor)\./);
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
describe('Persons', () => {
|
|
99
|
-
it('should get person entities via domain lookup', async () => {
|
|
100
|
-
// The HaClient doesn't have a getPersons method directly
|
|
101
|
-
// Persons are accessed via getEntitiesByDomain('person')
|
|
102
|
-
const persons = await client.getEntitiesByDomain('person');
|
|
103
|
-
expect(Array.isArray(persons)).toBe(true);
|
|
104
|
-
persons.forEach((person) => {
|
|
105
|
-
expect(person.entity_id).toMatch(/^person\./);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
describe('Automations', () => {
|
|
111
|
-
it('should list automations', async () => {
|
|
112
|
-
const result = await client.getAutomations();
|
|
113
|
-
expect(Array.isArray(result)).toBe(true);
|
|
114
|
-
if (result.length > 0) {
|
|
115
|
-
// Automation type uses 'id' not 'entity_id'
|
|
116
|
-
expect(result[0]).toHaveProperty('id');
|
|
117
|
-
expect(result[0]).toHaveProperty('state');
|
|
118
|
-
expect(result[0]).toHaveProperty('alias');
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
describe('Calendars', () => {
|
|
124
|
-
it('should list calendars (or report the integration absent)', async () => {
|
|
125
|
-
// HA only serves /api/calendars when a calendar integration is loaded;
|
|
126
|
-
// a bare instance 404s. Both are valid live-system states — the test
|
|
127
|
-
// asserts the client surfaces them correctly, not that the user has
|
|
128
|
-
// calendars configured.
|
|
129
|
-
try {
|
|
130
|
-
const result = await client.getCalendars();
|
|
131
|
-
expect(Array.isArray(result)).toBe(true);
|
|
132
|
-
} catch (error) {
|
|
133
|
-
expect((error as { statusCode?: number; message: string }).message).toMatch(/Not Found/i);
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
describe('System', () => {
|
|
139
|
-
it('should get system log', async () => {
|
|
140
|
-
const result = await client.getSystemLog({ hours: 1, limit: 10 });
|
|
141
|
-
expect(Array.isArray(result)).toBe(true);
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
});
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration tests for TP-Link Omada Controller
|
|
3
|
-
* These tests run against a real Omada controller
|
|
4
|
-
* Requires OMADA_* environment variables
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { describe, it, expect, beforeAll } from 'vitest';
|
|
8
|
-
import { OmadaClient } from '../../src/omadaClient/index.js';
|
|
9
|
-
|
|
10
|
-
describe('Omada Integration', () => {
|
|
11
|
-
let client: OmadaClient;
|
|
12
|
-
let siteId: string;
|
|
13
|
-
|
|
14
|
-
beforeAll(async () => {
|
|
15
|
-
const baseUrl = process.env.OMADA_BASE_URL;
|
|
16
|
-
const clientId = process.env.OMADA_CLIENT_ID;
|
|
17
|
-
const clientSecret = process.env.OMADA_CLIENT_SECRET;
|
|
18
|
-
const omadacId = process.env.OMADA_OMADAC_ID;
|
|
19
|
-
|
|
20
|
-
if (!baseUrl || !clientId || !clientSecret || !omadacId) {
|
|
21
|
-
throw new Error('OMADA_BASE_URL, OMADA_CLIENT_ID, OMADA_CLIENT_SECRET, and OMADA_OMADAC_ID are required');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
client = new OmadaClient({
|
|
25
|
-
baseUrl,
|
|
26
|
-
clientId,
|
|
27
|
-
clientSecret,
|
|
28
|
-
omadacId,
|
|
29
|
-
siteId: process.env.OMADA_SITE_ID,
|
|
30
|
-
strictSsl: process.env.OMADA_STRICT_SSL !== 'false',
|
|
31
|
-
timeout: parseInt(process.env.OMADA_TIMEOUT || '30000'),
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
// Get siteId for tests
|
|
35
|
-
siteId = process.env.OMADA_SITE_ID || '';
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
describe('Sites', () => {
|
|
39
|
-
it('should list all sites', async () => {
|
|
40
|
-
const sites = await client.listSites();
|
|
41
|
-
expect(Array.isArray(sites)).toBe(true);
|
|
42
|
-
expect(sites.length).toBeGreaterThan(0);
|
|
43
|
-
expect(sites[0]).toHaveProperty('siteId');
|
|
44
|
-
expect(sites[0]).toHaveProperty('name');
|
|
45
|
-
|
|
46
|
-
// Use first site if not configured
|
|
47
|
-
if (!siteId) {
|
|
48
|
-
siteId = sites[0].siteId;
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
describe('Devices', () => {
|
|
54
|
-
it('should list network devices', async () => {
|
|
55
|
-
const devices = await client.listDevices(siteId);
|
|
56
|
-
expect(Array.isArray(devices)).toBe(true);
|
|
57
|
-
if (devices.length > 0) {
|
|
58
|
-
expect(devices[0]).toHaveProperty('mac');
|
|
59
|
-
expect(devices[0]).toHaveProperty('name');
|
|
60
|
-
expect(devices[0]).toHaveProperty('type');
|
|
61
|
-
expect(devices[0]).toHaveProperty('ip');
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('should search devices globally', async () => {
|
|
66
|
-
// searchDevices returns an array of OmadaDeviceInfo
|
|
67
|
-
// Note: If no devices match, the API may return an empty object {} instead of []
|
|
68
|
-
// so we need to handle both cases
|
|
69
|
-
const results = await client.searchDevices('gateway');
|
|
70
|
-
// Results could be an array or an empty object if no matches
|
|
71
|
-
const isArrayOrEmpty = Array.isArray(results) || (typeof results === 'object' && results !== null);
|
|
72
|
-
expect(isArrayOrEmpty).toBe(true);
|
|
73
|
-
if (Array.isArray(results) && results.length > 0) {
|
|
74
|
-
expect(results[0]).toHaveProperty('mac');
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
describe('Clients', () => {
|
|
80
|
-
it('should list connected clients', async () => {
|
|
81
|
-
const clients = await client.listClients(siteId);
|
|
82
|
-
expect(Array.isArray(clients)).toBe(true);
|
|
83
|
-
if (clients.length > 0) {
|
|
84
|
-
expect(clients[0]).toHaveProperty('mac');
|
|
85
|
-
expect(clients[0]).toHaveProperty('ip');
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('should list most active clients', async () => {
|
|
90
|
-
const clients = await client.listMostActiveClients(siteId);
|
|
91
|
-
expect(Array.isArray(clients)).toBe(true);
|
|
92
|
-
if (clients.length > 0) {
|
|
93
|
-
expect(clients[0]).toHaveProperty('name');
|
|
94
|
-
// Controller v5 exposed `totalTraffic`; OC200 v6 renamed the traffic
|
|
95
|
-
// field. Assert a traffic-ish field exists rather than pinning the
|
|
96
|
-
// v5 name (discovered live on OC200 6.2, 2026-07-11).
|
|
97
|
-
const keys = Object.keys(clients[0] as Record<string, unknown>);
|
|
98
|
-
expect(keys.some((k) => /traffic|activity/i.test(k))).toBe(true);
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
describe('Network Configuration', () => {
|
|
104
|
-
it('should get internet info', async () => {
|
|
105
|
-
const info = await client.getInternetInfo(siteId);
|
|
106
|
-
expect(info).toHaveProperty('wanPortSettings');
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('should get LAN network list', async () => {
|
|
110
|
-
const networks = await client.getLanNetworkList(siteId);
|
|
111
|
-
expect(Array.isArray(networks)).toBe(true);
|
|
112
|
-
if (networks.length > 0) {
|
|
113
|
-
expect(networks[0]).toHaveProperty('name');
|
|
114
|
-
expect(networks[0]).toHaveProperty('vlan');
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('should get WLAN group list', async () => {
|
|
119
|
-
const groups = await client.getWlanGroupList(siteId);
|
|
120
|
-
expect(Array.isArray(groups)).toBe(true);
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
describe('Rate Limiting', () => {
|
|
125
|
-
it('should get rate limit profiles', async () => {
|
|
126
|
-
const profiles = await client.getRateLimitProfiles(siteId);
|
|
127
|
-
expect(Array.isArray(profiles)).toBe(true);
|
|
128
|
-
if (profiles.length > 0) {
|
|
129
|
-
expect(profiles[0]).toHaveProperty('profileId');
|
|
130
|
-
expect(profiles[0]).toHaveProperty('name');
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
describe('Security', () => {
|
|
136
|
-
it('should get threat list (may be empty)', async () => {
|
|
137
|
-
// The threat list API may return 400 if IDS/IPS is not enabled or configured
|
|
138
|
-
// This test catches the error and passes if no threats are available.
|
|
139
|
-
// NB: archived/page/pageSize/startTime/endTime are REQUIRED — controller
|
|
140
|
-
// v5 tolerated their absence, OC200 v6 rejects nulls ("archived should
|
|
141
|
-
// not be null", live finding 2026-07-11). The MCP tool schema already
|
|
142
|
-
// requires them; this test used to cheat with `{}`.
|
|
143
|
-
try {
|
|
144
|
-
const now = Math.floor(Date.now() / 1000);
|
|
145
|
-
const result = await client.getThreatList({
|
|
146
|
-
archived: false,
|
|
147
|
-
page: 1,
|
|
148
|
-
pageSize: 10,
|
|
149
|
-
startTime: now - 7 * 24 * 3600,
|
|
150
|
-
endTime: now,
|
|
151
|
-
});
|
|
152
|
-
// If we get here, the API worked - check structure
|
|
153
|
-
expect(result).toHaveProperty('data');
|
|
154
|
-
expect(Array.isArray(result.data)).toBe(true);
|
|
155
|
-
} catch (error) {
|
|
156
|
-
// Some Omada setups may not have threat detection enabled
|
|
157
|
-
// This is acceptable - skip rather than fail
|
|
158
|
-
if (error instanceof Error && error.message.includes('400')) {
|
|
159
|
-
// API returned 400 - threat detection may not be enabled
|
|
160
|
-
expect(true).toBe(true);
|
|
161
|
-
} else {
|
|
162
|
-
throw error;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
});
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration tests for MCP Server
|
|
3
|
-
* Tests server initialization with real clients
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
7
|
-
import { HaClient } from '../../src/haClient/index.js';
|
|
8
|
-
import { OmadaClient } from '../../src/omadaClient/index.js';
|
|
9
|
-
import { createServer } from '../../src/server/common.js';
|
|
10
|
-
import { generateInstructions } from '../../src/server/instructions.js';
|
|
11
|
-
|
|
12
|
-
describe('Server Integration', () => {
|
|
13
|
-
let haClient: HaClient | undefined;
|
|
14
|
-
let omadaClient: OmadaClient | undefined;
|
|
15
|
-
|
|
16
|
-
beforeAll(async () => {
|
|
17
|
-
// Initialize HA client if configured
|
|
18
|
-
if (process.env.HA_URL && process.env.HA_TOKEN) {
|
|
19
|
-
haClient = new HaClient({
|
|
20
|
-
baseUrl: process.env.HA_URL,
|
|
21
|
-
token: process.env.HA_TOKEN,
|
|
22
|
-
strictSsl: process.env.HA_STRICT_SSL !== 'false',
|
|
23
|
-
timeout: parseInt(process.env.HA_TIMEOUT || '30000'),
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Initialize Omada client if configured
|
|
28
|
-
if (
|
|
29
|
-
process.env.OMADA_BASE_URL &&
|
|
30
|
-
process.env.OMADA_CLIENT_ID &&
|
|
31
|
-
process.env.OMADA_CLIENT_SECRET &&
|
|
32
|
-
process.env.OMADA_OMADAC_ID
|
|
33
|
-
) {
|
|
34
|
-
omadaClient = new OmadaClient({
|
|
35
|
-
baseUrl: process.env.OMADA_BASE_URL,
|
|
36
|
-
clientId: process.env.OMADA_CLIENT_ID,
|
|
37
|
-
clientSecret: process.env.OMADA_CLIENT_SECRET,
|
|
38
|
-
omadacId: process.env.OMADA_OMADAC_ID,
|
|
39
|
-
siteId: process.env.OMADA_SITE_ID,
|
|
40
|
-
strictSsl: process.env.OMADA_STRICT_SSL !== 'false',
|
|
41
|
-
timeout: parseInt(process.env.OMADA_TIMEOUT || '30000'),
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
describe('Server Creation', () => {
|
|
47
|
-
it('should create server with HA client', () => {
|
|
48
|
-
if (!haClient) {
|
|
49
|
-
console.log('Skipping: HA not configured');
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const server = createServer({ haClient });
|
|
54
|
-
expect(server).toBeDefined();
|
|
55
|
-
expect(server.server).toBeDefined();
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should create server with Omada client', () => {
|
|
59
|
-
if (!omadaClient) {
|
|
60
|
-
console.log('Skipping: Omada not configured');
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const server = createServer({ omadaClient });
|
|
65
|
-
expect(server).toBeDefined();
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('should create server with all clients', () => {
|
|
69
|
-
const server = createServer({
|
|
70
|
-
haClient,
|
|
71
|
-
omadaClient,
|
|
72
|
-
});
|
|
73
|
-
expect(server).toBeDefined();
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
describe('Server Instructions', () => {
|
|
78
|
-
it('should generate instructions for HA only', () => {
|
|
79
|
-
const instructions = generateInstructions({
|
|
80
|
-
haEnabled: true,
|
|
81
|
-
omadaEnabled: false,
|
|
82
|
-
aiEnabled: false,
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
expect(instructions).toContain('MCP-HA-Connect');
|
|
86
|
-
expect(instructions).toContain('ENTITY QUERIES');
|
|
87
|
-
expect(instructions).not.toContain('OMADA');
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('should generate instructions for Omada only', () => {
|
|
91
|
-
const instructions = generateInstructions({
|
|
92
|
-
haEnabled: false,
|
|
93
|
-
omadaEnabled: true,
|
|
94
|
-
aiEnabled: false,
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
expect(instructions).toContain('MCP-HA-Connect');
|
|
98
|
-
expect(instructions).toContain('OMADA');
|
|
99
|
-
expect(instructions).not.toContain('ENTITY QUERIES');
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('should generate instructions for all plugins', () => {
|
|
103
|
-
const instructions = generateInstructions({
|
|
104
|
-
haEnabled: true,
|
|
105
|
-
omadaEnabled: true,
|
|
106
|
-
aiEnabled: true,
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
expect(instructions).toContain('MCP-HA-Connect');
|
|
110
|
-
expect(instructions).toContain('ENTITY QUERIES');
|
|
111
|
-
expect(instructions).toContain('OMADA');
|
|
112
|
-
expect(instructions).toContain('AI ANALYSIS');
|
|
113
|
-
expect(instructions).toContain('INTEGRATION');
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('should generate concise instructions under the size ceiling', () => {
|
|
117
|
-
const instructions = generateInstructions({
|
|
118
|
-
haEnabled: true,
|
|
119
|
-
omadaEnabled: true,
|
|
120
|
-
aiEnabled: true,
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
// Keep in sync with tests/server/instructions.test.ts — the ceiling was
|
|
124
|
-
// raised 2000 -> 2200 in v1.6.0 (ACTIONS line); this integration twin was
|
|
125
|
-
// stale until the suite was actually run (2026-07-11).
|
|
126
|
-
expect(instructions.length).toBeLessThan(2200);
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
describe('Client Connectivity', () => {
|
|
131
|
-
it('should verify HA connection', async () => {
|
|
132
|
-
if (!haClient) {
|
|
133
|
-
console.log('Skipping: HA not configured');
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const result = await haClient.checkApi();
|
|
138
|
-
expect(result.message).toBe('API running.');
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it('should verify Omada connection', async () => {
|
|
142
|
-
if (!omadaClient) {
|
|
143
|
-
console.log('Skipping: Omada not configured');
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const sites = await omadaClient.listSites();
|
|
148
|
-
expect(sites.length).toBeGreaterThan(0);
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
});
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import type { EnvironmentConfig } from '../../src/config.js';
|
|
3
|
-
import type { AIProviderType } from '../../src/localAI/types.js';
|
|
4
|
-
|
|
5
|
-
// Create mock functions that will be used by the mock implementations
|
|
6
|
-
const mockOllamaAnalyze = vi.fn();
|
|
7
|
-
const mockOllamaHealth = vi.fn();
|
|
8
|
-
const mockOpenAIAnalyze = vi.fn();
|
|
9
|
-
const mockOpenAIHealth = vi.fn();
|
|
10
|
-
|
|
11
|
-
// Mock the providers with class-style constructors
|
|
12
|
-
vi.mock('../../src/localAI/providers/ollama.js', () => {
|
|
13
|
-
return {
|
|
14
|
-
OllamaProvider: class MockOllamaProvider {
|
|
15
|
-
analyzeSensors = mockOllamaAnalyze;
|
|
16
|
-
checkHealth = mockOllamaHealth;
|
|
17
|
-
getProviderName() {
|
|
18
|
-
return 'ollama';
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
vi.mock('../../src/localAI/providers/openai.js', () => {
|
|
25
|
-
return {
|
|
26
|
-
OpenAICompatibleProvider: class MockOpenAIProvider {
|
|
27
|
-
analyzeSensors = mockOpenAIAnalyze;
|
|
28
|
-
checkHealth = mockOpenAIHealth;
|
|
29
|
-
getProviderName() {
|
|
30
|
-
return 'openai-compatible';
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
import { LocalAIClient } from '../../src/localAI/index.js';
|
|
37
|
-
|
|
38
|
-
describe('LocalAIClient', () => {
|
|
39
|
-
const createConfig = (provider: AIProviderType = 'ollama'): EnvironmentConfig =>
|
|
40
|
-
({
|
|
41
|
-
aiProvider: provider,
|
|
42
|
-
aiUrl: 'http://ollama.10.0.0.17.nip.io:11434',
|
|
43
|
-
aiModel: 'qwen3:14b',
|
|
44
|
-
aiTimeout: 60000,
|
|
45
|
-
aiApiKey: undefined,
|
|
46
|
-
// Other required config fields
|
|
47
|
-
baseUrl: 'http://homeassistant.10.0.0.19.nip.io:8123',
|
|
48
|
-
token: 'test-token',
|
|
49
|
-
strictSsl: true,
|
|
50
|
-
timeout: 30000,
|
|
51
|
-
logLevel: 'info',
|
|
52
|
-
logFormat: 'plain',
|
|
53
|
-
useHttp: false,
|
|
54
|
-
stateful: false,
|
|
55
|
-
|
|
56
|
-
httpEnableHealthcheck: true,
|
|
57
|
-
httpAllowCors: true,
|
|
58
|
-
}) as EnvironmentConfig;
|
|
59
|
-
|
|
60
|
-
beforeEach(() => {
|
|
61
|
-
vi.clearAllMocks();
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
describe('constructor', () => {
|
|
65
|
-
it('should create OllamaProvider for ollama provider type', () => {
|
|
66
|
-
const config = createConfig('ollama');
|
|
67
|
-
const client = new LocalAIClient(config);
|
|
68
|
-
|
|
69
|
-
expect(client.getProviderName()).toBe('ollama');
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should create OpenAICompatibleProvider for openai provider type', () => {
|
|
73
|
-
const config = createConfig('openai');
|
|
74
|
-
const client = new LocalAIClient(config);
|
|
75
|
-
|
|
76
|
-
expect(client.getProviderName()).toBe('openai-compatible');
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should default to OllamaProvider when provider is unknown', () => {
|
|
80
|
-
const config = createConfig('ollama');
|
|
81
|
-
// Force unknown provider
|
|
82
|
-
(config as unknown as { aiProvider: string }).aiProvider = 'unknown';
|
|
83
|
-
const client = new LocalAIClient(config);
|
|
84
|
-
|
|
85
|
-
// Should fall back to ollama
|
|
86
|
-
expect(client.getProviderName()).toBe('ollama');
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
describe('analyzeSensors', () => {
|
|
91
|
-
it('should delegate to the provider', async () => {
|
|
92
|
-
const mockResult = {
|
|
93
|
-
severity: 'critical' as const,
|
|
94
|
-
issue: 'Test issue',
|
|
95
|
-
reasoning: 'Test reasoning',
|
|
96
|
-
recommended_actions: [],
|
|
97
|
-
ssh_diagnostics: [],
|
|
98
|
-
confidence: 0.9,
|
|
99
|
-
model: 'qwen3:14b',
|
|
100
|
-
provider: 'ollama',
|
|
101
|
-
response_time: 1.5,
|
|
102
|
-
};
|
|
103
|
-
mockOllamaAnalyze.mockResolvedValueOnce(mockResult);
|
|
104
|
-
|
|
105
|
-
const config = createConfig('ollama');
|
|
106
|
-
const client = new LocalAIClient(config);
|
|
107
|
-
const sensors = { 'sensor.test': { state: '25' } };
|
|
108
|
-
|
|
109
|
-
const result = await client.analyzeSensors(sensors);
|
|
110
|
-
|
|
111
|
-
expect(mockOllamaAnalyze).toHaveBeenCalledWith(sensors);
|
|
112
|
-
expect(result).toEqual(mockResult);
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
describe('checkHealth', () => {
|
|
117
|
-
it('should delegate to the provider', async () => {
|
|
118
|
-
mockOllamaHealth.mockResolvedValueOnce(true);
|
|
119
|
-
|
|
120
|
-
const config = createConfig('ollama');
|
|
121
|
-
const client = new LocalAIClient(config);
|
|
122
|
-
|
|
123
|
-
const result = await client.checkHealth();
|
|
124
|
-
|
|
125
|
-
expect(mockOllamaHealth).toHaveBeenCalled();
|
|
126
|
-
expect(result).toBe(true);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('should return false when provider is unhealthy', async () => {
|
|
130
|
-
mockOllamaHealth.mockResolvedValueOnce(false);
|
|
131
|
-
|
|
132
|
-
const config = createConfig('ollama');
|
|
133
|
-
const client = new LocalAIClient(config);
|
|
134
|
-
|
|
135
|
-
const result = await client.checkHealth();
|
|
136
|
-
|
|
137
|
-
expect(result).toBe(false);
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
describe('getModelName', () => {
|
|
142
|
-
it('should return the configured model name', () => {
|
|
143
|
-
const config = createConfig('ollama');
|
|
144
|
-
config.aiModel = 'phi4:14b';
|
|
145
|
-
const client = new LocalAIClient(config);
|
|
146
|
-
|
|
147
|
-
expect(client.getModelName()).toBe('phi4:14b');
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
describe('getConfig', () => {
|
|
152
|
-
it('should return the provider configuration', () => {
|
|
153
|
-
const config = createConfig('ollama');
|
|
154
|
-
config.aiApiKey = 'test-key';
|
|
155
|
-
const client = new LocalAIClient(config);
|
|
156
|
-
|
|
157
|
-
const providerConfig = client.getConfig();
|
|
158
|
-
|
|
159
|
-
expect(providerConfig.provider).toBe('ollama');
|
|
160
|
-
expect(providerConfig.baseUrl).toBe('http://ollama.10.0.0.17.nip.io:11434');
|
|
161
|
-
expect(providerConfig.model).toBe('qwen3:14b');
|
|
162
|
-
expect(providerConfig.timeout).toBe(60000);
|
|
163
|
-
expect(providerConfig.apiKey).toBe('test-key');
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it('should return a copy of the config (immutable)', () => {
|
|
167
|
-
const config = createConfig('ollama');
|
|
168
|
-
const client = new LocalAIClient(config);
|
|
169
|
-
|
|
170
|
-
const providerConfig1 = client.getConfig();
|
|
171
|
-
const providerConfig2 = client.getConfig();
|
|
172
|
-
|
|
173
|
-
expect(providerConfig1).not.toBe(providerConfig2);
|
|
174
|
-
expect(providerConfig1).toEqual(providerConfig2);
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
});
|