Filesystem MCP Server
by bsmi021
import { promises as fs } from 'fs';
import path from 'path';
import { FileWatcher } from '../../operations/monitoring.js';
import {
TEST_DIR,
createTestFile,
createTestDir
} from '../setup.js';
describe('Monitoring Operations', () => {
let watcher: FileWatcher;
beforeEach(() => {
watcher = new FileWatcher();
});
afterEach(async () => {
await watcher.closeAll();
});
describe('FileWatcher', () => {
it('should detect file creation', async () => {
const changes: any[] = [];
watcher.on('change', (event) => changes.push(event));
await watcher.watchDirectory(TEST_DIR);
// Create a file
const filePath = path.join(TEST_DIR, 'new-file.txt');
await fs.writeFile(filePath, 'content');
// Wait for event to be processed
await new Promise(resolve => setTimeout(resolve, 100));
expect(changes.length).toBeGreaterThan(0);
expect(changes.some(event =>
event.type === 'change' &&
event.path.endsWith('new-file.txt')
)).toBe(true);
});
it('should detect file modification', async () => {
const filePath = await createTestFile('test.txt', 'initial content');
const changes: any[] = [];
watcher.on('change', (event) => changes.push(event));
await watcher.watchDirectory(TEST_DIR);
// Modify the file
await fs.writeFile(filePath, 'modified content');
// Wait for event to be processed
await new Promise(resolve => setTimeout(resolve, 100));
expect(changes.length).toBeGreaterThan(0);
expect(changes.some(event =>
event.type === 'change' &&
event.path.endsWith('test.txt')
)).toBe(true);
});
it('should detect file deletion', async () => {
const filePath = await createTestFile('test.txt', 'content');
const changes: any[] = [];
watcher.on('change', (event) => changes.push(event));
await watcher.watchDirectory(TEST_DIR);
// Delete the file
await fs.unlink(filePath);
// Wait for event to be processed
await new Promise(resolve => setTimeout(resolve, 100));
expect(changes.length).toBeGreaterThan(0);
expect(changes.some(event =>
event.type === 'unlink' &&
event.path.endsWith('test.txt')
)).toBe(true);
});
it('should watch recursively when specified', async () => {
const subdirPath = await createTestDir('subdir');
const changes: any[] = [];
watcher.on('change', (event) => changes.push(event));
await watcher.watchDirectory(TEST_DIR, true);
// Create a file in subdirectory
const filePath = path.join(subdirPath, 'nested-file.txt');
await fs.writeFile(filePath, 'content');
// Wait for event to be processed
await new Promise(resolve => setTimeout(resolve, 100));
expect(changes.length).toBeGreaterThan(0);
expect(changes.some(event =>
event.type === 'change' &&
event.path.endsWith('nested-file.txt')
)).toBe(true);
});
it('should not watch recursively when not specified', async () => {
const subdirPath = await createTestDir('subdir');
const changes: any[] = [];
watcher.on('change', (event) => changes.push(event));
await watcher.watchDirectory(TEST_DIR, false);
// Create a file in subdirectory
const filePath = path.join(subdirPath, 'nested-file.txt');
await fs.writeFile(filePath, 'content');
// Create a file in root directory
const rootFilePath = path.join(TEST_DIR, 'root-file.txt');
await fs.writeFile(rootFilePath, 'content');
// Wait for events to be processed
await new Promise(resolve => setTimeout(resolve, 100));
// Should only detect the root file
expect(changes.some(event =>
event.type === 'change' &&
event.path.endsWith('root-file.txt')
)).toBe(true);
// Should not detect the nested file
expect(changes.some(event =>
event.path.endsWith('nested-file.txt')
)).toBe(false);
});
it('should stop watching when unwatchDirectory is called', async () => {
const changes: any[] = [];
watcher.on('change', (event) => changes.push(event));
await watcher.watchDirectory(TEST_DIR);
// Unwatch the directory
await watcher.unwatchDirectory(TEST_DIR);
// Create a file
const filePath = path.join(TEST_DIR, 'new-file.txt');
await fs.writeFile(filePath, 'content');
// Wait for potential events
await new Promise(resolve => setTimeout(resolve, 100));
expect(changes.length).toBe(0);
});
it('should handle watching multiple directories', async () => {
const dir1 = await createTestDir('dir1');
const dir2 = await createTestDir('dir2');
const changes: any[] = [];
watcher.on('change', (event) => changes.push(event));
await watcher.watchDirectory(dir1);
await watcher.watchDirectory(dir2);
// Create files in both directories
await fs.writeFile(path.join(dir1, 'file1.txt'), 'content');
await fs.writeFile(path.join(dir2, 'file2.txt'), 'content');
// Wait for events to be processed
await new Promise(resolve => setTimeout(resolve, 100));
expect(changes.length).toBeGreaterThan(1);
expect(changes.some(event => event.path.endsWith('file1.txt'))).toBe(true);
expect(changes.some(event => event.path.endsWith('file2.txt'))).toBe(true);
});
it('should clean up all watchers when closeAll is called', async () => {
const dir1 = await createTestDir('dir1');
const dir2 = await createTestDir('dir2');
const changes: any[] = [];
watcher.on('change', (event) => changes.push(event));
await watcher.watchDirectory(dir1);
await watcher.watchDirectory(dir2);
// Close all watchers
await watcher.closeAll();
// Create files in both directories
await fs.writeFile(path.join(dir1, 'file1.txt'), 'content');
await fs.writeFile(path.join(dir2, 'file2.txt'), 'content');
// Wait for potential events
await new Promise(resolve => setTimeout(resolve, 100));
expect(changes.length).toBe(0);
});
});
});