116 lines
3.3 KiB
TypeScript
116 lines
3.3 KiB
TypeScript
/**
|
|
* Mock HTTP server for testing the HTTP client
|
|
* Replaces external dependency on httpbin.org with a local server
|
|
*/
|
|
export class MockServer {
|
|
private server: ReturnType<typeof Bun.serve> | null = null;
|
|
private port: number = 0;
|
|
|
|
/**
|
|
* Start the mock server on a random port
|
|
*/
|
|
async start(): Promise<void> {
|
|
this.server = Bun.serve({
|
|
port: 1, // Use any available port
|
|
fetch: this.handleRequest.bind(this),
|
|
error: this.handleError.bind(this),
|
|
});
|
|
|
|
this.port = this.server.port || 1;
|
|
console.log(`Mock server started on port ${this.port}`);
|
|
}
|
|
|
|
/**
|
|
* Stop the mock server
|
|
*/
|
|
async stop(): Promise<void> {
|
|
if (this.server) {
|
|
this.server.stop(true);
|
|
this.server = null;
|
|
this.port = 0;
|
|
console.log('Mock server stopped');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the base URL of the mock server
|
|
*/
|
|
getBaseUrl(): string {
|
|
if (!this.server) {
|
|
throw new Error('Server not started');
|
|
}
|
|
return `http://localhost:${this.port}`;
|
|
}
|
|
|
|
/**
|
|
* Handle incoming requests
|
|
*/ private async handleRequest(req: Request): Promise<Response> {
|
|
const url = new URL(req.url);
|
|
const path = url.pathname;
|
|
|
|
console.log(`Mock server handling request: ${req.method} ${path}`);
|
|
|
|
// Status endpoints
|
|
if (path.startsWith('/status/')) {
|
|
const status = parseInt(path.replace('/status/', ''), 10);
|
|
console.log(`Returning status: ${status}`);
|
|
return new Response(null, { status });
|
|
} // Headers endpoint
|
|
if (path === '/headers') {
|
|
const headers = Object.fromEntries([...req.headers.entries()]);
|
|
console.log('Headers endpoint called, received headers:', headers);
|
|
return Response.json({ headers });
|
|
} // Basic auth endpoint
|
|
if (path.startsWith('/basic-auth/')) {
|
|
const parts = path.split('/').filter(Boolean);
|
|
const expectedUsername = parts[1];
|
|
const expectedPassword = parts[2];
|
|
console.log(
|
|
`Basic auth endpoint called: expected user=${expectedUsername}, pass=${expectedPassword}`
|
|
);
|
|
|
|
const authHeader = req.headers.get('authorization');
|
|
if (!authHeader || !authHeader.startsWith('Basic ')) {
|
|
console.log('Missing or invalid Authorization header');
|
|
return new Response('Unauthorized', { status: 401 });
|
|
}
|
|
|
|
const base64Credentials = authHeader.split(' ')[1];
|
|
const credentials = atob(base64Credentials);
|
|
const [username, password] = credentials.split(':');
|
|
|
|
if (username === expectedUsername && password === expectedPassword) {
|
|
return Response.json({
|
|
authenticated: true,
|
|
user: username,
|
|
});
|
|
}
|
|
|
|
return new Response('Unauthorized', { status: 401 });
|
|
}
|
|
|
|
// Echo request body
|
|
if (path === '/post' && req.method === 'POST') {
|
|
const data = await req.json();
|
|
return Response.json({
|
|
data,
|
|
headers: Object.fromEntries([...req.headers.entries()]),
|
|
method: req.method,
|
|
});
|
|
}
|
|
|
|
// Default response
|
|
return Response.json({
|
|
url: req.url,
|
|
method: req.method,
|
|
headers: Object.fromEntries([...req.headers.entries()]),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Handle errors
|
|
*/
|
|
private handleError(error: Error): Response {
|
|
return new Response('Server error', { status: 500 });
|
|
}
|
|
}
|