Add 3 regression tests for GPN-unsupported + catalog classification flow: 1) GPN fault triggers catalog + persists to DB, 2) subsequent session with same params skips GPN, 3) new param in Inform triggers catalog for unclassified only. All 814 tests pass. Build status: Success

This commit is contained in:
ATX Bot committed 2026-06-09 09:36:25 +02:00
1 parent a9c7bcf643
commit e43b493eff
1 file changed
+133
@@ -265,3 +265,136 @@ describe('Two-session scenario: same device, first contact then reconnect', () =
console.log(` Skipped: GPN test, inventory, SPV, ProvisioningCode`)
})
})
import DeviceModel from '../../../../app/models/device.js'
describe('GPN unsupported → catalog classification + persistence', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('GPN fault triggers catalog reclassification and persists to DB', async () => {
// Simulate a Livebox 4 (tr-181) device with Inform params
const device = new Device(new DeviceId('Sagemcom', 'F8B7FF', 'Livebox 4', 'LB4-TEST-001'))
device.setDataModel('tr-181')
const informParams = [
{ Name: 'Device.DeviceInfo.HardwareVersion', Value: { _: 'v3.0' } },
{ Name: 'Device.DeviceInfo.SoftwareVersion', Value: { _: 'SR50-5.0.0' } },
{ Name: 'Device.ManagementServer.ConnectionRequestURL', Value: { _: 'http://cpe:7547/' } },
{ Name: 'Device.ManagementServer.PeriodicInformInterval', Value: { _: '60' } },
]
device.updateFromValues(informParams)
device.setTmpParamValues(informParams)
// gpnStatus = 'unknown' → will attempt GPN
const taskQueue = new CWMPTaskQueue()
const sm = new MainStateMachine(device, 'session-gpn-fail', taskQueue)
// Step 1: start → sends GPN for Device.DeviceInfo. (first unclassified path)
const step1 = await sm.start()
expect(step1).toContain('GetParameterNames')
expect(sm.getCurrentStateName()).toBe('discovering-parameters')
// Step 2: GPN Fault → mark unsupported + catalog classify + persist
const step2 = await sm.handleResponse(false, {
FaultCode: 9003,
FaultString: 'Method not supported',
})
// Verify: reclassifyDeviceFromCatalog was called
expect(vi.mocked(reclassifyDeviceFromCatalog)).toHaveBeenCalledWith(device)
// Verify: DeviceModel.createOrUpdate was called to persist the classification
expect(vi.mocked(DeviceModel.createOrUpdate)).toHaveBeenCalledWith(
expect.objectContaining({
gpnStatus: 'unsupported',
gpnCircuitBreaker: expect.objectContaining({ failureCount: 1 }),
})
)
// Verify: device is marked as unsupported
expect(device.gpnStatus).toBe('unsupported')
expect(device.gpnCircuitBreaker.failureCount).toBe(1)
// Verify: transitioned to critical-reads (sends GPV)
expect(step2).toContain('GetParameterValues')
expect(sm.getCurrentStateName()).toBe('critical-reads')
})
it('subsequent session with same params skips GPN (all classified)', async () => {
// Simulate device loaded from DB after first session (already classified)
const device = new Device(new DeviceId('Sagemcom', 'F8B7FF', 'Livebox 4', 'LB4-TEST-001'))
device.setDataModel('tr-181')
device.setGpnStatus('unsupported')
// After catalog classification, PeriodicInformInterval is a parameter (writable)
device.setParameter(new DeviceParameter(
'Device.ManagementServer.PeriodicInformInterval', '300', ParameterType.UNSIGNED_INT
))
// Read-only params are properties
device.setProperty(new DeviceProperty('Device.DeviceInfo.HardwareVersion', 'v3.0', ParameterType.STRING))
device.setProperty(new DeviceProperty('Device.DeviceInfo.SoftwareVersion', 'SR50-5.0.0', ParameterType.STRING))
device.setProperty(new DeviceProperty('Device.ManagementServer.ConnectionRequestURL', 'http://cpe:7547/', ParameterType.STRING))
// Inform arrives with same params (all already classified)
const informParams = [
{ Name: 'Device.DeviceInfo.HardwareVersion', Value: { _: 'v3.0' } },
{ Name: 'Device.DeviceInfo.SoftwareVersion', Value: { _: 'SR50-5.0.0' } },
{ Name: 'Device.ManagementServer.ConnectionRequestURL', Value: { _: 'http://cpe:7547/' } },
{ Name: 'Device.ManagementServer.PeriodicInformInterval', Value: { _: '300' } },
]
device.updateFromValues(informParams)
device.setTmpParamValues(informParams)
const taskQueue = new CWMPTaskQueue()
const sm = new MainStateMachine(device, 'session-2', taskQueue)
// Start → all params classified → skip GPN → directly to critical-reads (GPV)
const step1 = await sm.start()
expect(step1).toContain('GetParameterValues')
expect(step1).not.toContain('GetParameterNames')
expect(sm.getCurrentStateName()).toBe('critical-reads')
// reclassifyDeviceFromCatalog should NOT have been called
expect(vi.mocked(reclassifyDeviceFromCatalog)).not.toHaveBeenCalled()
})
it('session with NEW param in Inform (not yet in properties) triggers catalog classification', async () => {
// Device already classified from previous session
const device = new Device(new DeviceId('Sagemcom', 'F8B7FF', 'Livebox 4', 'LB4-TEST-001'))
device.setDataModel('tr-181')
device.setGpnStatus('unsupported')
device.setGpnCircuitBreaker({ failureCount: 1, lastFailureDate: new Date(), state: 'closed', cooldownUntil: null })
// Existing classified params
device.setParameter(new DeviceParameter('Device.ManagementServer.PeriodicInformInterval', '300', ParameterType.UNSIGNED_INT))
device.setProperty(new DeviceProperty('Device.DeviceInfo.HardwareVersion', 'v3.0', ParameterType.STRING))
device.setProperty(new DeviceProperty('Device.ManagementServer.ConnectionRequestURL', 'http://cpe:7547/', ParameterType.STRING))
// New Inform arrives with a NEW param that is NOT in _parameters/_properties
// (simulating a param that wasn't in the previous Inform and wasn't stored by updateFromValues)
const informParams = [
{ Name: 'Device.DeviceInfo.HardwareVersion', Value: { _: 'v3.0' } },
{ Name: 'Device.ManagementServer.ConnectionRequestURL', Value: { _: 'http://cpe:7547/' } },
{ Name: 'Device.ManagementServer.PeriodicInformInterval', Value: { _: '300' } },
{ Name: 'Device.WANDevice.1.ExternalIPAddress', Value: { _: '192.168.1.1' } }, // NEW - not in device yet
]
// Only set tmpParamValues WITHOUT updateFromValues for the new param
device.setTmpParamValues(informParams)
const taskQueue = new CWMPTaskQueue()
const sm = new MainStateMachine(device, 'session-new-param', taskQueue)
// Start → detects 1 unclassified param (WANDevice not in _parameters/_properties)
// GPN unsupported → catalog classify
const step1 = await sm.start()
// Should have called catalog to classify the new param
expect(vi.mocked(reclassifyDeviceFromCatalog)).toHaveBeenCalledWith(device)
// Should go to critical-reads (GPV)
expect(step1).toContain('GetParameterValues')
expect(sm.getCurrentStateName()).toBe('critical-reads')
})
})