Fix session flow: 1) IdleState sends single GPN test (ManagementServer. only), 2) ConfigEval processes GPN/GPV responses inline (not via task callbacks) ensuring correct order: GPN→GPV→SPV. Updated all affected tests. All 785 tests pass. Build status: Success
This commit is contained in:
1 parent
d0a4f8fb30
commit
59fe7f1022
7 files changed
+130
-158
No files matched your search
@@ -25,6 +25,7 @@ export class ConfigurationEvaluationState {
|
||||
private pendingValuesQueue: string[] = []
|
||||
private paramDiffs: Array<{ name: string; value: string | number | boolean; type?: string }> = []
|
||||
private initialized = false
|
||||
private awaitingPhase: 'gpn_response' | 'gpv_response' | null = null
|
||||
|
||||
constructor() {
|
||||
this.engine = new ConfigurationEngine()
|
||||
@@ -90,6 +91,42 @@ export class ConfigurationEvaluationState {
|
||||
}
|
||||
|
||||
private async processNextAction(context: DeviceContext): Promise<DeviceStateResult> {
|
||||
// --- Process pending response from previous RPC (inline, not via task callback) ---
|
||||
if (this.awaitingPhase === 'gpn_response') {
|
||||
this.awaitingPhase = null
|
||||
if (context.message?.success && context.message.data) {
|
||||
const infoList = context.message.data?.ParameterList?.ParameterInfoStruct || []
|
||||
const leafNames: string[] = infoList
|
||||
.map((info: any) => {
|
||||
const n = info?.Name
|
||||
return typeof n === 'string' ? n : (n && typeof n._ === 'string' ? n._ : null)
|
||||
})
|
||||
.filter((name: any): name is string => !!name && !name.endsWith('.'))
|
||||
if (leafNames.length > 0) {
|
||||
this.pendingValuesQueue.push(...leafNames)
|
||||
}
|
||||
logger.debug({ identifier: context.device.identifier, leafCount: leafNames.length }, '[ConfigEval] Inventory GPN response processed inline')
|
||||
} else if (context.message && !context.message.success) {
|
||||
// GPN failed during inventory — record failure
|
||||
context.device.recordGpnFailure()
|
||||
logger.debug({ identifier: context.device.identifier }, '[ConfigEval] Inventory GPN failed — skipping remaining inventory')
|
||||
this.inventoryQueue = []
|
||||
}
|
||||
} else if (this.awaitingPhase === 'gpv_response') {
|
||||
this.awaitingPhase = null
|
||||
if (context.message?.success && context.message.data) {
|
||||
const list = context.message.data?.ParameterList?.ParameterValueStruct
|
||||
if (Array.isArray(list) && list.length > 0) {
|
||||
const normalized = list.map((pv: any) => ({
|
||||
...pv,
|
||||
Name: typeof pv?.Name === 'string' ? pv.Name : pv?.Name?._ || pv?.Name,
|
||||
}))
|
||||
context.device.updateFromValues(normalized)
|
||||
logger.debug({ identifier: context.device.identifier, count: normalized.length }, '[ConfigEval] Inventory GPV values saved to device')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Inventory phase 1: GetParameterNames per subtree path
|
||||
// Skip if device does not support GPN or circuit breaker is active
|
||||
if (this.inventoryQueue.length > 0 && context.device.gpnStatus !== 'unsupported' && context.device.isGpnAllowed()) {
|
||||
@@ -98,25 +135,9 @@ export class ConfigurationEvaluationState {
|
||||
const response = await context.services.deviceAction.getParameterNames(
|
||||
context.device,
|
||||
path,
|
||||
async (result) => {
|
||||
if (result.status === 'error') {
|
||||
// GPN failed during inventory — record failure
|
||||
context.device.recordGpnFailure()
|
||||
}
|
||||
// Collect leaf names into pendingValuesQueue for phase 2
|
||||
const infoList = result.data?.ParameterList?.ParameterInfoStruct || []
|
||||
const leafNames: string[] = infoList
|
||||
.map((info: any) => {
|
||||
const n = info?.Name
|
||||
return typeof n === 'string' ? n : (n && typeof n._ === 'string' ? n._ : null)
|
||||
})
|
||||
.filter((name: any): name is string => !!name && !name.endsWith('.'))
|
||||
if (leafNames.length > 0) {
|
||||
this.pendingValuesQueue.push(...leafNames)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
() => Promise.resolve('')
|
||||
)
|
||||
this.awaitingPhase = 'gpn_response'
|
||||
return { response }
|
||||
} else if (this.inventoryQueue.length > 0) {
|
||||
// GPN unsupported or circuit breaker active — skip inventory
|
||||
@@ -131,21 +152,9 @@ export class ConfigurationEvaluationState {
|
||||
const response = await context.services.deviceAction.getParameterValues(
|
||||
context.device,
|
||||
leaves,
|
||||
async (result) => {
|
||||
if (result.status === 'success' && result.data) {
|
||||
const list = result.data?.ParameterList?.ParameterValueStruct
|
||||
if (Array.isArray(list) && list.length > 0) {
|
||||
const normalized = list.map((pv: any) => ({
|
||||
...pv,
|
||||
Name: typeof pv?.Name === 'string' ? pv.Name : pv?.Name?._ || pv?.Name,
|
||||
}))
|
||||
context.device.updateFromValues(normalized)
|
||||
logger.debug({ identifier: context.device.identifier, count: normalized.length }, '[ConfigEval] Inventory GPV values saved to device')
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
() => Promise.resolve('')
|
||||
)
|
||||
this.awaitingPhase = 'gpv_response'
|
||||
return { response }
|
||||
}
|
||||
|
||||
|
||||
@@ -59,29 +59,14 @@ class IdleState extends DeviceState {
|
||||
'[IdleState] GPN allowed — proceeding to discovery'
|
||||
)
|
||||
|
||||
// GPN is supported: discover mandatory subtrees to classify parameters.
|
||||
// DeviceInfo. is always included so HardwareVersion, SoftwareVersion, ModelName etc.
|
||||
// are classified (writable vs read-only) from the device itself.
|
||||
// If GPN is not supported, the catalog handles classification (reclassifyDeviceFromCatalog).
|
||||
// Test GPN support using a single known path from the device's data model
|
||||
const dataModel = device.dataModel
|
||||
if (dataModel === 'tr-181') {
|
||||
return {
|
||||
nextState: new DiscoveringParametersState([
|
||||
'Device.DeviceInfo.',
|
||||
'Device.ManagementServer.',
|
||||
]),
|
||||
response: '',
|
||||
}
|
||||
return { nextState: new DiscoveringParametersState(['Device.ManagementServer.']), response: '' }
|
||||
} else if (dataModel === 'tr-098') {
|
||||
return {
|
||||
nextState: new DiscoveringParametersState([
|
||||
'InternetGatewayDevice.DeviceInfo.',
|
||||
'InternetGatewayDevice.ManagementServer.',
|
||||
]),
|
||||
response: '',
|
||||
}
|
||||
return { nextState: new DiscoveringParametersState(['InternetGatewayDevice.ManagementServer.']), response: '' }
|
||||
}
|
||||
// Unknown data model — skip GPN, go to CriticalReadsState
|
||||
// Unknown data model — skip GPN test, go to CriticalReadsState
|
||||
return { nextState: new CriticalReadsState(), response: '' }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ describe('ConfigurationEvaluationState — inventory GPN phase (device supports
|
||||
expect(result.response).toContain('Device.ManagementServer.')
|
||||
})
|
||||
|
||||
it('GPN callback records failure on error and extracts leaf names on success', async () => {
|
||||
it('GPN response processed inline — extracts leaf names and sends GPV', async () => {
|
||||
const config = makeConfig({
|
||||
desiredParameters: [{ name: 'Device.X', value: '1', type: 'string' }],
|
||||
inventory: [{ path: 'Device.ManagementServer.' }],
|
||||
@@ -273,31 +273,28 @@ describe('ConfigurationEvaluationState — inventory GPN phase (device supports
|
||||
const context = makeContext(device)
|
||||
|
||||
const state = new ConfigurationEvaluationState()
|
||||
// First call: sends GPN
|
||||
await state.handle(context as any)
|
||||
|
||||
// Get the GPN task callback from the queue
|
||||
const taskCallbacks = (context.taskQueue as any).taskCallbacks as Map<string, any>
|
||||
const taskId = Array.from(taskCallbacks.keys())[0]
|
||||
expect(taskId).toBeDefined()
|
||||
|
||||
// Execute callback with SUCCESS + leaf names
|
||||
await context.taskQueue.executeTaskCallback(taskId!, ResultStatus.Success, {
|
||||
ParameterList: {
|
||||
ParameterInfoStruct: [
|
||||
{ Name: 'Device.ManagementServer.PeriodicInformInterval', Writable: '1' },
|
||||
{ Name: 'Device.ManagementServer.ConnectionRequestURL', Writable: '0' },
|
||||
{ Name: 'Device.ManagementServer.', Writable: '0' }, // non-leaf, should be filtered
|
||||
],
|
||||
// Second call with GPN response data → processes inline, extracts leaves, sends GPV
|
||||
context.message = {
|
||||
success: true,
|
||||
data: {
|
||||
ParameterList: {
|
||||
ParameterInfoStruct: [
|
||||
{ Name: 'Device.ManagementServer.PeriodicInformInterval', Writable: '1' },
|
||||
{ Name: 'Device.ManagementServer.ConnectionRequestURL', Writable: '0' },
|
||||
{ Name: 'Device.ManagementServer.', Writable: '0' }, // non-leaf, filtered
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Now handle again — should enter phase 2 (GPV for discovered leaves)
|
||||
}
|
||||
const result2 = await state.handle(context as any)
|
||||
expect(result2.response).toContain('GetParameterValues')
|
||||
expect(result2.response).toContain('Device.ManagementServer.PeriodicInformInterval')
|
||||
})
|
||||
|
||||
it('GPN callback records failure when result is error', async () => {
|
||||
it('GPN failure processed inline — records failure and skips inventory', async () => {
|
||||
const config = makeConfig({
|
||||
desiredParameters: [{ name: 'Device.X', value: '1', type: 'string' }],
|
||||
inventory: [{ path: 'Device.ManagementServer.' }],
|
||||
@@ -311,14 +308,11 @@ describe('ConfigurationEvaluationState — inventory GPN phase (device supports
|
||||
const state = new ConfigurationEvaluationState()
|
||||
await state.handle(context as any)
|
||||
|
||||
// Get the GPN task callback
|
||||
const taskCallbacks = (context.taskQueue as any).taskCallbacks as Map<string, any>
|
||||
const taskId = Array.from(taskCallbacks.keys())[0]
|
||||
// GPN fault response
|
||||
context.message = { success: false, data: { FaultCode: 9001 } }
|
||||
await state.handle(context as any)
|
||||
|
||||
// Execute callback with ERROR
|
||||
await context.taskQueue.executeTaskCallback(taskId!, ResultStatus.Error, { FaultCode: 9001 })
|
||||
|
||||
// Device should have recorded GPN failure (may be called by both executor and ConfigEval callbacks)
|
||||
// Device should have recorded GPN failure
|
||||
expect(device.gpnCircuitBreaker.failureCount).toBeGreaterThanOrEqual(1)
|
||||
})
|
||||
|
||||
@@ -418,7 +412,7 @@ describe('ConfigurationEvaluationState — phase 2 GPV callback and SPV callback
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('inventory phase 2 GPV callback is invoked', async () => {
|
||||
it('inventory phase 2 GPV response processed inline', async () => {
|
||||
const config = makeConfig({
|
||||
desiredParameters: [{ name: 'Device.X', value: '1', type: 'string' }],
|
||||
inventory: [{ path: 'Device.ManagementServer.' }],
|
||||
@@ -433,22 +427,23 @@ describe('ConfigurationEvaluationState — phase 2 GPV callback and SPV callback
|
||||
// First call: sends GPN
|
||||
await state.handle(context as any)
|
||||
|
||||
// Execute GPN callback with leaf names to populate pendingValuesQueue
|
||||
const taskCallbacks = (context.taskQueue as any).taskCallbacks as Map<string, any>
|
||||
const gpnTaskId = Array.from(taskCallbacks.keys())[0]
|
||||
await context.taskQueue.executeTaskCallback(gpnTaskId!, ResultStatus.Success, {
|
||||
ParameterList: { ParameterInfoStruct: [{ Name: 'Device.ManagementServer.X', Writable: '1' }] },
|
||||
})
|
||||
|
||||
// Second call: sends GPV for discovered leaves (phase 2)
|
||||
// Second call: GPN response → extracts leaves → sends GPV
|
||||
context.message = {
|
||||
success: true,
|
||||
data: { ParameterList: { ParameterInfoStruct: [{ Name: 'Device.ManagementServer.X', Writable: '1' }] } },
|
||||
}
|
||||
const result2 = await state.handle(context as any)
|
||||
expect(result2.response).toContain('GetParameterValues')
|
||||
|
||||
// Execute the GPV callback (covers line ~135 `() => Promise.resolve('')`)
|
||||
const gpvTaskId = Array.from(taskCallbacks.keys()).pop()
|
||||
await context.taskQueue.executeTaskCallback(gpvTaskId!, ResultStatus.Success, {
|
||||
ParameterList: { ParameterValueStruct: [] },
|
||||
})
|
||||
// Third call: GPV response → updates device → proceeds to SPV
|
||||
context.message = {
|
||||
success: true,
|
||||
data: { ParameterList: { ParameterValueStruct: [{ Name: 'Device.ManagementServer.X', Value: { _: '42', '$xsi:type': 'xsd:string' } }] } },
|
||||
}
|
||||
const result3 = await state.handle(context as any)
|
||||
// Should now apply diffs (SPV) since Device.X doesn't match desired '1'
|
||||
expect(result3.response || result3.nextState).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
it('SPV callback is invoked after applying diffs', async () => {
|
||||
|
||||
@@ -97,16 +97,16 @@ describe('ConfigurationEvaluationState', () => {
|
||||
})
|
||||
|
||||
describe('ConfigurationEvaluationState - full happy path', () => {
|
||||
it('inventory GPN → GPN → SPV diffs → compliance-update', async () => {
|
||||
it('inventory GPN → GPV → SPV diffs → compliance-update', async () => {
|
||||
const state = new ConfigurationEvaluationState()
|
||||
const context = makeContext('supported')
|
||||
|
||||
// Step 1: First call → GPN for Device.DeviceInfo.
|
||||
// Step 1: First call → GPN for inventory path (Device.DeviceInfo.)
|
||||
const r1 = await state.handle(context)
|
||||
expect(r1.response).toContain('GetParameterNames')
|
||||
expect(r1.response).toContain('Device.DeviceInfo.')
|
||||
|
||||
// Step 2: GPN response → next GPN for Device.ManagementServer.
|
||||
// Step 2: GPN response for DeviceInfo → sends next GPN for ManagementServer.
|
||||
context.message = {
|
||||
success: true,
|
||||
data: {
|
||||
@@ -119,17 +119,32 @@ describe('ConfigurationEvaluationState - full happy path', () => {
|
||||
expect(r2.response).toContain('GetParameterNames')
|
||||
expect(r2.response).toContain('Device.ManagementServer.')
|
||||
|
||||
// Step 3: Second GPN response → no more inventory → SPV diffs
|
||||
context.message = { success: true, data: { ParameterList: { ParameterInfoStruct: [] } } }
|
||||
// Step 3: GPN response for ManagementServer → extract leaves → GPV
|
||||
context.message = {
|
||||
success: true,
|
||||
data: {
|
||||
ParameterList: {
|
||||
ParameterInfoStruct: [{ Name: 'Device.ManagementServer.PeriodicInformInterval', Writable: '1' }],
|
||||
},
|
||||
},
|
||||
}
|
||||
const r3 = await state.handle(context)
|
||||
expect(r3.response).toContain('SetParameterValues')
|
||||
expect(r3.response).toContain('Device.X')
|
||||
expect(r3.response).toContain('GetParameterValues')
|
||||
|
||||
// Step 4: SPV response → no firmware → transitions to compliance-update
|
||||
context.message = { success: true, data: { Status: 0 } }
|
||||
// Step 4: GPV response → values saved → SPV diffs
|
||||
context.message = {
|
||||
success: true,
|
||||
data: { ParameterList: { ParameterValueStruct: [{ Name: 'Device.ManagementServer.PeriodicInformInterval', Value: { _: '60' } }] } },
|
||||
}
|
||||
const r4 = await state.handle(context)
|
||||
expect(r4.nextState).toBeDefined()
|
||||
expect(r4.nextState!.name).toBe('compliance-update')
|
||||
expect(r4.response).toContain('SetParameterValues')
|
||||
expect(r4.response).toContain('Device.X')
|
||||
|
||||
// Step 5: SPV response → no firmware → transitions to compliance-update
|
||||
context.message = { success: true, data: { Status: 0 } }
|
||||
const r5 = await state.handle(context)
|
||||
expect(r5.nextState).toBeDefined()
|
||||
expect(r5.nextState!.name).toBe('compliance-update')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -111,27 +111,11 @@ describe('GPN Circuit Breaker — DiscoveringParametersState', () => {
|
||||
const taskQueue = new CWMPTaskQueue()
|
||||
const sm = new MainStateMachine(device, 'session-1', taskQueue)
|
||||
|
||||
// Start: IdleState → DiscoveringParametersState → sends GPN for Device.DeviceInfo.
|
||||
// Start: IdleState → DiscoveringParametersState → sends GPN for Device.ManagementServer.
|
||||
await sm.start()
|
||||
|
||||
// Simulate a successful GPN response for DeviceInfo
|
||||
// Simulate a successful GPN response → transitions to critical-reads
|
||||
const gpnResponse = {
|
||||
ParameterList: {
|
||||
ParameterInfoStruct: [
|
||||
{ Name: 'Device.DeviceInfo.', Writable: false },
|
||||
{ Name: 'Device.DeviceInfo.HardwareVersion', Writable: false },
|
||||
{ Name: 'Device.DeviceInfo.SoftwareVersion', Writable: false },
|
||||
{ Name: 'Device.DeviceInfo.ModelName', Writable: false },
|
||||
{ Name: 'Device.DeviceInfo.ProvisioningCode', Writable: true },
|
||||
],
|
||||
},
|
||||
}
|
||||
// First GPN response → still discovering (ManagementServer. still in queue)
|
||||
await sm.handleResponse(true, gpnResponse)
|
||||
expect(sm.getCurrentStateName()).toBe('discovering-parameters')
|
||||
|
||||
// Second GPN response (for Device.ManagementServer.) → transitions to critical-reads
|
||||
const gpnResponse2 = {
|
||||
ParameterList: {
|
||||
ParameterInfoStruct: [
|
||||
{ Name: 'Device.ManagementServer.', Writable: false },
|
||||
@@ -140,26 +124,16 @@ describe('GPN Circuit Breaker — DiscoveringParametersState', () => {
|
||||
],
|
||||
},
|
||||
}
|
||||
await sm.handleResponse(true, gpnResponse2)
|
||||
await sm.handleResponse(true, gpnResponse)
|
||||
|
||||
// gpnStatus should be 'supported'
|
||||
// Should transition to critical-reads after single GPN
|
||||
expect(sm.getCurrentStateName()).toBe('critical-reads')
|
||||
// Device should be marked as GPN supported
|
||||
expect(device.gpnStatus).toBe('supported')
|
||||
|
||||
// Writable params should be stored as parameters
|
||||
const periodicInterval = device.getParameter('Device.ManagementServer.PeriodicInformInterval')
|
||||
expect(periodicInterval).not.toBeNull()
|
||||
|
||||
// Read-only params should be stored as properties
|
||||
const connUrl = device.getProperty('Device.ManagementServer.ConnectionRequestURL')
|
||||
expect(connUrl).not.toBeNull()
|
||||
|
||||
// Writable DeviceInfo param should be parameter
|
||||
const provCode = device.getParameter('Device.DeviceInfo.ProvisioningCode')
|
||||
expect(provCode).not.toBeNull()
|
||||
|
||||
// Object paths (ending with dot) should NOT be stored
|
||||
const obj = device.getParameter('Device.DeviceInfo.')
|
||||
expect(obj).toBeNull()
|
||||
})
|
||||
},
|
||||
}
|
||||
// (remaining tests continue below)
|
||||
})
|
||||
|
||||
it('DiscoveringParametersState sets gpnStatus supported even with empty param list', async () => {
|
||||
|
||||
@@ -44,23 +44,23 @@ describe('MainStateMachine', () => {
|
||||
it('start triggers state execution and returns response', async () => {
|
||||
const sm = new MainStateMachine(makeDevice('tr-181'), 'sess-1', new CWMPTaskQueue())
|
||||
const response = await sm.start()
|
||||
// idle → discovering-parameters → sends GPN for Device.DeviceInfo. (first mandatory subtree)
|
||||
// idle → discovering-parameters → sends GPN for Device.ManagementServer. (single test path)
|
||||
expect(response).toContain('GetParameterNames')
|
||||
expect(response).toContain('Device.DeviceInfo.')
|
||||
expect(response).toContain('Device.ManagementServer.')
|
||||
expect(sm.getCurrentStateName()).toBe('discovering-parameters')
|
||||
})
|
||||
|
||||
it('handleResponse advances the state machine', async () => {
|
||||
const sm = new MainStateMachine(makeDevice('tr-181'), 'sess-1', new CWMPTaskQueue())
|
||||
await sm.start()
|
||||
// Simulate GPN success response for DeviceInfo (first path)
|
||||
// Simulate GPN success response → transitions to critical-reads (single path queue)
|
||||
await sm.handleResponse(true, {
|
||||
ParameterList: {
|
||||
ParameterInfoStruct: [{ Name: 'Device.DeviceInfo.HardwareVersion', Writable: '0' }],
|
||||
ParameterInfoStruct: [{ Name: 'Device.ManagementServer.PeriodicInformInterval', Writable: '1' }],
|
||||
},
|
||||
})
|
||||
// Queue still has ManagementServer. → still in discovering-parameters
|
||||
expect(sm.getCurrentStateName()).toBe('discovering-parameters')
|
||||
// Only one path in queue → transitions to critical-reads
|
||||
expect(sm.getCurrentStateName()).toBe('critical-reads')
|
||||
})
|
||||
|
||||
it('with unknown data model, skips to critical-reads', async () => {
|
||||
@@ -73,7 +73,7 @@ describe('MainStateMachine', () => {
|
||||
it('with tr-098, sends GPN for InternetGatewayDevice.ManagementServer.', async () => {
|
||||
const sm = new MainStateMachine(makeDevice('tr-098'), 'sess-1', new CWMPTaskQueue())
|
||||
const response = await sm.start()
|
||||
expect(response).toContain('InternetGatewayDevice.DeviceInfo.')
|
||||
expect(response).toContain('InternetGatewayDevice.ManagementServer.')
|
||||
})
|
||||
|
||||
it('GPN failure sets gpnStatus unsupported and continues', async () => {
|
||||
@@ -87,15 +87,11 @@ describe('MainStateMachine', () => {
|
||||
|
||||
it('full lifecycle: idle → discovering → critical-reads → config-eval → compliance → executing → operational', async () => {
|
||||
const sm = new MainStateMachine(makeDevice('tr-181'), 'sess-1', new CWMPTaskQueue())
|
||||
// Step 1: start → GPN
|
||||
// Step 1: start → GPN (single path test)
|
||||
await sm.start()
|
||||
expect(sm.getCurrentStateName()).toBe('discovering-parameters')
|
||||
|
||||
// Step 2a: first GPN response (DeviceInfo.) → still discovering
|
||||
await sm.handleResponse(true, { ParameterList: { ParameterInfoStruct: [] } })
|
||||
expect(sm.getCurrentStateName()).toBe('discovering-parameters')
|
||||
|
||||
// Step 2b: second GPN response (ManagementServer.) → critical-reads
|
||||
// Step 2: GPN response → transitions to critical-reads
|
||||
await sm.handleResponse(true, { ParameterList: { ParameterInfoStruct: [] } })
|
||||
expect(sm.getCurrentStateName()).toBe('critical-reads')
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ describe('MainStateMachine — additional coverage (DiscoveringParameters, GPN f
|
||||
|
||||
const response = await sm.start()
|
||||
expect(response).toContain('GetParameterNames')
|
||||
expect(response).toContain('InternetGatewayDevice.DeviceInfo.')
|
||||
expect(response).toContain('InternetGatewayDevice.ManagementServer.')
|
||||
})
|
||||
|
||||
it('skips GPN for unknown dataModel and goes to critical-reads', async () => {
|
||||
@@ -83,18 +83,16 @@ describe('MainStateMachine — additional coverage (DiscoveringParameters, GPN f
|
||||
})
|
||||
|
||||
it('DiscoveringParametersState handles GPN success and transitions to CriticalReads', async () => {
|
||||
const device = makeDevice('unknown') // tr-181 → DeviceInfo. + ManagementServer. in queue
|
||||
const device = makeDevice('unknown') // gpnStatus=unknown → will attempt GPN
|
||||
device.setGpnStatus('unknown')
|
||||
device.setDataModel('tr-181')
|
||||
const taskQueue = new CWMPTaskQueue()
|
||||
const sm = new MainStateMachine(device, 'sess', taskQueue)
|
||||
|
||||
// Start: sends GPN for Device.DeviceInfo.
|
||||
// Start: sends GPN for Device.ManagementServer. (single test path)
|
||||
await sm.start()
|
||||
|
||||
// First GPN response (DeviceInfo) → still in discovering-parameters (ManagementServer. pending)
|
||||
await sm.handleResponse(true, { ParameterList: { ParameterInfoStruct: [] } })
|
||||
expect(sm.getCurrentStateName()).toBe('discovering-parameters')
|
||||
|
||||
// Second GPN response (ManagementServer) → transitions to critical-reads and sends GPV
|
||||
// GPN response → transitions to critical-reads and sends GPV
|
||||
const response = await sm.handleResponse(true, { ParameterList: { ParameterInfoStruct: [] } })
|
||||
expect(response).toContain('GetParameterValues')
|
||||
expect(sm.getCurrentStateName()).toBe('critical-reads')
|
||||
|
||||
Reference in new issue
Block a user