tschaub / mock-fs

Configurable mock for the fs module
https://npmjs.org/package/mock-fs
Other
906 stars 86 forks source link

Calls to asynchronous `fs.appendFile()` overwrite each other #37

Open jwngr opened 9 years ago

jwngr commented 9 years ago

Sequential calls to the asynchronous fs.appendFile() using this mocked library appear to conflict and overwrite each other, while the non-mocked library does not have this behavior.

Here is the behavior with the regular fs library:

var fs = require('fs');

var filename = './foo.txt';

for (var i = 0; i < 5; ++i) {
  fs.appendFile(filename, 'iteration' + i + '\n', function(error) {
    if (error) {
      console.log('Error:', error)
    }
    console.log('Added');
  });
}

setTimeout(function() {
  fs.readFile(filename, 'utf8', function (err, data) {
    if (err) throw err;
    console.log(data);
  });
}, 1000);

This outputs the following:

Added
Added
Added
Added
Added
iteration0
iteration4
iteration1
iteration3
iteration2

Note that this output is non-deterministic because the five writes could complete in any order. But that is tangential to this issue.

Now, using the mock-fs library:

var fs = require('fs');
var mockFs = require('mock-fs');

var filename = './foo.txt';

mockFs({
  '.': {}
});

for (var i = 0; i < 5; ++i) {
  fs.appendFile(filename, 'iteration' + i + '\n', function(error) {
    if (error) {
      console.log('Error:', error)
    }
    console.log('Added');
  });
}

setTimeout(function() {
  fs.readFile(filename, 'utf8', function (err, data) {
    if (err) throw err;
    console.log(data);
  });
}, 1000);

This outputs:

Added
Added
Added
Added
Added
iteration4

As you can see, only the last append succeeds. If we use the synchronous mocked version, all is well:

var fs = require('fs');
var mockFs = require('mock-fs');

var filename = './foo.txt';

mockFs({
  '.': {}
});

for (var i = 0; i < 5; ++i) {
  fs.appendFileSync(filename, 'iteration' + i + '\n');
}

setTimeout(function() {
  fs.readFile(filename, 'utf8', function (err, data) {
    if (err) throw err;
    console.log(data);
  });
}, 1000);

Outputs:

iteration0
iteration1
iteration2
iteration3
iteration4

I would like to use the asynchronous version of appendFile() because I don't care about the ordering of items, just that they all are there. I also don't want to block the process while the write is happening, which is what the synchronous version does.

jwngr commented 9 years ago

Hey @tschaub - if you can point me to some code lines or let me know what you think may be the issue here, I'd be happy to put together a PR for this. I assume the issue here is that each call to appendFile() is actually overwriting the file instead of appending to it. We don't run into this issue with appendFileSync() since it blocks the process until the append is done, before any other appends can be started.