197 lines
6.0 KiB
TypeScript
197 lines
6.0 KiB
TypeScript
import * as plugins from '../ts/plugins.js';
|
|
import { SmartProxy } from '../ts/index.js';
|
|
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
|
import { logger } from '../ts/core/utils/logger.js';
|
|
|
|
// Store the original logger reference
|
|
let originalLogger: any = logger;
|
|
let mockLogger: any;
|
|
|
|
// Create test routes using high ports to avoid permission issues
|
|
const createRoute = (id: number, domain: string, port: number = 8443) => ({
|
|
name: `test-route-${id}`,
|
|
match: {
|
|
ports: [port],
|
|
domains: [domain]
|
|
},
|
|
action: {
|
|
type: 'forward' as const,
|
|
target: {
|
|
host: 'localhost',
|
|
port: 3000 + id
|
|
},
|
|
tls: {
|
|
mode: 'terminate' as const,
|
|
certificate: 'auto' as const,
|
|
acme: {
|
|
email: 'test@testdomain.test',
|
|
useProduction: false
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
let testProxy: SmartProxy;
|
|
|
|
tap.test('should setup test proxy for logger error handling tests', async () => {
|
|
// Create a proxy for testing
|
|
testProxy = new SmartProxy({
|
|
routes: [createRoute(1, 'test1.error-handling.test', 8443)],
|
|
acme: {
|
|
email: 'test@testdomain.test',
|
|
useProduction: false,
|
|
port: 8080
|
|
}
|
|
});
|
|
|
|
// Mock the certificate manager to avoid actual ACME initialization
|
|
const originalCreateCertManager = (testProxy as any).createCertificateManager;
|
|
(testProxy as any).createCertificateManager = async function(routes: any[], certDir: string, acmeOptions: any, initialState?: any) {
|
|
const mockCertManager = {
|
|
setUpdateRoutesCallback: function(callback: any) {
|
|
this.updateRoutesCallback = callback;
|
|
},
|
|
updateRoutesCallback: null as any,
|
|
setHttpProxy: function() {},
|
|
setGlobalAcmeDefaults: function() {},
|
|
setAcmeStateManager: function() {},
|
|
initialize: async function() {},
|
|
provisionAllCertificates: async function() {},
|
|
stop: async function() {},
|
|
getAcmeOptions: function() {
|
|
return acmeOptions || { email: 'test@testdomain.test', useProduction: false };
|
|
},
|
|
getState: function() {
|
|
return initialState || { challengeRouteActive: false };
|
|
}
|
|
};
|
|
|
|
// Always set up the route update callback for ACME challenges
|
|
mockCertManager.setUpdateRoutesCallback(async (routes) => {
|
|
await this.updateRoutes(routes);
|
|
});
|
|
|
|
return mockCertManager;
|
|
};
|
|
|
|
// Mock initializeCertificateManager as well
|
|
(testProxy as any).initializeCertificateManager = async function() {
|
|
// Create mock cert manager using the method above
|
|
this.certManager = await this.createCertificateManager(
|
|
this.settings.routes,
|
|
'./certs',
|
|
{ email: 'test@testdomain.test', useProduction: false }
|
|
);
|
|
};
|
|
|
|
// Start the proxy with mocked components
|
|
await testProxy.start();
|
|
expect(testProxy).toBeTruthy();
|
|
});
|
|
|
|
tap.test('should handle logger errors in updateRoutes without failing', async () => {
|
|
// Temporarily inject the mock logger that throws errors
|
|
const origConsoleLog = console.log;
|
|
let consoleLogCalled = false;
|
|
|
|
// Spy on console.log to verify it's used as fallback
|
|
console.log = (...args: any[]) => {
|
|
consoleLogCalled = true;
|
|
// Call original implementation but mute the output for tests
|
|
// origConsoleLog(...args);
|
|
};
|
|
|
|
try {
|
|
// Create mock logger that throws
|
|
mockLogger = {
|
|
log: () => {
|
|
throw new Error('Simulated logger error');
|
|
}
|
|
};
|
|
|
|
// Override the logger in the imported module
|
|
// This is a hack but necessary for testing
|
|
(global as any).logger = mockLogger;
|
|
|
|
// Access the internal logger used by SmartProxy
|
|
const smartProxyImport = await import('../ts/proxies/smart-proxy/smart-proxy.js');
|
|
// @ts-ignore
|
|
smartProxyImport.logger = mockLogger;
|
|
|
|
// Update routes - this should not fail even with logger errors
|
|
const newRoutes = [
|
|
createRoute(1, 'test1.error-handling.test', 8443),
|
|
createRoute(2, 'test2.error-handling.test', 8444)
|
|
];
|
|
|
|
await testProxy.updateRoutes(newRoutes);
|
|
|
|
// Verify that the update was successful
|
|
expect((testProxy as any).settings.routes.length).toEqual(2);
|
|
expect(consoleLogCalled).toEqual(true);
|
|
} finally {
|
|
// Always restore console.log and logger
|
|
console.log = origConsoleLog;
|
|
(global as any).logger = originalLogger;
|
|
}
|
|
});
|
|
|
|
tap.test('should handle logger errors in certificate manager callbacks', async () => {
|
|
// Temporarily inject the mock logger that throws errors
|
|
const origConsoleLog = console.log;
|
|
let consoleLogCalled = false;
|
|
|
|
// Spy on console.log to verify it's used as fallback
|
|
console.log = (...args: any[]) => {
|
|
consoleLogCalled = true;
|
|
// Call original implementation but mute the output for tests
|
|
// origConsoleLog(...args);
|
|
};
|
|
|
|
try {
|
|
// Create mock logger that throws
|
|
mockLogger = {
|
|
log: () => {
|
|
throw new Error('Simulated logger error');
|
|
}
|
|
};
|
|
|
|
// Override the logger in the imported module
|
|
// This is a hack but necessary for testing
|
|
(global as any).logger = mockLogger;
|
|
|
|
// Access the cert manager and trigger the updateRoutesCallback
|
|
const certManager = (testProxy as any).certManager;
|
|
expect(certManager).toBeTruthy();
|
|
expect(certManager.updateRoutesCallback).toBeTruthy();
|
|
|
|
// Call the certificate manager's updateRoutesCallback directly
|
|
const challengeRoute = {
|
|
name: 'acme-challenge',
|
|
match: {
|
|
ports: [8080],
|
|
path: '/.well-known/acme-challenge/*'
|
|
},
|
|
action: {
|
|
type: 'static' as const,
|
|
content: 'mock-challenge-content'
|
|
}
|
|
};
|
|
|
|
// This should not throw, despite logger errors
|
|
await certManager.updateRoutesCallback([...testProxy.settings.routes, challengeRoute]);
|
|
|
|
// Verify console.log was used as fallback
|
|
expect(consoleLogCalled).toEqual(true);
|
|
} finally {
|
|
// Always restore console.log and logger
|
|
console.log = origConsoleLog;
|
|
(global as any).logger = originalLogger;
|
|
}
|
|
});
|
|
|
|
tap.test('should clean up properly', async () => {
|
|
await testProxy.stop();
|
|
});
|
|
|
|
tap.start(); |