- task_queue: task lifecycle, events, all SOAP builders, clear pending - device_action_executor: all action methods, callbacks (GPV/GPN/SPV) - reference_engine: resolveAll, resolveOne, trigger matching, numeric events - Coverage: 52% → 67% statements, 428 tests passing
178 lines
6.4 KiB
TypeScript
178 lines
6.4 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
import { DeviceActionExecutor } from '../../../../app/services/cwmp/device_action_executor.js'
|
|
import { CWMPTaskQueue, ResultStatus, TaskResult } from '../../../../app/services/cwmp/task_queue.js'
|
|
import { Device } from '../../../../app/domain/device/device.js'
|
|
import { DeviceId } from '../../../../app/domain/device/device_id.js'
|
|
|
|
// Mock AdonisJS logger
|
|
vi.mock('@adonisjs/core/services/logger', () => ({
|
|
default: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
|
|
}))
|
|
|
|
// Mock DeviceModel to avoid MongoDB dependency
|
|
vi.mock('../../../../app/models/device.js', () => ({
|
|
default: { createOrUpdate: vi.fn().mockResolvedValue(undefined) },
|
|
}))
|
|
|
|
function makeDevice(): Device {
|
|
return new Device(new DeviceId('TestMfr', 'AABBCC', 'TestBox', 'SN001'))
|
|
}
|
|
|
|
describe('DeviceActionExecutor', () => {
|
|
let queue: CWMPTaskQueue
|
|
let executor: DeviceActionExecutor
|
|
|
|
beforeEach(() => {
|
|
queue = new CWMPTaskQueue()
|
|
executor = new DeviceActionExecutor(queue)
|
|
})
|
|
|
|
describe('getParameterValues', () => {
|
|
it('returns SOAP XML for GPV', async () => {
|
|
const device = makeDevice()
|
|
const xml = await executor.getParameterValues(device, ['Device.Info.SW'], async () => '')
|
|
expect(xml).toContain('GetParameterValues')
|
|
expect(xml).toContain('Device.Info.SW')
|
|
})
|
|
})
|
|
|
|
describe('getParameterNames', () => {
|
|
it('returns SOAP XML for GPN', async () => {
|
|
const device = makeDevice()
|
|
const xml = await executor.getParameterNames(device, 'Device.ManagementServer.', async () => '')
|
|
expect(xml).toContain('GetParameterNames')
|
|
expect(xml).toContain('Device.ManagementServer.')
|
|
})
|
|
})
|
|
|
|
describe('getParameterAttributes', () => {
|
|
it('returns SOAP XML for GPA', async () => {
|
|
const device = makeDevice()
|
|
const xml = await executor.getParameterAttributes(device, ['Device.Info.'], async () => '')
|
|
expect(xml).toContain('GetParameterAttributes')
|
|
})
|
|
})
|
|
|
|
describe('applySetParameterValues', () => {
|
|
it('returns SOAP XML for SPV', async () => {
|
|
const device = makeDevice()
|
|
const xml = await executor.applySetParameterValues(
|
|
device,
|
|
[{ parameterName: 'Device.X', value: '42', type: 'unsignedInt' }],
|
|
async () => ''
|
|
)
|
|
expect(xml).toContain('SetParameterValues')
|
|
expect(xml).toContain('Device.X')
|
|
})
|
|
})
|
|
|
|
describe('applySetParameterAttributes', () => {
|
|
it('returns SOAP XML for SPA', async () => {
|
|
const device = makeDevice()
|
|
const xml = await executor.applySetParameterAttributes(
|
|
device,
|
|
[{ name: 'Device.X', notificationChange: true, notification: 2, accessListChange: false, accessList: [] }],
|
|
async () => ''
|
|
)
|
|
expect(xml).toContain('SetParameterAttributes')
|
|
})
|
|
})
|
|
|
|
describe('applyScheduleInform', () => {
|
|
it('returns SOAP XML for ScheduleInform', async () => {
|
|
const device = makeDevice()
|
|
const xml = await executor.applyScheduleInform(device, { delayInSeconds: 300 }, async () => '')
|
|
expect(xml).toContain('ScheduleInform')
|
|
expect(xml).toContain('300')
|
|
})
|
|
})
|
|
|
|
describe('applyReboot', () => {
|
|
it('returns SOAP XML for Reboot', async () => {
|
|
const device = makeDevice()
|
|
const xml = await executor.applyReboot(device, { commandKey: 'reboot-1' }, async () => '')
|
|
expect(xml).toContain('Reboot')
|
|
expect(xml).toContain('reboot-1')
|
|
})
|
|
})
|
|
|
|
describe('applyFactoryReset', () => {
|
|
it('returns SOAP XML for FactoryReset', async () => {
|
|
const device = makeDevice()
|
|
const xml = await executor.applyFactoryReset(device, {}, async () => '')
|
|
expect(xml).toContain('FactoryReset')
|
|
})
|
|
})
|
|
|
|
describe('applyDownload', () => {
|
|
it('returns SOAP XML for Download', async () => {
|
|
const device = makeDevice()
|
|
const xml = await executor.applyDownload(
|
|
device,
|
|
{ commandKey: 'fw', fileType: '1 Firmware Upgrade Image', url: 'http://fw.bin' },
|
|
async () => ''
|
|
)
|
|
expect(xml).toContain('Download')
|
|
expect(xml).toContain('http://fw.bin')
|
|
})
|
|
})
|
|
|
|
describe('applyUpload', () => {
|
|
it('returns SOAP XML for Upload', async () => {
|
|
const device = makeDevice()
|
|
const xml = await executor.applyUpload(
|
|
device,
|
|
{ commandKey: 'cfg', fileType: '3 Vendor Configuration File', url: 'http://up.bin' },
|
|
async () => ''
|
|
)
|
|
expect(xml).toContain('Upload')
|
|
expect(xml).toContain('http://up.bin')
|
|
})
|
|
})
|
|
|
|
describe('insertProvisioningCode', () => {
|
|
it('returns SOAP XML for SPV with provisioning code', async () => {
|
|
const device = makeDevice()
|
|
device.setDataModel('tr-181')
|
|
device.tmpPC = 'my-prov-code'
|
|
const xml = await executor.insertProvisioningCode(device, async () => '')
|
|
expect(xml).toContain('SetParameterValues')
|
|
expect(xml).toContain('ProvisioningCode')
|
|
})
|
|
})
|
|
|
|
describe('callbacks', () => {
|
|
it('GPV callback updates device on success', async () => {
|
|
const device = makeDevice()
|
|
let callbackCalled = false
|
|
executor.getParameterValues(device, ['Device.Info.SW'], async () => { callbackCalled = true; return '' })
|
|
|
|
// Simulate task completion
|
|
const task = queue.getTaskForDevice(device.deviceId)
|
|
expect(task).toBeDefined()
|
|
await queue.executeTaskCallback(task!.id, ResultStatus.Success, {
|
|
ParameterList: { ParameterValueStruct: [{ Name: 'Device.Info.SW', Value: { _: '2.0', $: { Type: 'xsd:string' } } }] },
|
|
})
|
|
expect(callbackCalled).toBe(true)
|
|
})
|
|
|
|
it('GPN callback sets gpnStatus to supported on success', async () => {
|
|
const device = makeDevice()
|
|
executor.getParameterNames(device, 'Device.', async () => '')
|
|
const task = queue.getTaskForDevice(device.deviceId)
|
|
await queue.executeTaskCallback(task!.id, ResultStatus.Success, {
|
|
ParameterList: { ParameterInfoStruct: [{ Name: 'Device.Info.SW', Writable: '1' }] },
|
|
})
|
|
expect(device.gpnStatus).toBe('supported')
|
|
})
|
|
|
|
it('GPN callback sets gpnStatus to unsupported on fault 9001', async () => {
|
|
const device = makeDevice()
|
|
executor.getParameterNames(device, 'Device.', async () => '')
|
|
const task = queue.getTaskForDevice(device.deviceId)
|
|
await queue.executeTaskCallback(task!.id, ResultStatus.Error, { FaultCode: 9001 })
|
|
expect(device.gpnStatus).toBe('unsupported')
|
|
})
|
|
})
|
|
})
|