changemaker.lite/api/test-pangolin-resources.ts

233 lines
6.0 KiB
JavaScript

#!/usr/bin/env node
/**
* Test Different Pangolin Raw Resource Creation Configurations
*
* Goal: Determine correct payload format for HTTP resources
*
* Tests:
* 1. Current payload (fails with "Unrecognized keys: type, ssl, enabled")
* 2. Payload without `type` field
* 3. Payload with only name, domainId, subdomain, http: true
* 4. Payload with `protocol: "http"` instead of `type: "http"`
* 5. TCP resource to understand base payload format
* 6. Minimal HTTP resource payload
* 7. Check actual resource structure from listResources()
*/
import { pangolinClient, CreateResourcePayload, PangolinResource } from './src/services/pangolin.client';
import { logger } from './src/utils/logger';
const orgId = process.env.PANGOLIN_ORG_ID || '';
const apiUrl = process.env.PANGOLIN_API_URL || '';
const apiKey = process.env.PANGOLIN_API_KEY || '';
if (!orgId || !apiUrl || !apiKey) {
logger.error('Missing required env vars: PANGOLIN_ORG_URL, PANGOLIN_API_KEY, PANGOLIN_ORG_ID');
process.exit(1);
}
logger.info('=== Pangolin Resource Payload Test ===');
logger.info(`OrgId: ${orgId}`);
logger.info(`API URL: ${apiUrl}`);
logger.info('');
// Helper to make raw requests
async function rawRequest(method: string, path: string, body?: unknown): Promise<unknown> {
const url = `${apiUrl}${path}`;
logger.info(`[${method}] ${url}`);
if (body) {
logger.info(`Body: ${JSON.stringify(body, null, 2)}`);
}
try {
const res = await fetch(url, {
method,
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
});
const text = await res.text();
logger.info(`Response Status: ${res.status}`);
if (text) {
try {
const json = JSON.parse(text);
logger.info(`Response: ${JSON.stringify(json, null, 2)}`);
return json;
} catch (e) {
logger.info(`Response (text): ${text}`);
return text;
}
}
return undefined;
} catch (err) {
logger.error(`Request failed: ${err instanceof Error ? err.message : String(err)}`);
return undefined;
}
}
async function testListExistingResources() {
logger.info('\n--- Test 0: List Existing Resources ---');
const resources = await pangolinClient.listResources();
logger.info(`Found ${resources.length} resources`);
if (resources.length > 0) {
logger.info('Sample resource structure:');
logger.info(JSON.stringify(resources[0], null, 2));
}
}
async function testPayload1() {
logger.info('\n--- Test 1: Current Payload (WITH type, ssl, enabled) ---');
logger.info('Expected error: "Unrecognized keys: type, ssl, enabled"');
const payload = {
name: 'Test HTTP 1',
type: 'http',
domainId: 'test-domain-id',
subdomain: 'test1',
http: true,
ssl: true,
enabled: true,
};
await rawRequest('PUT', `/org/${orgId}/site-resource`, payload);
}
async function testPayload2() {
logger.info('\n--- Test 2: Payload WITHOUT type field ---');
logger.info('Maybe endpoint determines type from other fields');
const payload = {
name: 'Test HTTP 2',
domainId: 'test-domain-id',
subdomain: 'test2',
http: true,
};
await rawRequest('PUT', `/org/${orgId}/site-resource`, payload);
}
async function testPayload3() {
logger.info('\n--- Test 3: Minimal Payload (name, domainId, subdomain, http) ---');
const payload = {
name: 'Test HTTP 3',
domainId: 'test-domain-id',
subdomain: 'test3',
http: true,
};
await rawRequest('PUT', `/org/${orgId}/site-resource`, payload);
}
async function testPayload4() {
logger.info('\n--- Test 4: Payload with protocol instead of type ---');
const payload = {
name: 'Test HTTP 4',
domainId: 'test-domain-id',
subdomain: 'test4',
protocol: 'http',
};
await rawRequest('PUT', `/org/${orgId}/site-resource`, payload);
}
async function testPayload5() {
logger.info('\n--- Test 5: TCP Resource on /resource endpoint ---');
logger.info('TCP uses `/org/{orgId}/resource` endpoint (different from /site-resource)');
const payload = {
name: 'Test TCP 1',
type: 'tcp',
proxyPort: 2222,
stickySession: false,
enabled: true,
};
await rawRequest('PUT', `/org/${orgId}/resource`, payload);
}
async function testPayload6() {
logger.info('\n--- Test 6: Only Name + Subdomain (simplest) ---');
const payload = {
name: 'Test HTTP 6',
subdomain: 'test6',
};
await rawRequest('PUT', `/org/${orgId}/site-resource`, payload);
}
async function testPayload7() {
logger.info('\n--- Test 7: Check if siteId is required ---');
// First get a valid siteId
const sites = await pangolinClient.listSites();
if (sites.length === 0) {
logger.warn('No sites found - skipping test');
return;
}
const siteId = sites[0].siteId;
logger.info(`Using siteId: ${siteId}`);
const payload = {
name: 'Test HTTP 7',
subdomain: 'test7',
siteId,
};
await rawRequest('PUT', `/org/${orgId}/site-resource`, payload);
}
async function testPayload8() {
logger.info('\n--- Test 8: Try on different endpoint (/org/{orgId}/resource) with http resource ---');
const payload = {
name: 'Test HTTP 8',
domainId: 'test-domain-id',
subdomain: 'test8',
http: true,
};
await rawRequest('PUT', `/org/${orgId}/resource`, payload);
}
async function main() {
try {
// Check health first
const healthy = await pangolinClient.healthCheck();
if (!healthy) {
logger.error('Pangolin API health check failed');
process.exit(1);
}
logger.info('Pangolin API health check: OK');
// Run tests
await testListExistingResources();
await testPayload1();
await testPayload2();
await testPayload3();
await testPayload4();
await testPayload5();
await testPayload6();
await testPayload7();
await testPayload8();
logger.info('\n=== Test Complete ===');
} catch (err) {
logger.error('Test failed:', err);
process.exit(1);
}
}
main().catch(err => {
logger.error('Uncaught error:', err);
process.exit(1);
});