Skip to content

Commit 652563a

Browse files
committed
Test symlink mounting
1 parent d18f5fa commit 652563a

File tree

1 file changed

+77
-141
lines changed

1 file changed

+77
-141
lines changed

packages/php-wasm/node/src/test/mounting.spec.ts

Lines changed: 77 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ describe('Mounting', () => {
88
let php: PHP;
99

1010
beforeEach(async () => {
11-
php = new PHP(await loadNodeRuntime(RecommendedPHPVersion));
11+
php = new PHP(
12+
await loadNodeRuntime(RecommendedPHPVersion, {
13+
followSymlinks: true,
14+
})
15+
);
1216
});
1317
afterEach(async () => {
1418
php.exit();
@@ -21,25 +25,19 @@ describe('Mounting', () => {
2125
'long-post-body.txt'
2226
);
2327

24-
const unmount = await php.mount(
28+
await php.mount(
2529
'/single-file.txt',
2630
createNodeFsMountHandler(testFilePath)
2731
);
2832

2933
const vfsContent = await php.readFileAsText('/single-file.txt');
3034
const localContent = fs.readFileSync(testFilePath, 'utf8');
3135
expect(vfsContent).toEqual(localContent);
32-
33-
await unmount();
34-
expect(php.isFile('/single-file.txt')).toBe(false);
3536
});
3637

3738
it('Should mount nested directories with recursive structure matching', async () => {
3839
const testDataPath = path.join(__dirname, 'test-data');
39-
const unmount = await php.mount(
40-
'/nested-test',
41-
createNodeFsMountHandler(testDataPath)
42-
);
40+
await php.mount('/nested-test', createNodeFsMountHandler(testDataPath));
4341

4442
// Recursively compare directory structure
4543
const compareDirectories = (vfsPath: string, localPath: string) => {
@@ -79,160 +77,98 @@ describe('Mounting', () => {
7977
const localContent = fs.readFileSync(localNestedPath, 'utf8');
8078
expect(vfsContent).toEqual(localContent);
8179
}
82-
83-
await unmount();
84-
expect(php.isDir('/nested-test')).toBe(false);
8580
});
8681

87-
describe('File types and system operations', () => {
88-
it('Should handle all file types with comprehensive FS comparison', async () => {
89-
const testDataPath = path.join(__dirname, 'test-data');
82+
it('Should mount a symlink', async () => {
83+
const symlinkPath = path.join(__dirname, 'test-data', 'symlink.txt');
84+
const symlinkTarget = path.join(
85+
__dirname,
86+
'test-data',
87+
'long-post-body.txt'
88+
);
89+
const vfsMountPoint = '/symlink.txt';
90+
try {
91+
fs.symlinkSync(symlinkTarget, symlinkPath, 'file');
92+
9093
await php.mount(
91-
'/comprehensive-test',
92-
createNodeFsMountHandler(testDataPath)
94+
vfsMountPoint,
95+
createNodeFsMountHandler(symlinkPath)
9396
);
9497

95-
const localFiles = fs.readdirSync(testDataPath);
96-
97-
for (const file of localFiles) {
98-
const localPath = path.join(testDataPath, file);
99-
const vfsPath = `/comprehensive-test/${file}`;
100-
const localStat = fs.statSync(localPath);
101-
102-
if (localStat.isFile()) {
103-
// Test binary files (images)
104-
if (file.endsWith('.jpg') || file.endsWith('.png')) {
105-
const vfsBinary = await php.readFileAsBuffer(vfsPath);
106-
const localBinary = fs.readFileSync(localPath);
107-
expect(Buffer.from(vfsBinary)).toEqual(localBinary);
108-
expect(vfsBinary.length).toBe(localStat.size);
109-
}
110-
// Test text files (certificates, documents)
111-
else if (file.endsWith('.txt') || file.endsWith('.pem')) {
112-
const vfsText = await php.readFileAsText(vfsPath);
113-
const localText = fs.readFileSync(localPath, 'utf8');
114-
expect(vfsText).toEqual(localText);
115-
expect(vfsText.length).toBe(localStat.size);
116-
117-
// Special certificate validation
118-
if (
119-
file.endsWith('.pem') &&
120-
localText.includes('-----BEGIN CERTIFICATE-----')
121-
) {
122-
expect(vfsText).toContain(
123-
'-----BEGIN CERTIFICATE-----'
124-
);
125-
}
126-
}
127-
128-
// Test stat operations
129-
const phpStat = await php.run({
130-
code: `<?php
131-
$stat = stat('/comprehensive-test/${file}');
132-
echo json_encode([
133-
'size' => $stat['size'],
134-
'mode' => $stat['mode'],
135-
'mtime' => $stat['mtime'],
136-
'is_file' => is_file('/comprehensive-test/${file}'),
137-
'is_readable' => is_readable('/comprehensive-test/${file}'),
138-
'filesize' => filesize('/comprehensive-test/${file}')
139-
]);
140-
`,
141-
});
142-
143-
const vfsStatResult = JSON.parse(phpStat.text);
144-
expect(vfsStatResult.size).toBe(localStat.size);
145-
expect(vfsStatResult.mtime).toBe(
146-
Math.floor(localStat.mtime.getTime() / 1000)
147-
);
148-
expect(vfsStatResult.is_file).toBe(true);
149-
expect(vfsStatResult.is_readable).toBe(true);
150-
expect(vfsStatResult.filesize).toBe(localStat.size);
151-
}
152-
}
153-
154-
// Test directory listing through PHP
155-
const phpListing = await php.run({
156-
code: `<?php
157-
$files = scandir('/comprehensive-test');
158-
echo json_encode(array_filter($files, function($file) {
159-
return !in_array($file, ['.', '..']);
160-
}));
161-
`,
162-
});
163-
164-
const vfsPhpFiles = JSON.parse(phpListing.text);
165-
expect(vfsPhpFiles.sort()).toEqual(localFiles.sort());
166-
});
98+
expect(php.isFile(vfsMountPoint)).toBe(true);
99+
expect(php.readFileAsText(vfsMountPoint)).toEqual(
100+
fs.readFileSync(symlinkTarget, 'utf8')
101+
);
102+
} finally {
103+
fs.unlinkSync(symlinkPath);
104+
}
167105
});
168106

169-
describe('Unmounting', () => {
170-
it('Should unmount a file and remove created node from VFS', async () => {
171-
const testFilePath = path.join(
172-
__dirname,
173-
'test-data',
174-
'long-post-body.txt'
175-
);
107+
it('Should unmount a file and remove created node from VFS', async () => {
108+
const testFilePath = path.join(
109+
__dirname,
110+
'test-data',
111+
'long-post-body.txt'
112+
);
176113

177-
const unmount = await php.mount(
178-
'/single-file.txt',
179-
createNodeFsMountHandler(testFilePath)
180-
);
114+
const unmount = await php.mount(
115+
'/single-file.txt',
116+
createNodeFsMountHandler(testFilePath)
117+
);
181118

182-
expect(php.isFile('/single-file.txt')).toBe(true);
119+
expect(php.isFile('/single-file.txt')).toBe(true);
183120

184-
await unmount();
185-
expect(php.isFile('/single-file.txt')).toBe(false);
186-
});
121+
await unmount();
122+
expect(php.isFile('/single-file.txt')).toBe(false);
123+
});
187124

188-
it('Should unmount a directory and remove created node from VFS', async () => {
189-
const testDataPath = path.join(__dirname, 'test-data');
190-
const unmount = await php.mount(
191-
'/nested-test',
192-
createNodeFsMountHandler(testDataPath)
193-
);
125+
it('Should unmount a directory and remove created node from VFS', async () => {
126+
const testDataPath = path.join(__dirname, 'test-data');
127+
const unmount = await php.mount(
128+
'/nested-test',
129+
createNodeFsMountHandler(testDataPath)
130+
);
194131

195-
expect(php.isDir('/nested-test')).toBe(true);
132+
expect(php.isDir('/nested-test')).toBe(true);
196133

197-
await unmount();
198-
expect(php.isDir('/nested-test')).toBe(false);
199-
});
134+
await unmount();
135+
expect(php.isDir('/nested-test')).toBe(false);
136+
});
200137

201-
it('Should unmount a file, but not remove the parent directory from VFS if it was created manually', async () => {
202-
const testFilePath = path.join(
203-
__dirname,
204-
'test-data',
205-
'long-post-body.txt'
206-
);
138+
it('Should unmount a file, but not remove the parent directory from VFS if it was created manually', async () => {
139+
const testFilePath = path.join(
140+
__dirname,
141+
'test-data',
142+
'long-post-body.txt'
143+
);
207144

208-
const mountPoint = '/sub-dir/single-file.txt';
145+
const mountPoint = '/sub-dir/single-file.txt';
209146

210-
await php.mkdir(dirname(mountPoint));
147+
await php.mkdir(dirname(mountPoint));
211148

212-
const unmount = await php.mount(
213-
mountPoint,
214-
createNodeFsMountHandler(testFilePath)
215-
);
149+
const unmount = await php.mount(
150+
mountPoint,
151+
createNodeFsMountHandler(testFilePath)
152+
);
216153

217-
expect(php.isFile(mountPoint)).toBe(true);
154+
expect(php.isFile(mountPoint)).toBe(true);
218155

219-
await unmount();
220-
expect(php.isDir(dirname(mountPoint))).toBe(true);
221-
});
156+
await unmount();
157+
expect(php.isDir(dirname(mountPoint))).toBe(true);
158+
});
222159

223-
it('Should unmount a directory, but not remove the parent directory from VFS if it was created manually', async () => {
224-
const testDataPath = path.join(__dirname, 'test-data');
160+
it('Should unmount a directory, but not remove the parent directory from VFS if it was created manually', async () => {
161+
const testDataPath = path.join(__dirname, 'test-data');
225162

226-
await php.mkdir('/nested-test');
227-
const unmount = await php.mount(
228-
'/nested-test',
229-
createNodeFsMountHandler(testDataPath)
230-
);
163+
await php.mkdir('/nested-test');
164+
const unmount = await php.mount(
165+
'/nested-test',
166+
createNodeFsMountHandler(testDataPath)
167+
);
231168

232-
expect(php.isDir('/nested-test')).toBe(true);
169+
expect(php.isDir('/nested-test')).toBe(true);
233170

234-
await unmount();
235-
expect(php.isDir('/nested-test')).toBe(true);
236-
});
171+
await unmount();
172+
expect(php.isDir('/nested-test')).toBe(true);
237173
});
238174
});

0 commit comments

Comments
 (0)