Skip to content

Commit 18862e4

Browse files
cjihrigtargos
authored andcommitted
fs: add flush option to appendFile() functions
This commit adds documentation and tests for the 'flush' option of the fs.appendFile family of functions. Technically, support was indirectly added in #50009, but this makes it more official. Refs: #49886 Refs: #50009 PR-URL: #50095 Reviewed-By: Matteo Collina <[email protected]>
1 parent 82363be commit 18862e4

File tree

2 files changed

+135
-0
lines changed

2 files changed

+135
-0
lines changed

doc/api/fs.md

+21
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ longer be used.
180180
<!-- YAML
181181
added: v10.0.0
182182
changes:
183+
- version: REPLACEME
184+
pr-url: https://github.com/nodejs/node/pull/50095
185+
description: The `flush` option is now supported.
183186
- version:
184187
- v15.14.0
185188
- v14.18.0
@@ -194,6 +197,8 @@ changes:
194197
* `data` {string|Buffer|TypedArray|DataView|AsyncIterable|Iterable|Stream}
195198
* `options` {Object|string}
196199
* `encoding` {string|null} **Default:** `'utf8'`
200+
* `flush` {boolean} If `true`, the underlying file descriptor is flushed
201+
prior to closing it. **Default:** `false`.
197202
* Returns: {Promise} Fulfills with `undefined` upon success.
198203

