feat: Add comprehensive optimization report for Tarot MCP Server

- Implemented performance optimizations including improved singleton pattern and card lookup efficiency.
- Enhanced error handling with a unified error type system and context-aware error messages.
- Introduced a strong type validation framework for input validation, including sanitization functions.
- Improved code quality through consistent formatting, ES module compatibility, and enhanced documentation.
- Expanded test coverage with detailed tests for reading manager and error handling scenarios.
- Created a simple test runner to validate optimizations and performance metrics.
This commit is contained in:
Morax
2025-08-27 17:50:24 +08:00
parent 3448e55ab1
commit 815a8e9c9d
10 changed files with 1753 additions and 126 deletions

181
test-runner.js Normal file
View File

@@ -0,0 +1,181 @@
#!/usr/bin/env node
import { TarotCardManager } from "./dist/tarot/card-manager.js";
import { TarotServer } from "./dist/tarot-server.js";
/**
* Simple test runner to validate our optimizations
*/
async function runTests() {
console.log("🔮 Starting Tarot MCP Server Tests...\n");
let passed = 0;
let failed = 0;
function test(name, fn) {
try {
fn();
console.log(`${name}`);
passed++;
} catch (error) {
console.log(`${name}: ${error.message}`);
failed++;
}
}
async function asyncTest(name, fn) {
try {
await fn();
console.log(`${name}`);
passed++;
} catch (error) {
console.log(`${name}: ${error.message}`);
failed++;
}
}
// Test CardManager initialization
await asyncTest("CardManager can be created", async () => {
const cardManager = await TarotCardManager.create();
if (!cardManager) throw new Error("CardManager not created");
});
// Test singleton pattern
await asyncTest("CardManager singleton works", async () => {
const manager1 = await TarotCardManager.create();
const manager2 = await TarotCardManager.create();
if (manager1 !== manager2) throw new Error("Singleton pattern broken");
});
// Test card operations
await asyncTest("Can get card info", async () => {
const cardManager = await TarotCardManager.create();
const info = cardManager.getCardInfo("The Fool", "upright");
if (!info.includes("The Fool (Upright)"))
throw new Error("Card info incorrect");
});
await asyncTest("Can list all cards", async () => {
const cardManager = await TarotCardManager.create();
const list = cardManager.listAllCards();
if (!list.includes("Major Arcana")) throw new Error("Card list incorrect");
});
await asyncTest("Can find cards", async () => {
const cardManager = await TarotCardManager.create();
const card = cardManager.findCard("The Fool");
if (!card || card.name !== "The Fool") throw new Error("Card not found");
});
await asyncTest("Can get random cards", async () => {
const cardManager = await TarotCardManager.create();
const cards = cardManager.getRandomCards(3);
if (cards.length !== 3) throw new Error("Wrong number of random cards");
// Check uniqueness
const ids = new Set(cards.map((c) => c.id));
if (ids.size !== 3) throw new Error("Duplicate cards in random selection");
});
// Test TarotServer
await asyncTest("TarotServer can be created", async () => {
const server = await TarotServer.create();
if (!server) throw new Error("TarotServer not created");
});
await asyncTest("TarotServer has tools", async () => {
const server = await TarotServer.create();
const tools = server.getAvailableTools();
if (!Array.isArray(tools) || tools.length === 0) {
throw new Error("No tools available");
}
});
// Test error handling
await asyncTest("Handles invalid card names gracefully", async () => {
const cardManager = await TarotCardManager.create();
const info = cardManager.getCardInfo("Invalid Card Name");
if (!info.includes("not found"))
throw new Error("Error not handled gracefully");
});
test("Throws error for too many cards", () => {
TarotCardManager.create().then((cardManager) => {
const allCards = cardManager.getAllCards();
try {
cardManager.getRandomCards(allCards.length + 1);
throw new Error("Should have thrown error");
} catch (error) {
if (!error.message.includes("Cannot draw")) {
throw new Error("Wrong error message");
}
}
});
});
// Test performance
await asyncTest("Multiple card manager creations are fast", async () => {
const start = Date.now();
for (let i = 0; i < 5; i++) {
await TarotCardManager.create();
}
const duration = Date.now() - start;
if (duration > 1000) throw new Error(`Too slow: ${duration}ms`);
});
await asyncTest("Random card generation is fast", async () => {
const cardManager = await TarotCardManager.create();
const start = Date.now();
for (let i = 0; i < 100; i++) {
cardManager.getRandomCard();
}
const duration = Date.now() - start;
if (duration > 1000) throw new Error(`Too slow: ${duration}ms`);
});
// Test crypto usage
test("Crypto functions work", () => {
const manager = TarotCardManager.create().then((cardManager) => {
// This should not throw
const card = cardManager.getRandomCard();
if (!card) throw new Error("Random card generation failed");
});
});
// Test concurrent access
await asyncTest("Handles concurrent requests", async () => {
const promises = [];
for (let i = 0; i < 10; i++) {
promises.push(
TarotCardManager.create().then((manager) => {
return manager.getRandomCards(3);
}),
);
}
const results = await Promise.all(promises);
if (results.length !== 10) throw new Error("Concurrent requests failed");
});
// Summary
console.log(`\n📊 Test Results:`);
console.log(`✅ Passed: ${passed}`);
console.log(`❌ Failed: ${failed}`);
console.log(
`📈 Success Rate: ${((passed / (passed + failed)) * 100).toFixed(1)}%`,
);
if (failed > 0) {
console.log("\n⚠ Some tests failed. Please review the issues above.");
process.exit(1);
} else {
console.log(
"\n🎉 All tests passed! The optimizations are working correctly.",
);
}
}
// Run the tests
runTests().catch((error) => {
console.error("❌ Test runner failed:", error);
process.exit(1);
});