Skip to content

fs, test: one set of file attributes in Windows prevents fs.fchmod() from changing mode to RW and breaks incomplete test #12803

Closed
@vsemozhetbyt

Description

@vsemozhetbyt
  • Version: 8.0.0 nightly 2017 05 01
  • Platform: Windows 7 x64
  • Subsystem: fs, libuv?, test

This is a confusing story here, so I am sorry for possibly clumsy wording.

Prehistory

I was launching tests with own test runner, each test with various context several times, and I've found out that parallel/test-fs-chmod.js was OK on the first run and failed on all the next ones. Moreover, this happened not on all the machines.

This turned up to be caused by some combination of a fixture file attributes.

Excursus

See this small attrib doc for context.

The test fails if both -a and -i flags are unset for a fixture file used in the test. This unsetting combination, strangely enough, correlates with this GUI setting:

Screenshot:

a


How to reproduce

Try to run these commands with repo root as cwd (firstly, we set a combination of the -a and -i flags; then we check the current attributes; then we run the test twice; then we check if the attributes are the same.; --no-deprecation key there is due to cause of #12795).

Commands :
attrib +a +i test/fixtures/a1.js
attrib test/fixtures/a1.js
node --no-deprecation test/parallel/test-fs-chmod.js
node --no-deprecation test/parallel/test-fs-chmod.js
attrib test/fixtures/a1.js

attrib +a -i test/fixtures/a1.js
attrib test/fixtures/a1.js
node --no-deprecation test/parallel/test-fs-chmod.js
node --no-deprecation test/parallel/test-fs-chmod.js
attrib test/fixtures/a1.js

attrib -a +i test/fixtures/a1.js
attrib test/fixtures/a1.js
node --no-deprecation test/parallel/test-fs-chmod.js
node --no-deprecation test/parallel/test-fs-chmod.js
attrib test/fixtures/a1.js

attrib -a -i test/fixtures/a1.js
attrib test/fixtures/a1.js
node --no-deprecation test/parallel/test-fs-chmod.js
node --no-deprecation test/parallel/test-fs-chmod.js
attrib test/fixtures/a1.js

I see this output (some path details stripped, borders added after each iteration):

Output:
/******************************************************************************/
> attrib +a +i test/fixtures/a1.js

> attrib test/fixtures/a1.js
A       I    fixtures/a1.js

> node --no-deprecation test/parallel/test-fs-chmod.js
33060
33060

> node --no-deprecation test/parallel/test-fs-chmod.js
33060
33060

> attrib test/fixtures/a1.js
A       I    fixtures/a1.js
/******************************************************************************/
> attrib +a -i test/fixtures/a1.js

> attrib test/fixtures/a1.js
A            fixtures/a1.js

> node --no-deprecation test/parallel/test-fs-chmod.js
33060
33060

> node --no-deprecation test/parallel/test-fs-chmod.js
33060
33060

> attrib test/fixtures/a1.js
A            fixtures/a1.js
/******************************************************************************/
> attrib -a +i test/fixtures/a1.js

> attrib test/fixtures/a1.js
        I    fixtures/a1.js

> node --no-deprecation test/parallel/test-fs-chmod.js
33060
33060

> node --no-deprecation test/parallel/test-fs-chmod.js
33060
33060

> attrib test/fixtures/a1.js
        I    fixtures/a1.js
/******************************************************************************/
> attrib -a -i test/fixtures/a1.js

> attrib test/fixtures/a1.js
             fixtures/a1.js

> node --no-deprecation test/parallel/test-fs-chmod.js
33060
33060

> node --no-deprecation test/parallel/test-fs-chmod.js
33060
assert.js:557
assert.ifError = function ifError(err) { if (err) throw err; };
                                                  ^

Error: EPERM: operation not permitted, open 'fixtures/a1.js'

> attrib test/fixtures/a1.js
     R       fixtures/a1.js
/******************************************************************************/

As you can see, in the last case the second test fails and the file mode is changed.

What is going on here?

test/parallel/test-fs-chmod.js changes the mode of fixtures/a.js with fs.chmod() and the mode of fixtures/a1.js with fs.fchmod() twice on Windows: to read-only and back to read-write. In case of fixtures/a.js and fs.chmod(), all is OK even with -a and -i attributes unset (I've checked this). But with fixtures/a1.js and fs.fchmod(), the beforementioned edge case prevents fs.fchmod() from the second change here: the fixtures/a1.js remains read-only after the first test run and fs.open() in append mode fails here on the second test run.

Why the test does not detect this?

This assertion before failed fs.fchmod() call and this assertion after the failed call check the same mode number in the failed case, but as long as this number is not falsy, the second assertion does not throw. On Windows, this number is not falsy in all the cases: it just differs in normal cases and remains the same in the edge case.

What possibly should be done?

  1. fs.fchmod() binding should be checked for this edge case. Maybe the bug should be reported upstream for libuv or even for Windows.
  2. The assertions in the test should be made stricter.

Unfortunately, I cannot be any more help in this case, as I am not good in this realm. Sorry.

Metadata

Metadata

Assignees

No one assigned

    Labels

    confirmed-bugIssues with confirmed bugs.fsIssues and PRs related to the fs subsystem / file system.libuvIssues and PRs related to the libuv dependency or the uv binding.regressionIssues related to regressions.testIssues and PRs related to the tests.windowsIssues and PRs related to the Windows platform.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions