import './setup.mjs'; import test from 'node:test'; import assert from 'node:assert/strict'; import { load } from './setup.mjs'; const { buildVmListPath, buildHostPayloadFromVm, buildStandaloneHostCandidate, filterSummaryVms, getVCenterVmPowerState, normalizeBaseUrl, normalizeVCenterVm, previewVCenterHosts, settingsFromVCenterConnection, vmMatchesFilter } = await load('../services/vcenterService.js'); const originalFetch = globalThis.fetch; function soapResponse(body) { return new Response(`${body}`, { status: 200, headers: { 'content-type': 'text/xml' } }); } function installStandaloneEsxiSoapStub() { globalThis.fetch = async (_url, options = {}) => { const body = String(options.body || ''); if (body.includes('ha-folder-rootha-property-collectorViewManagerha-sessionmgr`); } if (body.includes('session-1`); } if (body.includes('session[52b6]-vm-view`); } if (body.includes('vim.VirtualMachine:101nameENG-ENT-APP01guest.hostNameeng-ent-app01.contoso.localguest.ipAddress10.42.8.21guest.guestFullNameMicrosoft Windows Server 2022runtime.powerStatepoweredOn`); } return soapResponse(''); }; return () => { globalThis.fetch = originalFetch; }; } test('normalizeBaseUrl trims trailing slashes', () => { assert.equal(normalizeBaseUrl('https://vcenter.lab.local///'), 'https://vcenter.lab.local'); }); test('standalone VMware host connections use the Web Services profile', async () => { const restoreFetch = installStandaloneEsxiSoapStub(); const connection = { id: 'vc_host', name: 'ESXi 01', target_type: 'host', base_url: 'https://esxi01.lab.local/sdk', username: 'root', password: 'secret', enabled: 1, api_mode: 'api' }; const settings = settingsFromVCenterConnection(connection); assert.equal(settings.targetType, 'host'); assert.equal(settings.apiMode, 'web-services'); assert.equal(settings.baseUrl, 'https://esxi01.lab.local/sdk'); const preview = await previewVCenterHosts({ connection, filter: { field: 'hostname', operator: 'contains', value: 'ENG-ENT' } }); restoreFetch(); assert.equal(preview.count, 1); assert.equal(preview.diagnostics.standaloneHost, true); assert.equal(preview.candidates[0].source, 'standalone-vm'); assert.equal(preview.candidates[0].fqdn, 'eng-ent-app01.contoso.local'); assert.equal(preview.candidates[0].ipAddress, '10.42.8.21'); assert.equal(preview.candidates[0].powerState, 'POWERED_ON'); }); test('standalone VMware VM candidates build managed host payloads', async () => { const restoreFetch = installStandaloneEsxiSoapStub(); const connection = { id: 'vc_host', name: 'ESXi 01', target_type: 'host', base_url: 'https://esxi01.lab.local', username: 'root', password: 'secret', enabled: 1 }; const preview = await previewVCenterHosts({ connection, filter: { field: 'hostname', operator: 'contains', value: 'eng-ent' } }); const payload = buildHostPayloadFromVm(preview.candidates[0], { connectionId: 'vc_host', credentialId: 'cred_1', transport: 'winrm', tags: ['lab'], visibility: 'shared' }); const power = await getVCenterVmPowerState(connection, preview.candidates[0].id); restoreFetch(); assert.equal(payload.name, 'ENG-ENT-APP01'); assert.equal(payload.address, 'eng-ent-app01.contoso.local'); assert.equal(payload.transport, 'winrm'); assert.equal(payload.sourceType, 'vmware'); assert.equal(payload.sourceConnectionId, 'vc_host'); assert.equal(payload.sourceRef, 'vim.VirtualMachine:101'); assert.ok(payload.tags.includes('standalone-esxi')); assert.ok(payload.tags.includes('esxi-vm:vim.VirtualMachine:101')); assert.equal(power.checked, true); assert.equal(power.state, 'POWERED_ON'); }); test('standalone VMware host candidates build managed host payloads', () => { const candidate = buildStandaloneHostCandidate( { id: 'vc_host', name: 'ESXi 01' }, { baseUrl: 'https://esxi01.lab.local', targetType: 'host' } ); const payload = buildHostPayloadFromVm(candidate, { connectionId: 'vc_host', credentialId: 'cred_1', transport: 'ssh', tags: ['lab'], visibility: 'shared' }); assert.equal(payload.name, 'ESXi 01'); assert.equal(payload.address, 'esxi01.lab.local'); assert.equal(payload.transport, 'ssh'); assert.equal(payload.credentialId, 'cred_1'); assert.equal(payload.sourceType, 'vmware'); assert.equal(payload.sourceConnectionId, 'vc_host'); assert.equal(payload.sourceRef, 'standalone-esxi-host'); assert.ok(payload.tags.includes('standalone-esxi')); assert.ok(payload.tags.includes('lab')); }); test('normalizeVCenterVm maps guest identity and networking into a host candidate', () => { const candidate = normalizeVCenterVm( { vm: 'vm-42', name: 'ENG-ENT-APP01', power_state: 'POWERED_ON' }, { host_name: 'eng-ent-app01.contoso.local', ip_address: '10.42.1.20', full_name: { default_message: 'Microsoft Windows Server 2022' } }, [{ ip: { ip_addresses: [{ ip_address: 'fe80::1' }, { ip_address: '10.42.1.21' }] } }] ); assert.equal(candidate.id, 'vm-42'); assert.equal(candidate.name, 'ENG-ENT-APP01'); assert.equal(candidate.fqdn, 'eng-ent-app01.contoso.local'); assert.equal(candidate.address, 'eng-ent-app01.contoso.local'); assert.deepEqual(candidate.ipAddresses, ['10.42.1.20', '10.42.1.21']); assert.equal(candidate.osFamily, 'windows'); assert.equal(candidate.guestFullName, 'Microsoft Windows Server 2022'); }); test('normalizeVCenterVm marks unknown guest operating systems as other', () => { const candidate = normalizeVCenterVm( { vm: 'vm-unknown', name: 'MYSTERY-01', power_state: 'POWERED_ON' }, null, [] ); assert.equal(candidate.osFamily, 'other'); }); test('vmMatchesFilter supports hostname contains and IP equals matching', () => { const candidate = { name: 'ENG-ENT-APP01', fqdn: 'app01.contoso.local', address: 'app01.contoso.local', ipAddress: '10.42.1.20', ipAddresses: ['10.42.1.20'] }; assert.equal(vmMatchesFilter(candidate, { field: 'hostname', operator: 'contains', value: 'eng-ent' }), true); assert.equal(vmMatchesFilter(candidate, { field: 'hostname', operator: 'contains', value: 'contoso' }), true); assert.equal(vmMatchesFilter(candidate, { field: 'ip', operator: 'equals', value: '10.42.1.20' }), true); assert.equal(vmMatchesFilter(candidate, { field: 'fqdn', operator: 'startsWith', value: 'db' }), false); }); test('vmMatchesFilter matches guest-only host names after enrichment', () => { const candidate = normalizeVCenterVm( { vm: 'vm-200', name: 'KSUS01PAPP01', power_state: 'POWERED_ON' }, { host_name: 'MCS-WIN-APP01.ent.mitekindustries.com', ip_address: '10.42.5.44', family: 'WINDOWS' }, [] ); assert.equal(vmMatchesFilter(candidate, { field: 'hostname', operator: 'contains', value: 'MCS' }), true); assert.equal(vmMatchesFilter(candidate, { field: 'name', operator: 'contains', value: 'MCS' }), false); }); test('filterSummaryVms scans the full VM summary list for VM-name filters', () => { const vms = [ ...Array.from({ length: 900 }, (_, index) => ({ vm: `vm-${index}`, name: `ZZZ-${index}` })), { vm: 'vm-901', name: 'MCS-WIN-APP01' } ]; const result = filterSummaryVms(vms, { field: 'name', operator: 'contains', value: 'MCS' }); assert.equal(result.summaryFilterApplied, true); assert.equal(result.summaryMatched, 1); assert.equal(result.vms.length, 1); assert.equal(result.vms[0].name, 'MCS-WIN-APP01'); }); test('filterSummaryVms prefilters hostname searches by VM name and falls back when needed', () => { const vms = [{ vm: 'vm-1', name: 'MCS-WIN-APP01' }, { vm: 'vm-2', name: 'SQL-01' }]; const matched = filterSummaryVms(vms, { field: 'hostname', operator: 'contains', value: 'MCS' }); const fallback = filterSummaryVms(vms, { field: 'hostname', operator: 'contains', value: 'guest-only-name' }); assert.equal(matched.summaryMatched, 1); assert.equal(matched.summaryFilterFallback, false); assert.deepEqual(matched.vms.map((vm) => vm.vm), ['vm-1', 'vm-2']); assert.equal(fallback.summaryMatched, 0); assert.equal(fallback.summaryFilterFallback, true); assert.equal(fallback.vms.length, 2); }); test('buildVmListPath uses documented exact-name filters for api and rest profiles', () => { const filter = { field: 'name', operator: 'equals', value: 'MCS-WIN-APP01' }; assert.equal( buildVmListPath({ vmListPath: '/api/vcenter/vm', vmNameParam: 'names' }, filter), '/api/vcenter/vm?names=MCS-WIN-APP01' ); assert.equal( buildVmListPath({ vmListPath: '/rest/vcenter/vm', vmNameParam: 'filter.names' }, filter), '/rest/vcenter/vm?filter.names=MCS-WIN-APP01' ); assert.equal( buildVmListPath({ vmListPath: '/api/vcenter/vm', vmNameParam: 'names' }, { field: 'name', operator: 'contains', value: 'MCS' }), '/api/vcenter/vm' ); }); test('buildHostPayloadFromVm attaches credential, tags, transport, and import notes', () => { const payload = buildHostPayloadFromVm( { id: 'vm-42', name: 'ENG-ENT-APP01', fqdn: 'eng-ent-app01.contoso.local', address: 'eng-ent-app01.contoso.local', osFamily: 'windows', powerState: 'POWERED_ON', guestFullName: 'Microsoft Windows Server 2022', ipAddresses: ['10.42.1.20'] }, { credentialId: 'cred_1', connectionId: 'vc_1', transport: 'winrm', tags: ['engineering'], visibility: 'group', groupId: 'grp_1' } ); assert.equal(payload.credentialId, 'cred_1'); assert.equal(payload.transport, 'winrm'); assert.equal(payload.visibility, 'group'); assert.equal(payload.groupId, 'grp_1'); assert.equal(payload.sourceType, 'vmware'); assert.equal(payload.sourceConnectionId, 'vc_1'); assert.equal(payload.sourceRef, 'vm-42'); assert.ok(payload.tags.includes('vcenter:vm-42')); assert.ok(payload.tags.includes('engineering')); assert.match(payload.notes, /Imported from VMware vCenter VM vm-42/); });