Files
pulse/server/tests/dnsResolver.test.js
T
courtmanr@gmail.com bd9a976100 feat: enhance system reliability with DNS resilience and advanced alerting
- Implement resilient DNS resolution for API calls with fallback mechanisms
- Add compound threshold alert rules with multi-metric evaluation
- Enable immediate alert evaluation when rules are enabled
- Add alert rules file watching for dynamic configuration updates
- Improve alert state management with proper resolution handling
- Include comprehensive testing and documentation for DNS features

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-07 15:46:04 +01:00

123 lines
4.4 KiB
JavaScript

const dnsResolver = require('../dnsResolver');
const dns = require('dns').promises;
// Mock the dns module
jest.mock('dns', () => ({
promises: {
resolve4: jest.fn(),
resolve6: jest.fn()
}
}));
// Mock the util.promisify
jest.mock('util', () => ({
promisify: () => jest.fn()
}));
describe('DnsResolver', () => {
beforeEach(() => {
// Clear all mocks and caches
jest.clearAllMocks();
dnsResolver.clearCache();
});
describe('resolveHostname', () => {
it('should resolve hostname to IP addresses', async () => {
const mockIPs = ['192.168.1.10', '192.168.1.11', '192.168.1.12'];
dns.resolve4.mockResolvedValue(mockIPs);
dns.resolve6.mockResolvedValue([]);
const result = await dnsResolver.resolveHostname('proxmox.lan');
expect(result).toEqual(mockIPs);
expect(dns.resolve4).toHaveBeenCalledWith('proxmox.lan');
});
it('should cache DNS results', async () => {
const mockIPs = ['192.168.1.10'];
dns.resolve4.mockResolvedValue(mockIPs);
dns.resolve6.mockResolvedValue([]);
// First call
await dnsResolver.resolveHostname('test.lan');
expect(dns.resolve4).toHaveBeenCalledTimes(1);
// Second call should use cache
await dnsResolver.resolveHostname('test.lan');
expect(dns.resolve4).toHaveBeenCalledTimes(1); // Still only called once
});
it('should filter out failed IPs', async () => {
const mockIPs = ['192.168.1.10', '192.168.1.11', '192.168.1.12'];
dns.resolve4.mockResolvedValue(mockIPs);
dns.resolve6.mockResolvedValue([]);
// Mark one IP as failed
dnsResolver.markHostFailed('192.168.1.11');
const result = await dnsResolver.resolveHostname('proxmox.lan');
expect(result).toEqual(['192.168.1.10', '192.168.1.12']);
expect(result).not.toContain('192.168.1.11');
});
it('should handle DNS resolution failures gracefully', async () => {
dns.resolve4.mockRejectedValue(new Error('DNS resolution failed'));
dns.resolve6.mockRejectedValue(new Error('DNS resolution failed'));
// Mock lookup to also fail
const lookup = require('util').promisify();
lookup.mockRejectedValue(new Error('Lookup failed'));
await expect(dnsResolver.resolveHostname('invalid.lan'))
.rejects.toThrow('No IP addresses found');
});
});
describe('markHostFailed and isHostFailed', () => {
it('should mark host as failed temporarily', async () => {
const testIP = '192.168.1.10';
expect(dnsResolver.isHostFailed(testIP)).toBe(false);
dnsResolver.markHostFailed(testIP);
expect(dnsResolver.isHostFailed(testIP)).toBe(true);
});
});
describe('extractHostname', () => {
it('should extract hostname from various URL formats', () => {
const testCases = [
{ input: 'https://proxmox.lan:8006', expected: 'proxmox.lan' },
{ input: 'http://test.local:3000/path', expected: 'test.local' },
{ input: 'server.domain:8080', expected: 'server.domain' },
{ input: 'simple-hostname', expected: 'simple-hostname' }
];
testCases.forEach(({ input, expected }) => {
expect(dnsResolver.extractHostname(input)).toBe(expected);
});
});
});
describe('canResolve', () => {
it('should return true for resolvable hostnames', async () => {
dns.resolve4.mockResolvedValue(['192.168.1.10']);
dns.resolve6.mockResolvedValue([]);
const result = await dnsResolver.canResolve('valid.lan');
expect(result).toBe(true);
});
it('should return false for unresolvable hostnames', async () => {
dns.resolve4.mockRejectedValue(new Error('Not found'));
dns.resolve6.mockRejectedValue(new Error('Not found'));
const lookup = require('util').promisify();
lookup.mockRejectedValue(new Error('Not found'));
const result = await dnsResolver.canResolve('invalid.lan');
expect(result).toBe(false);
});
});
});