Skip to main content
Glama

Simple Files Vector Store Server

watchConfig.test.ts6.17 kB
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import * as fs from 'fs/promises'; import * as path from 'path'; import { SimpleFilesVectorStore } from '../index.js'; import { FileWatcher } from '../fileWatcher.js'; import { VectorStore } from '../vectorStore.js'; import { FileProcessor } from '../fileProcessor.js'; // Mock the FileProcessor class vi.mock('../fileProcessor.js', () => ({ FileProcessor: vi.fn().mockImplementation(() => ({ processFile: vi.fn().mockResolvedValue([]), })), })); // Mock the FileWatcher class vi.mock('../fileWatcher.js', () => ({ FileWatcher: vi.fn().mockImplementation(() => ({ initializeIgnorePatterns: vi.fn().mockResolvedValue(undefined), setWatchedDirectories: vi.fn(), setupDirectoryWatch: vi.fn(), processDirectory: vi.fn().mockResolvedValue(undefined), close: vi.fn().mockResolvedValue(undefined), })), })); // Mock the VectorStore class vi.mock('../vectorStore.js', () => ({ VectorStore: vi.fn().mockImplementation(() => ({ setWatchedDirectories: vi.fn(), incrementProcessingCount: vi.fn(), decrementProcessingCount: vi.fn(), updateDocuments: vi.fn().mockResolvedValue(undefined), removeDocumentsBySource: vi.fn().mockResolvedValue(undefined), similaritySearch: vi.fn().mockResolvedValue([]), getStats: vi.fn().mockReturnValue({ totalDocuments: 0, documentsByType: {}, watchedDirectories: [], filesBeingProcessed: 0 }), })), })); // Mock the fs module vi.mock('fs/promises', () => ({ readFile: vi.fn(), access: vi.fn().mockResolvedValue(undefined), readdir: vi.fn().mockResolvedValue([]), stat: vi.fn().mockResolvedValue({ isFile: () => true, isDirectory: () => false }), })); // Mock the fs watch function vi.mock('fs', () => ({ watch: vi.fn().mockReturnValue({ close: vi.fn(), }), })); // Mock the server connection vi.mock('@modelcontextprotocol/sdk/server/index.js', () => ({ Server: vi.fn().mockImplementation(() => ({ connect: vi.fn().mockResolvedValue(undefined), close: vi.fn().mockResolvedValue(undefined), setRequestHandler: vi.fn(), onerror: null, })), })); vi.mock('@modelcontextprotocol/sdk/server/stdio.js', () => ({ StdioServerTransport: vi.fn().mockImplementation(() => ({ onmessage: null, send: vi.fn(), close: vi.fn().mockResolvedValue(undefined), start: vi.fn().mockResolvedValue(undefined), })), })); describe('Watch Config File', () => { const originalEnv = process.env; beforeEach(() => { // Reset process.env process.env = { ...originalEnv }; // Clear all mocks vi.clearAllMocks(); // Mock console.error to avoid cluttering test output vi.spyOn(console, 'error').mockImplementation(() => {}); }); afterEach(() => { // Restore process.env process.env = originalEnv; }); it('should load directories from WATCH_CONFIG_FILE', async () => { // Setup const mockConfigPath = '/path/to/config.json'; const mockWatchList = ['dir1', 'dir2', 'dir3']; // Mock the readFile function to return our test config (fs.readFile as any).mockResolvedValue(JSON.stringify({ watchList: mockWatchList })); // Set environment variables process.env.WATCH_CONFIG_FILE = mockConfigPath; // Create an instance of SimpleFilesVectorStore const server = new SimpleFilesVectorStore(); // Run the server await server.run(); // Verify that readFile was called with the correct path expect(fs.readFile).toHaveBeenCalledWith(mockConfigPath, 'utf-8'); // Verify that the directories were loaded correctly // We can't directly access private properties, but we can check if the console.error was called // with the expected message expect(console.error).toHaveBeenCalledWith( `Loaded watch list from config file: ${mockWatchList.join(', ')}` ); }); it('should throw an error if WATCH_CONFIG_FILE is invalid', async () => { // Setup const mockConfigPath = '/path/to/invalid-config.json'; // Mock the readFile function to return invalid JSON (fs.readFile as any).mockResolvedValue('{ invalid json }'); // Set environment variables process.env.WATCH_CONFIG_FILE = mockConfigPath; // Create an instance of SimpleFilesVectorStore const server = new SimpleFilesVectorStore(); // Run the server should throw an error await expect(server.run()).rejects.toThrow(); }); it('should throw an error if watchList is missing or empty', async () => { // Setup const mockConfigPath = '/path/to/empty-config.json'; // Mock the readFile function to return a config without watchList (fs.readFile as any).mockResolvedValue(JSON.stringify({})); // Set environment variables process.env.WATCH_CONFIG_FILE = mockConfigPath; // Create an instance of SimpleFilesVectorStore const server = new SimpleFilesVectorStore(); // Run the server should throw an error await expect(server.run()).rejects.toThrow(); }); it('should prefer WATCH_CONFIG_FILE over WATCH_DIRECTORIES when both are set', async () => { // Setup const mockConfigPath = '/path/to/config.json'; const mockWatchList = ['config-dir1', 'config-dir2']; const envDirs = 'env-dir1,env-dir2'; // Mock the readFile function to return our test config (fs.readFile as any).mockResolvedValue(JSON.stringify({ watchList: mockWatchList })); // Set environment variables process.env.WATCH_CONFIG_FILE = mockConfigPath; process.env.WATCH_DIRECTORIES = envDirs; // Create an instance of SimpleFilesVectorStore const server = new SimpleFilesVectorStore(); // Run the server await server.run(); // Verify that readFile was called with the correct path expect(fs.readFile).toHaveBeenCalledWith(mockConfigPath, 'utf-8'); // Verify that the directories from the config file were used, not from WATCH_DIRECTORIES expect(console.error).toHaveBeenCalledWith( `Loaded watch list from config file: ${mockWatchList.join(', ')}` ); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/lishenxydlgzs/simple-files-vectorstore'

If you have feedback or need assistance with the MCP directory API, please join our Discord server