Skip to content

Commit 583dcfb

Browse files
mertcanaltinjasnell
authored andcommitted
test: add FastUtf8Stream tests
1 parent 077d9ae commit 583dcfb

14 files changed

+3076
-688
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
'use strict';
2+
3+
require('../common');
4+
const { test } = require('node:test');
5+
const assert = require('node:assert');
6+
const fs = require('node:fs');
7+
const { FastUtf8Stream } = require('node:fs');
8+
const { tmpdir } = require('node:os');
9+
const path = require('node:path');
10+
11+
let fileCounter = 0;
12+
13+
function getTempFile() {
14+
return path.join(tmpdir(), `fastutf8stream-${process.pid}-${Date.now()}-${fileCounter++}.log`);
15+
}
16+
17+
test('FastUtf8Stream destroy - basic functionality', async (t) => {
18+
// Reset the umask for testing
19+
process.umask(0o000);
20+
21+
const dest = getTempFile();
22+
const fd = fs.openSync(dest, 'w');
23+
const stream = new FastUtf8Stream({ fd, sync: false });
24+
25+
// Test successful write
26+
const writeResult = stream.write('hello world\n');
27+
assert.ok(writeResult);
28+
29+
// Destroy the stream
30+
stream.destroy();
31+
32+
// Test that write throws after destroy
33+
assert.throws(() => {
34+
stream.write('hello world\n');
35+
}, Error);
36+
37+
// Wait for file to be written and check content
38+
await new Promise((resolve, reject) => {
39+
fs.readFile(dest, 'utf8', (err, data) => {
40+
if (err) reject(err);
41+
else {
42+
assert.strictEqual(data, 'hello world\n');
43+
resolve();
44+
}
45+
});
46+
});
47+
48+
// Test events - use Promise to handle async events
49+
const eventPromises = [];
50+
51+
// Finish event should NOT be emitted after destroy
52+
eventPromises.push(new Promise((resolve) => {
53+
const finishTimeout = setTimeout(() => {
54+
resolve('finish not emitted'); // This is what we want
55+
}, 100);
56+
57+
stream.on('finish', () => {
58+
clearTimeout(finishTimeout);
59+
resolve('finish emitted');
60+
});
61+
}));
62+
63+
// Close event SHOULD be emitted after destroy
64+
eventPromises.push(new Promise((resolve) => {
65+
stream.on('close', () => {
66+
resolve('close emitted');
67+
});
68+
}));
69+
70+
const [finishResult, closeResult] = await Promise.all(eventPromises);
71+
72+
assert.strictEqual(finishResult, 'finish not emitted');
73+
assert.strictEqual(closeResult, 'close emitted');
74+
75+
// Cleanup
76+
try {
77+
fs.unlinkSync(dest);
78+
} catch (err) {
79+
console.warn('Cleanup error:', err.message);
80+
}
81+
});
82+
83+
test('FastUtf8Stream destroy - sync mode', async (t) => {
84+
process.umask(0o000);
85+
86+
const dest = getTempFile();
87+
const fd = fs.openSync(dest, 'w');
88+
const stream = new FastUtf8Stream({ fd, sync: true });
89+
90+
assert.ok(stream.write('hello world\n'));
91+
stream.destroy();
92+
assert.throws(() => { stream.write('hello world\n'); }, Error);
93+
94+
const data = fs.readFileSync(dest, 'utf8');
95+
assert.strictEqual(data, 'hello world\n');
96+
97+
// Cleanup
98+
try {
99+
fs.unlinkSync(dest);
100+
} catch (err) {
101+
console.warn('Cleanup error:', err.message);
102+
}
103+
});
104+
105+
test('FastUtf8Stream destroy while opening', async (t) => {
106+
const dest = getTempFile();
107+
const stream = new FastUtf8Stream({ dest });
108+
109+
// Destroy immediately while opening
110+
stream.destroy();
111+
112+
// Wait for close event
113+
await new Promise((resolve) => {
114+
stream.on('close', () => {
115+
resolve();
116+
});
117+
});
118+
119+
// Cleanup
120+
try {
121+
fs.unlinkSync(dest);
122+
} catch (err) {
123+
console.warn('Cleanup error:', err.message);
124+
}
125+
});
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
'use strict';
2+
3+
require('../common');
4+
const { test } = require('node:test');
5+
const assert = require('node:assert');
6+
const fs = require('node:fs');
7+
const { FastUtf8Stream } = require('node:fs');
8+
const { tmpdir } = require('node:os');
9+
const path = require('node:path');
10+
11+
let fileCounter = 0;
12+
13+
function getTempFile() {
14+
return path.join(tmpdir(), `fastutf8stream-${process.pid}-${Date.now()}-${fileCounter++}.log`);
15+
}
16+
17+
function runTests(buildTests) {
18+
buildTests(test, false);
19+
buildTests(test, true);
20+
}
21+
22+
runTests(buildTests);
23+
24+
function buildTests(test, sync) {
25+
// Reset the umask for testing
26+
process.umask(0o000);
27+
28+
test(`end after reopen - sync: ${sync}`, async (t) => {
29+
const dest = getTempFile();
30+
const stream = new FastUtf8Stream({ dest, minLength: 4096, sync });
31+
32+
await new Promise((resolve) => {
33+
stream.once('ready', () => {
34+
const after = dest + '-moved';
35+
stream.reopen(after);
36+
stream.write('after reopen\n');
37+
stream.on('finish', () => {
38+
fs.readFile(after, 'utf8', (err, data) => {
39+
assert.ifError(err);
40+
assert.strictEqual(data, 'after reopen\n');
41+
42+
// Cleanup
43+
try {
44+
fs.unlinkSync(dest);
45+
fs.unlinkSync(after);
46+
} catch (err) {
47+
console.warn('Cleanup error:', err.message);
48+
}
49+
50+
resolve();
51+
});
52+
});
53+
stream.end();
54+
});
55+
});
56+
});
57+
58+
test(`end after 2x reopen - sync: ${sync}`, async (t) => {
59+
const dest = getTempFile();
60+
const stream = new FastUtf8Stream({ dest, minLength: 4096, sync });
61+
62+
await new Promise((resolve) => {
63+
stream.once('ready', () => {
64+
stream.reopen(dest + '-moved');
65+
const after = dest + '-moved-moved';
66+
stream.reopen(after);
67+
stream.write('after reopen\n');
68+
stream.on('finish', () => {
69+
fs.readFile(after, 'utf8', (err, data) => {
70+
assert.ifError(err);
71+
assert.strictEqual(data, 'after reopen\n');
72+
73+
// Cleanup
74+
try {
75+
fs.unlinkSync(dest);
76+
fs.unlinkSync(dest + '-moved');
77+
fs.unlinkSync(after);
78+
} catch (err) {
79+
console.warn('Cleanup error:', err.message);
80+
}
81+
82+
resolve();
83+
});
84+
});
85+
stream.end();
86+
});
87+
});
88+
});
89+
90+
test(`end if not ready - sync: ${sync}`, async (t) => {
91+
const dest = getTempFile();
92+
const stream = new FastUtf8Stream({ dest, minLength: 4096, sync });
93+
const after = dest + '-moved';
94+
95+
stream.reopen(after);
96+
stream.write('after reopen\n');
97+
98+
await new Promise((resolve) => {
99+
stream.on('finish', () => {
100+
fs.readFile(after, 'utf8', (err, data) => {
101+
assert.ifError(err);
102+
assert.strictEqual(data, 'after reopen\n');
103+
104+
// Cleanup
105+
try {
106+
fs.unlinkSync(dest);
107+
fs.unlinkSync(after);
108+
} catch {
109+
// Ignore cleanup errors
110+
}
111+
112+
resolve();
113+
});
114+
});
115+
116+
stream.end();
117+
});
118+
});
119+
120+
test(`large data write - sync: ${sync}`, async (t) => {
121+
const dest = getTempFile();
122+
const stream = new FastUtf8Stream({ dest, sync });
123+
const str = Buffer.alloc(10000).fill('a').toString();
124+
125+
let totalWritten = 0;
126+
const writeData = () => {
127+
if (totalWritten >= 10000) {
128+
stream.end();
129+
return;
130+
}
131+
132+
const chunk = str.slice(totalWritten, totalWritten + 1000);
133+
if (stream.write(chunk)) {
134+
totalWritten += chunk.length;
135+
setImmediate(writeData);
136+
} else {
137+
stream.once('drain', () => {
138+
totalWritten += chunk.length;
139+
setImmediate(writeData);
140+
});
141+
}
142+
};
143+
144+
await new Promise((resolve) => {
145+
stream.on('finish', () => {
146+
fs.readFile(dest, 'utf8', (err, data) => {
147+
assert.ifError(err);
148+
assert.strictEqual(data.length, 10000);
149+
assert.strictEqual(data, str);
150+
151+
// Cleanup
152+
try {
153+
fs.unlinkSync(dest);
154+
} catch {
155+
// Ignore cleanup errors
156+
}
157+
158+
resolve();
159+
});
160+
});
161+
162+
writeData();
163+
});
164+
});
165+
}

0 commit comments

Comments
 (0)