locker-mcp
Version:
MCP server for file locking and access control for AI code tools
231 lines • 10.5 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const metadata_1 = require("../metadata");
describe('MetadataManager', () => {
let tempDir;
let metadataManager;
beforeEach(() => {
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'locker-test-'));
metadataManager = new metadata_1.MetadataManager(tempDir);
});
afterEach(() => {
if (fs.existsSync(tempDir)) {
fs.rmSync(tempDir, { recursive: true, force: true });
}
});
describe('getEntry', () => {
it('should return null for non-existent file', () => {
const result = metadataManager.getEntry('non-existent.ts');
expect(result).toBeNull();
});
it('should return entry for existing file', () => {
const filePath = 'test.ts';
const id = 'test-id';
const context = 'test context';
const state = 'locked-context';
metadataManager.createEntry(filePath, id, context, state);
const result = metadataManager.getEntry(filePath);
expect(result).not.toBeNull();
expect(result.filePath).toBe(filePath);
expect(result.id).toBe(id);
expect(result.context).toBe(context);
expect(result.state).toBe(state);
expect(result.history).toHaveLength(1);
expect(result.history[0].state).toBe(state);
});
});
describe('createEntry', () => {
it('should create new entry successfully', () => {
const filePath = 'test.ts';
const id = 'test-id';
const context = 'test context';
const state = 'locked-context';
const entry = metadataManager.createEntry(filePath, id, context, state);
expect(entry.filePath).toBe(filePath);
expect(entry.id).toBe(id);
expect(entry.context).toBe(context);
expect(entry.state).toBe(state);
expect(entry.history).toHaveLength(1);
expect(entry.history[0].state).toBe(state);
expect(entry.history[0].timestamp).toBeDefined();
});
it('should throw error for duplicate entry', () => {
const filePath = 'test.ts';
const id = 'test-id';
const context = 'test context';
const state = 'locked-context';
metadataManager.createEntry(filePath, id, context, state);
expect(() => {
metadataManager.createEntry(filePath, id, context, state);
}).toThrow('Entry already exists for file: test.ts');
});
it('should normalize file paths', () => {
const filePath = './test/../test.ts';
const normalizedPath = 'test.ts';
const id = 'test-id';
const context = 'test context';
const state = 'locked-context';
const entry = metadataManager.createEntry(filePath, id, context, state);
expect(entry.filePath).toBe(normalizedPath);
});
});
describe('updateEntry', () => {
it('should update state and add history entry', () => {
const filePath = 'test.ts';
const id = 'test-id';
const context = 'test context';
const initialState = 'locked-context';
metadataManager.createEntry(filePath, id, context, initialState);
const newState = 'locked';
const updatedEntry = metadataManager.updateEntry(filePath, { state: newState });
expect(updatedEntry.state).toBe(newState);
expect(updatedEntry.context).toBe(context);
expect(updatedEntry.history).toHaveLength(2);
expect(updatedEntry.history[1].state).toBe(newState);
});
it('should update context without changing state', () => {
const filePath = 'test.ts';
const id = 'test-id';
const initialContext = 'test context';
const state = 'locked-context';
metadataManager.createEntry(filePath, id, initialContext, state);
const newContext = 'updated context';
const updatedEntry = metadataManager.updateEntry(filePath, { context: newContext });
expect(updatedEntry.context).toBe(newContext);
expect(updatedEntry.state).toBe(state);
expect(updatedEntry.history).toHaveLength(1); // No state change, no new history entry
});
it('should throw error for non-existent file', () => {
expect(() => {
metadataManager.updateEntry('non-existent.ts', { state: 'locked' });
}).toThrow('No entry found for file: non-existent.ts');
});
});
describe('removeEntry', () => {
it('should remove existing entry', () => {
const filePath = 'test.ts';
const id = 'test-id';
const context = 'test context';
const state = 'locked-context';
metadataManager.createEntry(filePath, id, context, state);
const removed = metadataManager.removeEntry(filePath);
expect(removed).toBe(true);
expect(metadataManager.getEntry(filePath)).toBeNull();
});
it('should return false for non-existent entry', () => {
const removed = metadataManager.removeEntry('non-existent.ts');
expect(removed).toBe(false);
});
});
describe('getAllEntries', () => {
it('should return empty array when no entries exist', () => {
const entries = metadataManager.getAllEntries();
expect(entries).toEqual([]);
});
it('should return all entries', () => {
const files = ['test1.ts', 'test2.ts', 'test3.ts'];
files.forEach((file, index) => {
metadataManager.createEntry(file, `id-${index}`, `context-${index}`, 'locked-context');
});
const entries = metadataManager.getAllEntries();
expect(entries).toHaveLength(3);
expect(entries.map(e => e.filePath)).toEqual(expect.arrayContaining(files));
});
});
describe('metadata file persistence', () => {
it('should persist metadata to file system', () => {
const filePath = 'test.ts';
const id = 'test-id';
const context = 'test context';
const state = 'locked-context';
metadataManager.createEntry(filePath, id, context, state);
const metadataFile = path.join(tempDir, '.reporepo', 'locker', 'locker.json');
expect(fs.existsSync(metadataFile)).toBe(true);
const content = JSON.parse(fs.readFileSync(metadataFile, 'utf-8'));
expect(content.entries).toHaveLength(1);
expect(content.entries[0].filePath).toBe(filePath);
});
it('should load existing metadata from file system', () => {
const filePath = 'test.ts';
const id = 'test-id';
const context = 'test context';
const state = 'locked-context';
metadataManager.createEntry(filePath, id, context, state);
// Create new manager instance to test loading
const newManager = new metadata_1.MetadataManager(tempDir);
const entry = newManager.getEntry(filePath);
expect(entry).not.toBeNull();
expect(entry.filePath).toBe(filePath);
expect(entry.id).toBe(id);
expect(entry.context).toBe(context);
expect(entry.state).toBe(state);
});
it('should handle corrupted metadata file', () => {
const metadataDir = path.join(tempDir, '.reporepo', 'locker');
fs.mkdirSync(metadataDir, { recursive: true });
const metadataFile = path.join(metadataDir, 'locker.json');
// Write invalid JSON
fs.writeFileSync(metadataFile, 'invalid json content', 'utf-8');
expect(() => {
metadataManager.getEntry('test.ts');
}).toThrow('Failed to parse metadata file:');
});
it('should handle file system write errors', () => {
const filePath = 'test.ts';
const id = 'test-id';
const context = 'test context';
const state = 'locked-context';
// Create the metadata directory but make it read-only
const metadataDir = path.join(tempDir, '.reporepo', 'locker');
fs.mkdirSync(metadataDir, { recursive: true });
// Make directory read-only (this will cause write to fail)
fs.chmodSync(metadataDir, 0o444);
try {
expect(() => {
metadataManager.createEntry(filePath, id, context, state);
}).toThrow('Failed to save metadata file:');
}
finally {
// Restore permissions for cleanup
fs.chmodSync(metadataDir, 0o755);
}
});
});
});
//# sourceMappingURL=metadata.test.js.map