Files
adam-acs/tests/unit/models/device_model.spec.ts
T
Kevin L'Hereec 12a1787151 test: 492 tests, 78% line coverage
- Device domain: updateFromValues, organizeParameters, identifier
- BaseModel: full CRUD mock tests
- DeviceModel: all methods mocked
- Other models: collectionName verification
- MainStateMachine: start, handleResponse, state transitions
- ConfigurationEvaluationState: init, GPN flow, GPN-unsupported skip
- MongodbProvider: getMongoDb guard
- device_utils: hash determinism
- vitest.config.ts: coverage scope (excludes HTTP layer)
- 492 tests passing, 78% line coverage
2026-06-02 16:45:19 +02:00

142 lines
5.2 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest'
// Mock the mongodb provider before importing the model
const mockCollection = {
findOne: vi.fn(),
find: vi.fn().mockReturnThis(),
countDocuments: vi.fn(),
findOneAndUpdate: vi.fn(),
updateOne: vi.fn(),
updateMany: vi.fn(),
distinct: vi.fn(),
aggregate: vi.fn().mockReturnThis(),
skip: vi.fn().mockReturnThis(),
limit: vi.fn().mockReturnThis(),
sort: vi.fn().mockReturnThis(),
toArray: vi.fn(),
}
const mockDb = {
collection: vi.fn().mockReturnValue(mockCollection),
}
vi.mock('#providers/mongodb_provider', () => ({
getMongoDb: () => mockDb,
}))
import DeviceModel from '../../../app/models/device.js'
describe('DeviceModel', () => {
beforeEach(() => {
vi.clearAllMocks()
mockCollection.toArray.mockResolvedValue([])
})
it('findByIdentifier calls findOne with identifier', async () => {
mockCollection.findOne.mockResolvedValue({ identifier: 'abc', deviceId: {} })
const result = await DeviceModel.findByIdentifier('abc')
expect(mockCollection.findOne).toHaveBeenCalledWith({ identifier: 'abc' })
expect(result).toEqual({ identifier: 'abc', deviceId: {} })
})
it('findByIdentifier returns null when not found', async () => {
mockCollection.findOne.mockResolvedValue(null)
const result = await DeviceModel.findByIdentifier('xyz')
expect(result).toBeNull()
})
it('findByDeviceId queries by all 4 fields', async () => {
const { DeviceId } = await import('../../../app/domain/device/device_id.js')
const deviceId = new DeviceId('Mfr', 'OUI', 'PC', 'SN')
mockCollection.findOne.mockResolvedValue(null)
await DeviceModel.findByDeviceId(deviceId)
expect(mockCollection.findOne).toHaveBeenCalledWith({
'deviceId.manufacturer': 'Mfr',
'deviceId.oui': 'OUI',
'deviceId.productClass': 'PC',
'deviceId.serialNumber': 'SN',
})
})
it('paginateDevices returns data and total', async () => {
mockCollection.countDocuments.mockResolvedValue(25)
mockCollection.toArray.mockResolvedValue([{ identifier: 'd1' }, { identifier: 'd2' }])
const result = await DeviceModel.paginateDevices(0, 10)
expect(result.total).toBe(25)
expect(result.data).toHaveLength(2)
expect(mockCollection.skip).toHaveBeenCalledWith(0)
expect(mockCollection.limit).toHaveBeenCalledWith(10)
})
it('createOrUpdate upserts by deviceId', async () => {
const device = { deviceId: { manufacturer: 'M', oui: 'O', productClass: 'P', serialNumber: 'S' }, properties: [] }
mockCollection.findOneAndUpdate.mockResolvedValue(device)
const result = await DeviceModel.createOrUpdate(device as any)
expect(mockCollection.findOneAndUpdate).toHaveBeenCalled()
expect(result).toEqual(device)
})
it('createOrUpdate upserts by identifier', async () => {
const device = { identifier: 'hash123', properties: [] }
mockCollection.findOneAndUpdate.mockResolvedValue(device)
await DeviceModel.createOrUpdate(device as any)
expect(mockCollection.findOneAndUpdate).toHaveBeenCalledWith(
{ identifier: 'hash123' },
expect.any(Object),
expect.any(Object)
)
})
it('createOrUpdate throws if no identifier or deviceId', async () => {
await expect(DeviceModel.createOrUpdate({} as any)).rejects.toThrow('Either identifier or deviceId must be provided')
})
it('updateCompliance calls updateOne', async () => {
mockCollection.updateOne.mockResolvedValue({ modifiedCount: 1 })
await DeviceModel.updateCompliance('id1', { status: 'compliant' } as any)
expect(mockCollection.updateOne).toHaveBeenCalled()
})
it('updateProvisioningCode calls updateOne', async () => {
mockCollection.updateOne.mockResolvedValue({ modifiedCount: 1 })
await DeviceModel.updateProvisioningCode('id1', 'code-123')
expect(mockCollection.updateOne).toHaveBeenCalled()
})
it('findByComplianceStatus queries by status', async () => {
mockCollection.toArray.mockResolvedValue([{ identifier: 'x' }])
const result = await DeviceModel.findByComplianceStatus('compliant')
expect(result).toHaveLength(1)
})
it('findByConfigurationIdentifier queries by configId', async () => {
mockCollection.toArray.mockResolvedValue([])
const result = await DeviceModel.findByConfigurationIdentifier('cfg-1')
expect(result).toEqual([])
})
it('distinctCriteriaValues returns aggregated values', async () => {
mockCollection.distinct.mockResolvedValue(['Sagemcom'])
mockCollection.toArray.mockResolvedValue([{ _id: 'v1' }])
const result = await DeviceModel.distinctCriteriaValues()
expect(result.manufacturer).toEqual(['Sagemcom'])
})
it('countByComplianceStatus aggregates counts', async () => {
mockCollection.toArray.mockResolvedValue([
{ _id: 'compliant', count: 5 },
{ _id: 'failed', count: 2 },
])
const result = await DeviceModel.countByComplianceStatus('cfg-1')
expect(result.compliant).toBe(5)
expect(result.failed).toBe(2)
expect(result.in_progress).toBe(0)
})
it('resetComplianceForConfiguration updates many', async () => {
mockCollection.updateMany.mockResolvedValue({ modifiedCount: 3 })
await DeviceModel.resetComplianceForConfiguration('cfg-1')
expect(mockCollection.updateMany).toHaveBeenCalled()
})
})