UNPKG

combined-memory-mcp

Version:

MCP server for Combined Memory API - AI-powered chat with unlimited context, memory management, voice agents, and 500+ tool integrations

185 lines (184 loc) 9.87 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const openapiProcessor_1 = require("../../src/openapiProcessor"); const path_1 = __importDefault(require("path")); const promises_1 = __importDefault(require("fs/promises")); const test_config_1 = require("../fixtures/test-config"); const globals_1 = require("@jest/globals"); // Define constants const configPath = '../../src/config'; describe('OpenAPI Processor Integration Tests', () => { const originalEnv = Object.assign({}, process.env); const originalArgv = [...process.argv]; const fixturesPath = path_1.default.resolve(process.cwd(), 'test/fixtures'); beforeEach(() => { // Reset environment variables before each test process.env = Object.assign({}, originalEnv); process.argv = [...originalArgv]; // Set up test OpenAPI file path process.env.OPENAPI_SPEC_PATH = path_1.default.resolve(process.cwd(), test_config_1.testConfig.openApiFile); // Clear jest module mocks between tests globals_1.jest.resetModules(); globals_1.jest.dontMock('../../src/config'); }); afterAll(() => { // Restore original environment after all tests process.env = originalEnv; process.argv = originalArgv; }); it('should load and process OpenAPI specification from file', () => __awaiter(void 0, void 0, void 0, function* () { // Explicitly mock config with no overlays for this test globals_1.jest.resetModules(); globals_1.jest.doMock('../../src/config', () => ({ config: { specPath: path_1.default.resolve(process.cwd(), test_config_1.testConfig.openApiFile), overlayPaths: [], mcpPort: 8080, targetApiBaseUrl: undefined, apiKey: undefined, securitySchemeName: undefined, securityCredentials: {}, customHeaders: {}, disableXMcp: false, filter: { whitelist: null, blacklist: [], }, } })); // Import the module with our mocks applied const { getProcessedOpenApi: getProcessedOpenApiClean } = require('../../src/openapiProcessor'); const openApiSpec = yield getProcessedOpenApiClean(); expect(openApiSpec).toBeDefined(); expect(openApiSpec.openapi).toBe('3.0.0'); expect(openApiSpec.info.title).toBe('Petstore API'); expect(openApiSpec.paths).toBeDefined(); expect(openApiSpec.paths["/pets"]).toBeDefined(); expect(openApiSpec.paths["/pets/{petId}"]).toBeDefined(); expect(openApiSpec.components.schemas.Pet).toBeDefined(); })); it('should apply overlay configuration when provided', () => __awaiter(void 0, void 0, void 0, function* () { const overlayFilePath = path_1.default.resolve(process.cwd(), 'test/fixtures/petstore-overlay.json'); // Clear any cached modules globals_1.jest.resetModules(); // Read the overlay file contents directly to confirm it has what we expect const overlayContent = yield promises_1.default.readFile(overlayFilePath, 'utf8'); const overlay = JSON.parse(overlayContent); // Verify this is a proper OpenAPI Overlay Spec 1.0.0 document expect(overlay.overlay).toBe('1.0.0'); expect(overlay.info.title).toBe('Modified Petstore API Overlay'); expect(overlay.actions).toBeInstanceOf(Array); // The info.title in the overlay document itself is 'Modified Petstore API Overlay' // but the action will update the OpenAPI document title to 'Modified Petstore API' const titleUpdateAction = overlay.actions.find(action => { var _a; return action.target === '$.info' && ((_a = action.update) === null || _a === void 0 ? void 0 : _a.title) === 'Modified Petstore API'; }); expect(titleUpdateAction).toBeDefined(); // Mock the config module to include our overlay globals_1.jest.doMock('../../src/config', () => ({ config: { specPath: path_1.default.resolve(process.cwd(), test_config_1.testConfig.openApiFile), overlayPaths: [overlayFilePath], mcpPort: 8080, targetApiBaseUrl: undefined, apiKey: undefined, securitySchemeName: undefined, securityCredentials: {}, filter: { whitelist: null, blacklist: [], }, } })); // Import the processor module with our mock config const { getProcessedOpenApi: getProcessedOpenApiWithOverlay } = require('../../src/openapiProcessor'); const openApiSpec = yield getProcessedOpenApiWithOverlay(); // The overlay should be applied to the spec expect(openApiSpec).toBeDefined(); // Verify that the overlay changes were applied based on the actual actions // Instead of hardcoded values, we'll check against the actions in the overlay const infoAction = overlay.actions.find(a => a.target === '$.info'); expect(infoAction).toBeDefined(); expect(openApiSpec.info.title).toBe(infoAction.update.title); expect(openApiSpec.info.version).toBe(infoAction.update.version); // Validate path-level overlay changes const pathAction = overlay.actions.find(a => a.target === "$.paths['/pets'].get"); expect(pathAction).toBeDefined(); expect(openApiSpec.paths["/pets"].get.summary).toBe(pathAction.update.summary); expect(openApiSpec.paths["/pets"].get.description).toBe(pathAction.update.description); // Validate parameter overlay changes const petIdParam = openApiSpec.paths["/pets/{petId}"].get.parameters.find((p) => p.name === 'petId' && p.in === 'path'); const paramAction = overlay.actions.find(a => a.target.includes('petId')); expect(petIdParam).toBeDefined(); expect(paramAction).toBeDefined(); expect(petIdParam.description).toBe(paramAction.update.description); expect(petIdParam.schema.type).toBe(paramAction.update.schema.type); expect(petIdParam.schema.format).toBe(paramAction.update.schema.format); })); it('should throw error for invalid OpenAPI file path', () => __awaiter(void 0, void 0, void 0, function* () { // Mock the config with an invalid file path globals_1.jest.resetModules(); globals_1.jest.doMock('../../src/config', () => ({ config: { specPath: '/path/to/nonexistent/openapi.json', overlayPaths: [], mcpPort: 8080, targetApiBaseUrl: undefined, apiKey: undefined, securitySchemeName: undefined, securityCredentials: {}, filter: { whitelist: null, blacklist: [], }, } })); // Import the processor module with our mocks applied const { getProcessedOpenApi: getProcessedOpenApiWithInvalidPath } = require('../../src/openapiProcessor'); // Expect the function to throw an error yield expect(getProcessedOpenApiWithInvalidPath()).rejects.toThrow(); // Reset mocks globals_1.jest.resetModules(); globals_1.jest.dontMock('../../src/config'); })); it('should create a valid OpenAPI spec object', () => __awaiter(void 0, void 0, void 0, function* () { // Test that the processed OpenAPI spec has all required properties const openApiSpec = yield (0, openapiProcessor_1.getProcessedOpenApi)(); // Check basic structure requirements expect(openApiSpec).toHaveProperty('openapi'); expect(openApiSpec).toHaveProperty('info'); expect(openApiSpec).toHaveProperty('paths'); // Validate info section expect(openApiSpec.info).toHaveProperty('title'); expect(openApiSpec.info).toHaveProperty('version'); // Validate paths have operations // Find at least one valid operation with standard HTTP methods let hasValidOperation = false; Object.values(openApiSpec.paths).forEach((pathItem) => { ['get', 'post', 'put', 'delete', 'patch'].forEach(method => { if (pathItem[method]) hasValidOperation = true; }); }); expect(hasValidOperation).toBe(true); // Check that all operations have required fields Object.entries(openApiSpec.paths).forEach(([path, pathItem]) => { Object.entries(pathItem).forEach(([method, operation]) => { if (['get', 'post', 'put', 'delete', 'patch'].includes(method)) { expect(operation).toHaveProperty('operationId'); expect(operation).toHaveProperty('responses'); } }); }); })); });