199204
Alias of [`filehandle.writeFile()`][].
@@ -896,6 +901,10 @@ the error raised if the file is not accessible.
896901
897902
<!-- YAML
898903
added: v10.0.0
904+
changes:
905+
- version: REPLACEME
906+
pr-url: https://github.com/nodejs/node/pull/50095
907+
description: The `flush` option is now supported.
899908
-->
900909
901910
* `path` {string|Buffer|URL|FileHandle} filename or {FileHandle}
@@ -904,6 +913,8 @@ added: v10.0.0
904913
* `encoding` {string|null} **Default:** `'utf8'`
905914
* `mode` {integer} **Default:** `0o666`
906915
* `flag` {string} See [support of file system `flags`][]. **Default:** `'a'`.
916+
* `flush` {boolean} If `true`, the underlying file descriptor is flushed
917+
prior to closing it. **Default:** `false`.
907918
* Returns: {Promise} Fulfills with `undefined` upon success.
908919
909920
Asynchronously append data to a file, creating the file if it does not yet
@@ -2052,6 +2063,9 @@ the user from reading or writing to it.
20522063
<!-- YAML
20532064
added: v0.6.7
20542065
changes:
2066+
- version: REPLACEME
2067+
pr-url: https://github.com/nodejs/node/pull/50095
2068+
description: The `flush` option is now supported.
20552069
- version: v18.0.0
20562070
pr-url: https://github.com/nodejs/node/pull/41678
20572071
description: Passing an invalid callback to the `callback` argument
@@ -2079,6 +2093,8 @@ changes:
20792093
* `encoding` {string|null} **Default:** `'utf8'`
20802094
* `mode` {integer} **Default:** `0o666`
20812095
* `flag` {string} See [support of file system `flags`][]. **Default:** `'a'`.
2096+
* `flush` {boolean} If `true`, the underlying file descriptor is flushed
2097+
prior to closing it. **Default:** `false`.
20822098
* `callback` {Function}
20832099
* `err` {Error}
20842100
@@ -5142,6 +5158,9 @@ try {
51425158
<!-- YAML
51435159
added: v0.6.7
51445160
changes:
5161+
- version: REPLACEME
5162+
pr-url: https://github.com/nodejs/node/pull/50095
5163+
description: The `flush` option is now supported.
51455164
- version: v7.0.0
51465165
pr-url: https://github.com/nodejs/node/pull/7831
51475166
description: The passed `options` object will never be modified.
@@ -5156,6 +5175,8 @@ changes:
51565175
* `encoding` {string|null} **Default:** `'utf8'`
51575176
* `mode` {integer} **Default:** `0o666`
51585177
* `flag` {string} See [support of file system `flags`][]. **Default:** `'a'`.
5178+
* `flush` {boolean} If `true`, the underlying file descriptor is flushed
5179+
prior to closing it. **Default:** `false`.
51595180

51605181
Synchronously append data to a file, creating the file if it does not yet
51615182
exist. `data` can be a string or a {Buffer}.
+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
'use strict';
2+
const common = require('../common');
3+
const tmpdir = require('../common/tmpdir');
4+
const assert = require('node:assert');
5+
const fs = require('node:fs');
6+
const fsp = require('node:fs/promises');
7+
const test = require('node:test');
8+
const data = 'foo';
9+
let cnt = 0;
10+
11+
function nextFile() {
12+
return tmpdir.resolve(`${cnt++}.out`);
13+
}
14+
15+
tmpdir.refresh();
16+
17+
test('synchronous version', async (t) => {
18+
await t.test('validation', (t) => {
19+
for (const v of ['true', '', 0, 1, [], {}, Symbol()]) {
20+
assert.throws(() => {
21+
fs.appendFileSync(nextFile(), data, { flush: v });
22+
}, { code: 'ERR_INVALID_ARG_TYPE' });
23+
}
24+
});
25+
26+
await t.test('performs flush', (t) => {
27+
const spy = t.mock.method(fs, 'fsyncSync');
28+
const file = nextFile();
29+
fs.appendFileSync(file, data, { flush: true });
30+
const calls = spy.mock.calls;
31+
assert.strictEqual(calls.length, 1);
32+
assert.strictEqual(calls[0].result, undefined);
33+
assert.strictEqual(calls[0].error, undefined);
34+
assert.strictEqual(calls[0].arguments.length, 1);
35+
assert.strictEqual(typeof calls[0].arguments[0], 'number');
36+
assert.strictEqual(fs.readFileSync(file, 'utf8'), data);
37+
});
38+
39+
await t.test('does not perform flush', (t) => {
40+
const spy = t.mock.method(fs, 'fsyncSync');
41+
42+
for (const v of [undefined, null, false]) {
43+
const file = nextFile();
44+
fs.appendFileSync(file, data, { flush: v });
45+
assert.strictEqual(fs.readFileSync(file, 'utf8'), data);
46+
}
47+
48+
assert.strictEqual(spy.mock.calls.length, 0);
49+
});
50+
});
51+
52+
test('callback version', async (t) => {
53+
await t.test('validation', (t) => {
54+
for (const v of ['true', '', 0, 1, [], {}, Symbol()]) {
55+
assert.throws(() => {
56+
fs.appendFileSync(nextFile(), data, { flush: v });
57+
}, { code: 'ERR_INVALID_ARG_TYPE' });
58+
}
59+
});
60+
61+
await t.test('performs flush', (t, done) => {
62+
const spy = t.mock.method(fs, 'fsync');
63+
const file = nextFile();
64+
fs.appendFile(file, data, { flush: true }, common.mustSucceed(() => {
65+
const calls = spy.mock.calls;
66+
assert.strictEqual(calls.length, 1);
67+
assert.strictEqual(calls[0].result, undefined);
68+
assert.strictEqual(calls[0].error, undefined);
69+
assert.strictEqual(calls[0].arguments.length, 2);
70+
assert.strictEqual(typeof calls[0].arguments[0], 'number');
71+
assert.strictEqual(typeof calls[0].arguments[1], 'function');
72+
assert.strictEqual(fs.readFileSync(file, 'utf8'), data);
73+
done();
74+
}));
75+
});
76+
77+
await t.test('does not perform flush', (t, done) => {
78+
const values = [undefined, null, false];
79+
const spy = t.mock.method(fs, 'fsync');
80+
let cnt = 0;
81+
82+
for (const v of values) {
83+
const file = nextFile();
84+
85+
fs.appendFile(file, data, { flush: v }, common.mustSucceed(() => {
86+
assert.strictEqual(fs.readFileSync(file, 'utf8'), data);
87+
cnt++;
88+
89+
if (cnt === values.length) {
90+
assert.strictEqual(spy.mock.calls.length, 0);
91+
done();
92+
}
93+
}));
94+
}
95+
});
96+
});
97+
98+
test('promise based version', async (t) => {
99+
await t.test('validation', async (t) => {
100+
for (const v of ['true', '', 0, 1, [], {}, Symbol()]) {
101+
await assert.rejects(() => {
102+
return fsp.appendFile(nextFile(), data, { flush: v });
103+
}, { code: 'ERR_INVALID_ARG_TYPE' });
104+
}
105+
});
106+
107+
await t.test('success path', async (t) => {
108+
for (const v of [undefined, null, false, true]) {
109+
const file = nextFile();
110+
await fsp.appendFile(file, data, { flush: v });
111+
assert.strictEqual(await fsp.readFile(file, 'utf8'), data);
112+
}
113+
});
114+
});

0 commit comments

Comments
 (0)