This commit is contained in:
nasir@endelospay.com
2025-07-11 20:22:12 +05:00
commit 8c74b0e23f
120 changed files with 206874 additions and 0 deletions

377
test/test-runner.js Normal file
View File

@@ -0,0 +1,377 @@
#!/usr/bin/env node
/**
* @fileoverview Test runner for Laravel Healthcare MCP Server
* Validates configuration, authentication, and basic functionality
*/
import { ConfigManager } from "../src/config/ConfigManager.js";
import { AuthManager } from "../src/auth/AuthManager.js";
import { ApiClient } from "../src/proxy/ApiClient.js";
import { ToolGenerator } from "../src/tools/ToolGenerator.js";
import { logger } from "../src/utils/logger.js";
import { AUTH_TYPES } from "../src/config/endpoints.js";
/**
* Test runner class
*/
class TestRunner {
constructor() {
this.tests = [];
this.results = {
passed: 0,
failed: 0,
skipped: 0,
total: 0,
};
}
/**
* Add a test
* @param {string} name - Test name
* @param {Function} testFn - Test function
* @param {boolean} skip - Skip this test
*/
addTest(name, testFn, skip = false) {
this.tests.push({ name, testFn, skip });
}
/**
* Run all tests
*/
async runTests() {
console.log("🧪 Laravel Healthcare MCP Server Test Suite\n");
for (const test of this.tests) {
this.results.total++;
if (test.skip) {
console.log(`⏭️ SKIP: ${test.name}`);
this.results.skipped++;
continue;
}
try {
console.log(`🔄 Running: ${test.name}`);
await test.testFn();
console.log(`✅ PASS: ${test.name}\n`);
this.results.passed++;
} catch (error) {
console.log(`❌ FAIL: ${test.name}`);
console.log(` Error: ${error.message}\n`);
this.results.failed++;
}
}
this.printSummary();
}
/**
* Print test summary
*/
printSummary() {
console.log("📊 Test Results Summary");
console.log("========================");
console.log(`Total Tests: ${this.results.total}`);
console.log(`Passed: ${this.results.passed}`);
console.log(`Failed: ${this.results.failed}`);
console.log(`Skipped: ${this.results.skipped}`);
const successRate =
this.results.total > 0
? ((this.results.passed / this.results.total) * 100).toFixed(1)
: 0;
console.log(`Success Rate: ${successRate}%`);
if (this.results.failed > 0) {
console.log(
"\n❌ Some tests failed. Check the output above for details."
);
process.exit(1);
} else {
console.log("\n✅ All tests passed!");
}
}
}
/**
* Configuration tests
*/
async function testConfiguration() {
const config = new ConfigManager();
// Test required configuration
if (!config.get("LARAVEL_API_BASE_URL")) {
throw new Error("LARAVEL_API_BASE_URL is required");
}
// Test URL format
try {
new URL(config.get("LARAVEL_API_BASE_URL"));
} catch (error) {
throw new Error("LARAVEL_API_BASE_URL must be a valid URL");
}
// Test numeric values
const numericConfigs = [
"LARAVEL_API_TIMEOUT",
"LARAVEL_API_RETRY_ATTEMPTS",
"TOKEN_CACHE_DURATION",
];
numericConfigs.forEach((key) => {
const value = config.get(key);
if (value !== undefined && (isNaN(value) || value < 0)) {
throw new Error(`${key} must be a positive number`);
}
});
console.log(" ✓ Configuration validation passed");
}
/**
* Authentication manager tests
*/
async function testAuthManager() {
const config = new ConfigManager();
const authManager = new AuthManager(null, config.getAll(true));
// Test cache functionality
const stats = authManager.getCacheStats();
if (!stats || typeof stats !== "object") {
throw new Error("Auth manager cache stats not available");
}
// Test credential loading
const credentials = authManager.credentials;
if (!credentials || typeof credentials !== "object") {
throw new Error("Auth manager credentials not loaded");
}
// Check if at least one auth type is configured
const configuredAuthTypes = Object.values(AUTH_TYPES).filter((authType) => {
if (authType === AUTH_TYPES.PUBLIC) return false;
const creds = credentials[authType];
return creds && creds.username && creds.password;
});
if (configuredAuthTypes.length === 0) {
throw new Error("At least one authentication type must be configured");
}
console.log(
` ✓ Auth manager initialized with ${configuredAuthTypes.length} auth types`
);
}
/**
* API client tests
*/
async function testApiClient() {
const config = new ConfigManager();
const authManager = new AuthManager(null, config.getAll(true));
const apiClient = new ApiClient(config.getAll(), authManager);
// Test health status
const health = apiClient.getHealthStatus();
if (!health || !health.baseURL) {
throw new Error("API client health status not available");
}
// Test configuration
if (health.baseURL !== config.get("LARAVEL_API_BASE_URL")) {
throw new Error("API client base URL mismatch");
}
console.log(" ✓ API client initialized successfully");
}
/**
* Tool generator tests
*/
async function testToolGenerator() {
const config = new ConfigManager();
const authManager = new AuthManager(null, config.getAll(true));
const apiClient = new ApiClient(config.getAll(), authManager);
const toolGenerator = new ToolGenerator(apiClient);
// Generate tools
const tools = toolGenerator.generateAllTools();
if (!Array.isArray(tools) || tools.length === 0) {
throw new Error("Tool generator did not generate any tools");
}
// Test tool structure
const firstTool = tools[0];
const requiredFields = ["name", "description", "inputSchema"];
requiredFields.forEach((field) => {
if (!firstTool[field]) {
throw new Error(`Tool missing required field: ${field}`);
}
});
// Test tool retrieval
const toolByName = toolGenerator.getTool(firstTool.name);
if (!toolByName) {
throw new Error("Tool retrieval by name failed");
}
console.log(` ✓ Tool generator created ${tools.length} tools`);
}
/**
* Endpoint registry tests
*/
async function testEndpointRegistry() {
const { PUBLIC_ENDPOINTS, AUTH_TYPES, ENDPOINT_CATEGORIES } = await import(
"../src/config/endpoints.js"
);
// Test public endpoints
if (!Array.isArray(PUBLIC_ENDPOINTS) || PUBLIC_ENDPOINTS.length === 0) {
throw new Error("No public endpoints defined");
}
// Test endpoint structure
const firstEndpoint = PUBLIC_ENDPOINTS[0];
const requiredFields = [
"path",
"method",
"controller",
"category",
"description",
];
requiredFields.forEach((field) => {
if (!firstEndpoint[field]) {
throw new Error(`Endpoint missing required field: ${field}`);
}
});
// Test auth types
const authTypeValues = Object.values(AUTH_TYPES);
if (authTypeValues.length < 8) {
throw new Error("Not all authentication types defined");
}
// Test categories
const categoryValues = Object.values(ENDPOINT_CATEGORIES);
if (categoryValues.length === 0) {
throw new Error("No endpoint categories defined");
}
console.log(
` ✓ Endpoint registry has ${PUBLIC_ENDPOINTS.length} public endpoints`
);
}
/**
* Environment variable tests
*/
async function testEnvironmentVariables() {
const requiredEnvVars = ["LARAVEL_API_BASE_URL"];
const missingVars = [];
requiredEnvVars.forEach((varName) => {
if (!process.env[varName]) {
missingVars.push(varName);
}
});
if (missingVars.length > 0) {
throw new Error(
`Missing required environment variables: ${missingVars.join(", ")}`
);
}
// Check for at least one auth configuration
const authTypes = [
"ADMIN",
"AGENT",
"PATIENT",
"PRACTITIONER",
"AFFILIATE",
"PARTNER",
"NETWORK",
"DOCTOR",
"PROVIDER",
];
const configuredAuth = authTypes.filter((authType) => {
return (
process.env[`${authType}_USERNAME`] && process.env[`${authType}_PASSWORD`]
);
});
if (configuredAuth.length === 0) {
console.log(" ⚠️ Warning: No authentication credentials configured");
}
console.log(
` ✓ Environment variables validated (${configuredAuth.length} auth types configured)`
);
}
/**
* Network connectivity tests
*/
async function testNetworkConnectivity() {
const config = new ConfigManager();
const baseUrl = config.get("LARAVEL_API_BASE_URL");
try {
// Simple connectivity test using fetch
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
const response = await fetch(baseUrl, {
method: "HEAD",
signal: controller.signal,
});
clearTimeout(timeoutId);
console.log(
` ✓ Network connectivity to ${baseUrl} successful (${response.status})`
);
} catch (error) {
if (error.name === "AbortError") {
throw new Error(`Network timeout connecting to ${baseUrl}`);
}
throw new Error(`Network connectivity failed: ${error.message}`);
}
}
/**
* Main test execution
*/
async function main() {
const runner = new TestRunner();
// Add tests
runner.addTest("Environment Variables", testEnvironmentVariables);
runner.addTest("Configuration Loading", testConfiguration);
runner.addTest("Endpoint Registry", testEndpointRegistry);
runner.addTest("Authentication Manager", testAuthManager);
runner.addTest("API Client", testApiClient);
runner.addTest("Tool Generator", testToolGenerator);
runner.addTest(
"Network Connectivity",
testNetworkConnectivity,
!process.env.LARAVEL_API_BASE_URL
);
// Run tests
await runner.runTests();
}
// Run tests if this file is executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
main().catch((error) => {
console.error("Test runner failed:", error);
process.exit(1);
});
}
export { TestRunner };