Skip to content

Commit 975ee1e

Browse files
committed
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
1 parent 81e4d2e commit 975ee1e

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/xxxxx
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()`][].
@@ -890,6 +895,10 @@ the error raised if the file is not accessible.
890895
891896
<!-- YAML
892897
added: v10.0.0
898+
changes:
899+
- version: REPLACEME
900+
pr-url: https://github.com/nodejs/node/pull/xxxxx
901+
description: The `flush` option is now supported.
893902
-->
894903
895904
* `path` {string|Buffer|URL|FileHandle} filename or {FileHandle}
@@ -898,6 +907,8 @@ added: v10.0.0
898907
* `encoding` {string|null} **Default:** `'utf8'`
899908
* `mode` {integer} **Default:** `0o666`
900909
* `flag` {string} See [support of file system `flags`][]. **Default:** `'a'`.
910+
* `flush` {boolean} If `true`, the underlying file descriptor is flushed
911+
prior to closing it. **Default:** `false`.
901912
* Returns: {Promise} Fulfills with `undefined` upon success.
902913
903914
Asynchronously append data to a file, creating the file if it does not yet
@@ -2044,6 +2055,9 @@ the user from reading or writing to it.
20442055
<!-- YAML
20452056
added: v0.6.7
20462057
changes:
2058+
- version: REPLACEME
2059+
pr-url: https://github.com/nodejs/node/pull/xxxxx
2060+
description: The `flush` option is now supported.
20472061
- version: v18.0.0
20482062
pr-url: https://github.com/nodejs/node/pull/41678
20492063
description: Passing an invalid callback to the `callback` argument
@@ -2071,6 +2085,8 @@ changes:
20712085
* `encoding` {string|null} **Default:** `'utf8'`
20722086
* `mode` {integer} **Default:** `0o666`
20732087
* `flag` {string} See [support of file system `flags`][]. **Default:** `'a'`.
2088+
* `flush` {boolean} If `true`, the underlying file descriptor is flushed
2089+
prior to closing it. **Default:** `false`.
20742090
* `callback` {Function}
20752091
* `err` {Error}
20762092
@@ -5127,6 +5143,9 @@ try {
51275143
<!-- YAML
51285144
added: v0.6.7
51295145
changes:
5146+
- version: REPLACEME
5147+
pr-url: https://github.com/nodejs/node/pull/xxxxx
5148+
description: The `flush` option is now supported.
51305149
- version: v7.0.0
51315150
pr-url: https://github.com/nodejs/node/pull/7831
51325151
description: The passed `options` object will never be modified.
@@ -5141,6 +5160,8 @@ changes:
51415160
* `encoding` {string|null} **Default:** `'utf8'`
51425161
* `mode` {integer} **Default:** `0o666`
51435162
* `flag` {string} See [support of file system `flags`][]. **Default:** `'a'`.
5163+
* `flush` {boolean} If `true`, the underlying file descriptor is flushed
5164+
prior to closing it. **Default:** `false`.
51445165

51455166
Synchronously append data to a file, creating the file if it does not yet
51465167
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)