Skip to content

Commit b471b5e

Browse files
authored
Merge pull request #2924 from olaservo/update-tests-and-markdown-files
Add tests for memory server, fix filesystem tests, and move testing guidelines
2 parents f592b6b + 4198468 commit b471b5e

File tree

10 files changed

+617
-39
lines changed

10 files changed

+617
-39
lines changed

AGENTS.md

Lines changed: 0 additions & 9 deletions
This file was deleted.

CLAUDE.md

Lines changed: 0 additions & 2 deletions
This file was deleted.

CONTRIBUTING.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ We're more selective about:
2121
We don't accept:
2222
- **New server implementations** — We encourage you to publish them yourself, and link to them from the README.
2323

24+
## Testing
25+
26+
When adding or configuring tests for servers implemented in TypeScript, use **vitest** as the test framework. Vitest provides better ESM support, faster test execution, and a more modern testing experience.
27+
2428
## Documentation
2529

2630
Improvements to existing documentation is welcome - although generally we'd prefer ergonomic improvements than documenting pain points if possible!

package-lock.json

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/filesystem/__tests__/path-utils.test.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, it, expect } from 'vitest';
1+
import { describe, it, expect, afterEach } from 'vitest';
22
import { normalizePath, expandHome, convertToWindowsPath } from '../path-utils.js';
33

