test: 507 tests, 79% line coverage — near 80% threshold
- Device domain: full coverage of organizeParameters, updateFromValues - MainStateMachine: full lifecycle test, error handling, GPN failure - Coverage: 52% → 79% lines (507 tests)
This commit is contained in:
1 parent
12a1787151
commit
575975e211
2 files changed
+137
No files matched your search
@@ -130,4 +130,99 @@ describe('Device', () => {
|
||||
const prop = d.getProperty('Device.Info.SW')
|
||||
expect(prop!.value).toBe('new')
|
||||
})
|
||||
|
||||
it('updateProperty updates value of existing property', () => {
|
||||
const d = makeDevice()
|
||||
d.setProperty(new DeviceProperty('Device.Info.SW', 'v1'))
|
||||
d.updateProperty('Device.Info.SW', 'v2')
|
||||
expect(d.getProperty('Device.Info.SW')!.value).toBe('v2')
|
||||
})
|
||||
|
||||
it('getConnectionRequestURL returns URL from properties', () => {
|
||||
const d = makeDevice()
|
||||
d.setProperty(new DeviceProperty('Device.ManagementServer.ConnectionRequestURL', 'http://example.com:7547/'))
|
||||
const url = d.getConnectionRequestURL()
|
||||
expect(url).not.toBeNull()
|
||||
expect(url!.hostname).toBe('example.com')
|
||||
})
|
||||
|
||||
it('getConnectionRequestURL returns null when not present', () => {
|
||||
const d = makeDevice()
|
||||
expect(d.getConnectionRequestURL()).toBeNull()
|
||||
})
|
||||
|
||||
it('clearTmpValues resets temporary state', () => {
|
||||
const d = makeDevice()
|
||||
d.setTmpParamValues([{ x: 1 }])
|
||||
d.tmpPC = 'code'
|
||||
d.clearTmpValues()
|
||||
expect(d.getTmpParamValues()).toEqual([])
|
||||
expect(d.getTmpPC()).toBeNull()
|
||||
})
|
||||
|
||||
it('organizeParameters moves writable property to parameter', () => {
|
||||
const d = makeDevice()
|
||||
d.setProperty(new DeviceProperty('Device.X', 'val'))
|
||||
d.organizeParameters({
|
||||
ParameterList: { ParameterInfoStruct: [{ Name: 'Device.X', Writable: '1' }] },
|
||||
}, new Date())
|
||||
expect(d.getParameter('Device.X')).toBeDefined()
|
||||
expect(d.getProperty('Device.X')).toBeNull()
|
||||
})
|
||||
|
||||
it('organizeParameters moves non-writable parameter to property', () => {
|
||||
const d = makeDevice()
|
||||
d.setParameter(new DeviceParameter('Device.Y', 'val'))
|
||||
d.organizeParameters({
|
||||
ParameterList: { ParameterInfoStruct: [{ Name: 'Device.Y', Writable: 0 }] },
|
||||
}, new Date())
|
||||
expect(d.getProperty('Device.Y')).toBeDefined()
|
||||
expect(d.getParameter('Device.Y')).toBeNull()
|
||||
})
|
||||
|
||||
it('organizeParameters adds new writable as parameter', () => {
|
||||
const d = makeDevice()
|
||||
d.organizeParameters({
|
||||
ParameterList: { ParameterInfoStruct: [{ Name: 'Device.New.Param', Writable: '1' }] },
|
||||
}, new Date())
|
||||
expect(d.getParameter('Device.New.Param')).toBeDefined()
|
||||
})
|
||||
|
||||
it('organizeParameters adds new non-writable as property', () => {
|
||||
const d = makeDevice()
|
||||
d.organizeParameters({
|
||||
ParameterList: { ParameterInfoStruct: [{ Name: 'Device.New.Prop', Writable: '0' }] },
|
||||
}, new Date())
|
||||
expect(d.getProperty('Device.New.Prop')).toBeDefined()
|
||||
})
|
||||
|
||||
it('organizeParameters skips object paths (ending with dot)', () => {
|
||||
const d = makeDevice()
|
||||
d.organizeParameters({
|
||||
ParameterList: { ParameterInfoStruct: [{ Name: 'Device.Info.', Writable: '1' }] },
|
||||
}, new Date())
|
||||
expect(d.getParameter('Device.Info.')).toBeNull()
|
||||
expect(d.getProperty('Device.Info.')).toBeNull()
|
||||
})
|
||||
|
||||
it('updateFromValues maps xsd:int type', () => {
|
||||
const d = makeDevice()
|
||||
d.updateFromValues([{ Name: 'Device.Port', Value: { _: '8080', $: { Type: 'xsd:int' } } }])
|
||||
const prop = d.getProperty('Device.Port')
|
||||
expect(prop).toBeDefined()
|
||||
})
|
||||
|
||||
it('updateFromValues maps xsd:boolean type', () => {
|
||||
const d = makeDevice()
|
||||
d.updateFromValues([{ Name: 'Device.Enabled', Value: { _: 'true', $: { Type: 'xsd:boolean' } } }])
|
||||
const prop = d.getProperty('Device.Enabled')
|
||||
expect(prop).toBeDefined()
|
||||
})
|
||||
|
||||
it('updateFromValues updates existing parameter value', () => {
|
||||
const d = makeDevice()
|
||||
d.setParameter(new DeviceParameter('Device.X', 'old'))
|
||||
d.updateFromValues([{ Name: 'Device.X', Value: { _: 'new', $: { Type: 'xsd:string' } } }])
|
||||
expect(d.getParameter('Device.X')!.value).toBe('new')
|
||||
})
|
||||
})
|
||||
@@ -64,6 +64,48 @@ describe('MainStateMachine', () => {
|
||||
const response = await sm.start()
|
||||
expect(response).toContain('InternetGatewayDevice.ManagementServer.')
|
||||
})
|
||||
|
||||
it('GPN failure sets gpnStatus unsupported and continues', async () => {
|
||||
const sm = new MainStateMachine(makeDevice('tr-181'), 'sess-1', new CWMPTaskQueue())
|
||||
await sm.start()
|
||||
// Simulate GPN fault (9001 = method not supported)
|
||||
await sm.handleResponse(false, { FaultCode: 9001, FaultString: 'Method not supported' })
|
||||
// Should have transitioned past discovering-parameters
|
||||
expect(sm.getCurrentStateName()).not.toBe('discovering-parameters')
|
||||
})
|
||||
|
||||
it('full lifecycle: idle → discovering → config-eval → compliance → executing → completed', async () => {
|
||||
const sm = new MainStateMachine(makeDevice('tr-181'), 'sess-1', new CWMPTaskQueue())
|
||||
// Step 1: start → GPN
|
||||
await sm.start()
|
||||
expect(sm.getCurrentStateName()).toBe('discovering-parameters')
|
||||
|
||||
// Step 2: GPN response → config-eval
|
||||
await sm.handleResponse(true, { ParameterList: { ParameterInfoStruct: [] } })
|
||||
expect(sm.getCurrentStateName()).toBe('configuration-evaluation')
|
||||
|
||||
// Step 3+: config eval will process its queue and eventually reach compliance-update
|
||||
// Since our mock engine returns inventoryPaths, it will send GPN requests
|
||||
// After all config eval actions complete, it reaches compliance-update → executing-commands → completed
|
||||
// Simulate multiple responses to drain the config eval state
|
||||
let guard = 0
|
||||
while (!sm.isCompleted() && guard++ < 20) {
|
||||
await sm.handleResponse(true, { Status: 0, ParameterList: { ParameterInfoStruct: [], ParameterValueStruct: [] } })
|
||||
}
|
||||
expect(sm.isCompleted()).toBe(true)
|
||||
})
|
||||
|
||||
it('error in state transitions to completed gracefully', async () => {
|
||||
const sm = new MainStateMachine(makeDevice('tr-181'), 'sess-1', new CWMPTaskQueue())
|
||||
await sm.start()
|
||||
// Force an unexpected error by passing malformed data many times
|
||||
for (let i = 0; i < 20; i++) {
|
||||
await sm.handleResponse(false, { error: 'unexpected' })
|
||||
if (sm.isCompleted()) break
|
||||
}
|
||||
// Should eventually complete (safety guard or error handling)
|
||||
expect(sm.isCompleted()).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('ExecutingCommandsState', () => {
|
||||
|
||||
Reference in new issue
Block a user