44
describe('Path Utilities', () => {
@@ -196,11 +196,8 @@ describe('Path Utilities', () => {
196196
});
197197

198198
it('returns normalized non-Windows/WSL/Unix-style Windows paths as is after basic normalization', () => {
199-
// Relative path
200-
const relativePath = 'some/relative/path';
201-
expect(normalizePath(relativePath)).toBe(relativePath.replace(/\//g, '\\'));
202-
203199
// A path that looks somewhat absolute but isn't a drive or recognized Unix root for Windows conversion
200+
// These paths should be preserved as-is (not converted to Windows C:\ format or WSL format)
204201
const otherAbsolutePath = '\\someserver\\share\\file';
205202
expect(normalizePath(otherAbsolutePath)).toBe(otherAbsolutePath);
206203
});
@@ -350,5 +347,19 @@ describe('Path Utilities', () => {
350347
expect(result).not.toContain('C:');
351348
expect(result).not.toContain('\\');
352349
});
350+
351+
it('should handle relative path slash conversion based on platform', () => {
352+
// This test verifies platform-specific behavior naturally without mocking
353+
// On Windows: forward slashes converted to backslashes
354+
// On Linux/Unix: forward slashes preserved
355+
const relativePath = 'some/relative/path';
356+
const result = normalizePath(relativePath);
357+
358+
if (originalPlatform === 'win32') {
359+
expect(result).toBe('some\\relative\\path');
360+
} else {
361+
expect(result).toBe('some/relative/path');
362+
}
363+
});
353364
});
354365
});
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2+
import { promises as fs } from 'fs';
3+
import path from 'path';
4+
import { fileURLToPath } from 'url';
5+
import { ensureMemoryFilePath, defaultMemoryPath } from '../index.js';
6+
7+
describe('ensureMemoryFilePath', () => {
8+
const testDir = path.dirname(fileURLToPath(import.meta.url));
9+
const oldMemoryPath = path.join(testDir, '..', 'memory.json');
10+
const newMemoryPath = path.join(testDir, '..', 'memory.jsonl');
11+
12+
let originalEnv: string | undefined;
13+
14+
beforeEach(() => {
15+
// Save original environment variable
16+
originalEnv = process.env.MEMORY_FILE_PATH;
17+
// Delete environment variable
18+
delete process.env.MEMORY_FILE_PATH;
19+
});
20+
21+
afterEach(async () => {
22+
// Restore original environment variable
23+
if (originalEnv !== undefined) {
24+
process.env.MEMORY_FILE_PATH = originalEnv;
25+
} else {
26+
delete process.env.MEMORY_FILE_PATH;
27+
}
28+
29+
// Clean up test files
30+
try {
31+
await fs.unlink(oldMemoryPath);
32+
} catch {
33+
// Ignore if file doesn't exist
34+
}
35+
try {
36+
await fs.unlink(newMemoryPath);
37+
} catch {
38+
// Ignore if file doesn't exist
39+
}
40+
});
41+
42+
describe('with MEMORY_FILE_PATH environment variable', () => {
43+
it('should return absolute path when MEMORY_FILE_PATH is absolute', async () => {
44+
const absolutePath = '/tmp/custom-memory.jsonl';
45+
process.env.MEMORY_FILE_PATH = absolutePath;
46+
47+
const result = await ensureMemoryFilePath();
48+
49+
expect(result).toBe(absolutePath);
50+
});
51+
52+
it('should convert relative path to absolute when MEMORY_FILE_PATH is relative', async () => {
53+
const relativePath = 'custom-memory.jsonl';
54+
process.env.MEMORY_FILE_PATH = relativePath;
55+
56+
const result = await ensureMemoryFilePath();
57+
58+
expect(path.isAbsolute(result)).toBe(true);
59+
expect(result).toContain('custom-memory.jsonl');
60+
});
61+
62+
it('should handle Windows absolute paths', async () => {
63+
const windowsPath = 'C:\\temp\\memory.jsonl';
64+
process.env.MEMORY_FILE_PATH = windowsPath;
65+
66+
const result = await ensureMemoryFilePath();
67+
68+
// On Windows, should return as-is; on Unix, will be treated as relative
69+
if (process.platform === 'win32') {
70+
expect(result).toBe(windowsPath);
71+
} else {
72+
expect(path.isAbsolute(result)).toBe(true);
73+
}
74+
});
75+
});
76+
77+
describe('without MEMORY_FILE_PATH environment variable', () => {
78+
it('should return default path when no files exist', async () => {
79+
const result = await ensureMemoryFilePath();
80+
81+
expect(result).toBe(defaultMemoryPath);
82+
});
83+
84+
it('should migrate from memory.json to memory.jsonl when only old file exists', async () => {
85+
// Create old memory.json file
86+
await fs.writeFile(oldMemoryPath, '{"test":"data"}');
87+
88+
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
89+
90+
const result = await ensureMemoryFilePath();
91+
92+
expect(result).toBe(defaultMemoryPath);
93+
94+
// Verify migration happened
95+
const newFileExists = await fs.access(newMemoryPath).then(() => true).catch(() => false);
96+
const oldFileExists = await fs.access(oldMemoryPath).then(() => true).catch(() => false);
97+
98+
expect(newFileExists).toBe(true);
99+
expect(oldFileExists).toBe(false);
100+
101+
// Verify console messages
102+
expect(consoleErrorSpy).toHaveBeenCalledWith(
103+
expect.stringContaining('DETECTED: Found legacy memory.json file')
104+
);
105+
expect(consoleErrorSpy).toHaveBeenCalledWith(
106+
expect.stringContaining('COMPLETED: Successfully migrated')
107+
);
108+
109+
consoleErrorSpy.mockRestore();
110+
});
111+
112+
it('should use new file when both old and new files exist', async () => {
113+
// Create both files
114+
await fs.writeFile(oldMemoryPath, '{"old":"data"}');
115+
await fs.writeFile(newMemoryPath, '{"new":"data"}');
116+
117+
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
118+
119+
const result = await ensureMemoryFilePath();
120+
121+
expect(result).toBe(defaultMemoryPath);
122+
123+
// Verify no migration happened (both files should still exist)
124+
const newFileExists = await fs.access(newMemoryPath).then(() => true).catch(() => false);
125+
const oldFileExists = await fs.access(oldMemoryPath).then(() => true).catch(() => false);
126+
127+
expect(newFileExists).toBe(true);
128+
expect(oldFileExists).toBe(true);
129+
130+
// Verify no console messages about migration
131+
expect(consoleErrorSpy).not.toHaveBeenCalled();
132+
133+
consoleErrorSpy.mockRestore();
134+
});
135+
136+
it('should preserve file content during migration', async () => {
137+
const testContent = '{"entities": [{"name": "test", "type": "person"}]}';
138+
await fs.writeFile(oldMemoryPath, testContent);
139+
140+
await ensureMemoryFilePath();
141+
142+
const migratedContent = await fs.readFile(newMemoryPath, 'utf-8');
143+
expect(migratedContent).toBe(testContent);
144+
});
145+
});
146+
147+
describe('defaultMemoryPath', () => {
148+
it('should end with memory.jsonl', () => {
149+
expect(defaultMemoryPath).toMatch(/memory\.jsonl$/);
150+
});
151+
152+
it('should be an absolute path', () => {
153+
expect(path.isAbsolute(defaultMemoryPath)).toBe(true);
154+
});
155+
});
156+
});

0 commit comments

Comments
 (0)