Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows 10 test failures not reflected in CI #266

Open
BurtHarris opened this issue Jul 30, 2017 · 48 comments
Open

Windows 10 test failures not reflected in CI #266

BurtHarris opened this issue Jul 30, 2017 · 48 comments

Comments

@BurtHarris
Copy link
Contributor

BurtHarris commented Jul 30, 2017

PR #265 seems to have passed the Appveyor tests, but the tests aren't working in my normal Windows dev environment. This is because Appveyer is running with elevated privileges; I've learned its best not to enable elevated privileges as a developer. But without them, symlinks can't be created on NTFS volumes. NTFS junction points are the recommended alternative, which does not require admin permissions, but I'm not sure if they match up for your use-cases.

node: v6.11.1
npm: 3.10.10
Microsoft Windows [Version 10.0.15063]

> vinyl-fs@2.4.3 lint C:\try\vinyl-fs
> eslint . && jscs index.js lib/ test/


> vinyl-fs@2.4.3 test C:\try\vinyl-fs
> mocha --async-only

  .dest() with custom modes
    - sets the mode of a written buffer file if set on the vinyl object
    - sets the sticky bit on the mode of a written stream file if set on the vinyl object
    - sets the mode of a written stream file if set on the vinyl object
    - sets the mode of a written directory if set on the vinyl object
    - sets sticky bit on the mode of a written directory if set on the vinyl object
    - writes new files with the mode specified in options
    - updates the file mode to match the vinyl mode
    - updates the directory mode to match the vinyl mode
    - uses different modes for files and directories
    - does not fchmod a matching file
    - sees a file with special chmod (setuid/setgid/sticky) as distinct
    - reports fchmod errors

  .dest() with custom owner
    - calls fchown when the uid and/or gid are provided on the vinyl stat
    - does not call fchown when the uid and gid provided on the vinyl stat are invalid

  .dest() with symlinks
    1) creates symlinks when the `symlink` attribute is set on the file
    2) can create relative links
    - (*nix) creates a link for a directory
    √ (windows) creates a junction for a directory
    3) (windows) options can disable junctions for a directory
    4) (windows) options can disable junctions for a directory (as a function)
    - (*nix) can create relative links for directories
    √ (windows) relativeSymlinks option is ignored when junctions are used
    5) (windows) supports relativeSymlinks option when link is not for a directory
    6) (windows) can create relative links for directories when junctions are disabled
    7) does not overwrite links with overwrite option set to false
    8) overwrites links with overwrite option set to true
    9) does not overwrite links with overwrite option set to a function that returns false
    10) overwrites links with overwrite option set to a function that returns true

  .dest() with custom times
    - does not call futimes when no mtime is provided on the vinyl stat
    - calls futimes when an mtime is provided on the vinyl stat
    - does not call futimes when provided mtime on the vinyl stat is invalid
    - calls futimes when provided mtime on the vinyl stat is valid but provided atime is invalid
    - writes file atime and mtime using the vinyl stat

  .dest()
    - throws on invalid folder (empty)
    - throws on invalid folder (empty string)
    √ accepts the sourcemap option as true
    √ accepts the sourcemap option as a string
    √ inlines sourcemaps when option is true
    √ generates an extra File when option is a string
    √ passes through writes with cwd
    √ passes through writes with default cwd
    √ does not write null files
    √ writes buffer files to the right folder with relative cwd
    √ writes buffer files to the right folder with function and relative cwd
    √ writes buffer files to the right folder
    √ writes streaming files to the right folder
    √ writes large streaming files to the right folder
    √ writes directories to the right folder
    √ allows piping multiple dests in streaming mode
    √ writes new files with the default user mode
    √ reports i/o errors
    √ reports stat errors
    √ does not overwrite files with overwrite option set to false
    √ overwrites files with overwrite option set to true
    √ does not overwrite files with overwrite option set to a function that returns false
    √ overwrites files with overwrite option set to a function that returns true
    √ emits a finish event
    √ does not get clogged by highWaterMark (38ms)
    √ allows backpressure when piped to another, slower stream (6024ms)
    √ respects readable listeners on destination stream
    √ respects data listeners on destination stream
    √ sinks the stream if all the readable event handlers are removed (41ms)
    √ sinks the stream if all the data event handlers are removed
    √ successfully processes files with streaming contents
    √ errors if we cannot mkdirp
    √ errors if vinyl object is a directory and we cannot mkdirp
    √ does not error if vinyl object is a directory and we cannot open it
    √ errors if vinyl object is a directory and open errors
    √ errors if content stream errors
    √ does not pass options on to through2

  isOwner
    √ uses process.geteuid() when available
    √ uses process.getuid() when geteuid() is not available
    √ returns false when non-root and non-owner
    √ returns true when owner and non-root
    √ returns true when non-owner but root

  isValidUnixId
    √ returns true if the given id is a valid unix id
    √ returns false if the given id is not a number
    √ returns false when the given id is less than 0

  isFatalOverwriteError
    √ returns false if not given any error
    √ returns true if code != EEXIST
    √ returns false if code == EEXIST and flag == wx
    √ returns true if error.code == EEXIST and file.flag != wx

  isFatalUnlinkError
    √ returns false if not given any error
    √ returns false if code == ENOENT
    √ returns true if code != ENOENT

  getModeDiff
    √ returns 0 if both modes are the same
    √ returns 0 if vinyl mode is not a number
    √ returns a value greater than 0 if modes are different
    √ returns the proper diff
    √ does not matter the order of diffing
    √ includes the sticky/setuid/setgid bits

  getTimesDiff
    √ returns undefined if vinyl mtime is not a valid date
    √ returns undefined if vinyl mtime & atime are both equal to counterparts
    √ returns undefined if vinyl mtimes equals the counterpart and atimes are null
    √ returns a diff object if mtimes do not match
    √ returns a diff object if atimes do not match
    √ returns the fs atime if the vinyl atime is invalid
    √ makes atime diff undefined if fs and vinyl atime are invalid

  getOwnerDiff
    √ returns undefined if vinyl uid & gid are invalid
    √ returns undefined if vinyl uid & gid are both equal to counterparts
    √ returns a diff object if uid or gid do not match
    √ returns the fs uid if the vinyl uid is invalid
    √ returns the fs gid if the vinyl gid is invalid
    √ returns undefined if fs and vinyl uid are invalid
    √ returns undefined if fs and vinyl gid are invalid

  closeFd
    √ calls the callback with propagated error if fd is not a number
    √ calls the callback with close error if no error to propagate
    √ calls the callback with propagated error if close errors
    √ calls the callback with propagated error if close succeeds
    √ calls the callback with no error if close succeeds & no propagated error

  writeFile
    √ writes a file to the filesystem, does not close and returns the fd
    √ defaults to writing files with 0666 mode
    - accepts a different mode in options
    √ defaults to opening files with write flag
    √ accepts a different flag in options
    √ appends to a file if append flag is given
    √ does not pass a file descriptor if open call errors
    √ passes a file descriptor if write call errors
    √ passes an error if called with string as data
    √ does not error on SlowBuffer
    √ does not error if options is falsey

  updateMetadata
    - passes the error if fstat fails
    - updates the vinyl object with fs stats
    - does not touch the fs if nothing to update
    - does not touch the fs if process is not owner of the file
    - updates times on fs and vinyl object if there is a diff
    - forwards futimes error and descriptor upon error
    - updates the mode on fs and vinyl object if there is a diff
    - updates the sticky bit on mode on fs and vinyl object if there is a diff
    - forwards fchmod error and descriptor upon error
    - updates the mode & times on fs and vinyl object if there is a diff
    - forwards fchmod error and descriptor through futimes if there is a time diff

  createWriteStream
    √ accepts just a file path and writes to it
    √ accepts just a file path and writes a large file to it
    √ accepts flag option
    √ accepts append flag as option & places cursor at the end
Changing the mode of a file is not supported by node.js in Windows.
    - accepts mode option
    √ uses default file mode if no mode options
    √ accepts a flush function that is called before close emitted
    √ can specify flush without options argument
    √ passes the file descriptor to flush
    √ passes a callback to flush to call when work is done (252ms)
    √ emits an error if open fails
    √ emits an error if write fails

  integrations
    √ does not exhaust available file descriptors when streaming thousands of files (16916ms)

  .dest() on not owned files
    √ does not error if mtime is different
    √ does not error if mode is different

  .src() with symlinks
    11) "before each" hook for "resolves symlinks correctly"

  .src()
    √ throws on invalid glob (empty)
    √ throws on invalid glob (empty string)
    √ throws on invalid glob (number)
    √ throws on invalid glob (nested array)
    √ throws on invalid glob (empty string in array)
    √ throws on invalid glob (empty array)
    √ emits an error on file not existing
    √ passes through writes
    √ strips BOM from utf8-encoded files by default
    √ does not strip BOM from utf8-encoded files if option is false
    √ does not strip anything that looks like a utf8-encoded BOM from utf16be-encoded files
    √ does not strip anything that looks like a utf8-encoded BOM from utf16be-encoded files with streaming contents
    √ does not strip anything that looks like a utf8-encoded BOM from utf16le-encoded files
    √ does not strip anything that looks like a utf8-encoded BOM from utf16le-encoded files with streaming contents
    √ globs files with default settings
    √ globs files with default settings and relative cwd
    √ globs a directory with default settings
    √ globs a directory with default settings and relative cwd
    √ streams a directory with default settings
    √ streams file with with no contents using read: false option
    √ streams a file changed after since
    √ does not stream a file changed before since
    √ streams a file with streaming contents
    √ can be used as a through stream and adds new files to the end
    √ can be used at beginning and in the middle
    √ does not pass options on to through2

  symlink stream
    - throws on invalid folder
    12) passes through writes with cwd
    13) passes through writes with default cwd
    14) creates a link to the right folder with relative cwd
    15) creates a link to the right folder with function and relative cwd
    16) creates a link for a file with buffered contents
    17) can create relative links
    18) creates a link for a file with streaming contents
    - (*nix) creates a link for a directory
    √ (windows) creates a junction for a directory
    19) (windows) options can disable junctions for a directory
    20) (windows) options can disable junctions for a directory (as a function)
    - (*nix) can create relative links for directories
    √ (windows) relativeSymlinks option is ignored when junctions are used
    21) (windows) supports relativeSymlinks option when link is not for a directory
    22) (windows) can create relative links for directories when junctions are disabled
    - uses different modes for files and directories
    - reports IO errors
    23) does not overwrite links with overwrite option set to false
    24) overwrites links with overwrite option set to true
    25) does not overwrite links with overwrite option set to a function that returns false
    26) overwrites links with overwrite option set to a function that returns true
    √ emits an end event
    27) emits a finish event
    28) does not get clogged by highWaterMark
    29) allows backpressure when piped to another, slower stream
    30) respects readable listeners on symlink stream
    31) respects data listeners on symlink stream
    32) sinks the stream if all the readable event handlers are removed
    33) sinks the stream if all the data event handlers are removed
    34) does not pass options on to through2


  130 passing (29s)
  41 pending
  34 failing

  1) .dest() with symlinks creates symlinks when the `symlink` attribute is set on the file:
     Uncaught Error: ENOENT: no such file or directory, readlink 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)
      at Object.fs.readlinkSync (fs.js:1028:18)
      at assert (C:\try\vinyl-fs\test\dest-symlinks.js:47:24)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  2) .dest() with symlinks can create relative links:
     Uncaught Error: ENOENT: no such file or directory, readlink 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)
      at Object.fs.readlinkSync (fs.js:1028:18)
      at assert (C:\try\vinyl-fs\test\dest-symlinks.js:73:27)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  3) .dest() with symlinks (windows) options can disable junctions for a directory:
     Uncaught Error: ENOENT: no such file or directory, stat 'C:\try\vinyl-fs\test\out-fixtures\foo'
      at Error (native)
      at Object.fs.statSync (fs.js:1000:11)
      at Object.statSync (C:\try\vinyl-fs\node_modules\graceful-fs\polyfills.js:297:22)
      at assert (C:\try\vinyl-fs\test\dest-symlinks.js:178:22)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  4) .dest() with symlinks (windows) options can disable junctions for a directory (as a function):
     Uncaught Error: ENOENT: no such file or directory, stat 'C:\try\vinyl-fs\test\out-fixtures\foo'
      at Error (native)
      at Object.fs.statSync (fs.js:1000:11)
      at Object.statSync (C:\try\vinyl-fs\node_modules\graceful-fs\polyfills.js:297:22)
      at assert (C:\try\vinyl-fs\test\dest-symlinks.js:220:22)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  5) .dest() with symlinks (windows) supports relativeSymlinks option when link is not for a directory:
     Uncaught Error: ENOENT: no such file or directory, readlink 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)
      at Object.fs.readlinkSync (fs.js:1028:18)
      at assert (C:\try\vinyl-fs\test\dest-symlinks.js:326:27)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  6) .dest() with symlinks (windows) can create relative links for directories when junctions are disabled:
     Uncaught Error: ENOENT: no such file or directory, stat 'C:\try\vinyl-fs\test\out-fixtures\foo'
      at Error (native)
      at Object.fs.statSync (fs.js:1000:11)
      at Object.statSync (C:\try\vinyl-fs\node_modules\graceful-fs\polyfills.js:297:22)
      at assert (C:\try\vinyl-fs\test\dest-symlinks.js:359:22)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  7) .dest() with symlinks does not overwrite links with overwrite option set to false:

      Uncaught Error: Expected 0 to equal 1
      + expected - actual

      -0
      +1

      at assert (C:\try\vinyl-fs\node_modules\expect\lib\assert.js:29:9)
      at Expectation.toEqual (C:\try\vinyl-fs\node_modules\expect\lib\Expectation.js:81:30)
      at assert (C:\try\vinyl-fs\test\dest-symlinks.js:394:28)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  8) .dest() with symlinks overwrites links with overwrite option set to true:
     Uncaught Error: ENOENT: no such file or directory, open 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)
      at Object.fs.openSync (fs.js:641:18)
      at Object.fs.readFileSync (fs.js:509:33)
      at assert (C:\try\vinyl-fs\test\dest-symlinks.js:423:31)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  9) .dest() with symlinks does not overwrite links with overwrite option set to a function that returns false:

      Uncaught Error: Expected 0 to equal 1
      + expected - actual

      -0
      +1

      at assert (C:\try\vinyl-fs\node_modules\expect\lib\assert.js:29:9)
      at Expectation.toEqual (C:\try\vinyl-fs\node_modules\expect\lib\Expectation.js:81:30)
      at assert (C:\try\vinyl-fs\test\dest-symlinks.js:460:28)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  10) .dest() with symlinks overwrites links with overwrite option set to a function that returns true:
     Uncaught Error: ENOENT: no such file or directory, open 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)
      at Object.fs.openSync (fs.js:641:18)
      at Object.fs.readFileSync (fs.js:509:33)
      at assert (C:\try\vinyl-fs\test\dest-symlinks.js:493:31)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  11) .src() with symlinks "before each" hook for "resolves symlinks correctly":
     Error: EPERM: operation not permitted, symlink 'C:\try\vinyl-fs\test\fixtures\foo' -> 'C:\try\vinyl-fs\test\out-fixtures\test-symlink-dir'
      at Error (native)
      at Object.fs.symlinkSync (fs.js:1068:18)
      at Context.<anonymous> (C:\try\vinyl-fs\test\src-symlinks.js:37:8)
      at callFnAsync (C:\try\vinyl-fs\node_modules\mocha\lib\runnable.js:349:8)
      at Hook.Runnable.run (C:\try\vinyl-fs\node_modules\mocha\lib\runnable.js:301:7)
      at next (C:\try\vinyl-fs\node_modules\mocha\lib\runner.js:298:10)
      at C:\try\vinyl-fs\node_modules\mocha\lib\runner.js:315:7
      at done (C:\try\vinyl-fs\node_modules\mocha\lib\runnable.js:287:5)
      at C:\try\vinyl-fs\node_modules\mocha\lib\runnable.js:360:7
      at next (C:\try\vinyl-fs\node_modules\rimraf\rimraf.js:74:7)
      at CB (C:\try\vinyl-fs\node_modules\rimraf\rimraf.js:110:9)
      at C:\try\vinyl-fs\node_modules\rimraf\rimraf.js:136:14
      at FSReqWrap.oncomplete (fs.js:123:15)

  12) symlink stream passes through writes with cwd:

      Uncaught Error: Expected 0 to equal 1
      + expected - actual

      -0
      +1

      at assert (C:\try\vinyl-fs\node_modules\expect\lib\assert.js:29:9)
      at Expectation.toEqual (C:\try\vinyl-fs\node_modules\expect\lib\Expectation.js:81:30)
      at assert (C:\try\vinyl-fs\test\symlink.js:65:28)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  13) symlink stream passes through writes with default cwd:

      Uncaught Error: Expected 0 to equal 1
      + expected - actual

      -0
      +1

      at assert (C:\try\vinyl-fs\node_modules\expect\lib\assert.js:29:9)
      at Expectation.toEqual (C:\try\vinyl-fs\node_modules\expect\lib\Expectation.js:81:30)
      at assert (C:\try\vinyl-fs\test\symlink.js:85:28)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  14) symlink stream creates a link to the right folder with relative cwd:
     Uncaught Error: ENOENT: no such file or directory, readlink 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)
      at Object.fs.readlinkSync (fs.js:1028:18)
      at assert (C:\try\vinyl-fs\test\symlink.js:107:27)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  15) symlink stream creates a link to the right folder with function and relative cwd:
     Uncaught Error: ENOENT: no such file or directory, readlink 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)
      at Object.fs.readlinkSync (fs.js:1028:18)
      at assert (C:\try\vinyl-fs\test\symlink.js:140:27)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  16) symlink stream creates a link for a file with buffered contents:
     Uncaught Error: ENOENT: no such file or directory, readlink 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)
      at Object.fs.readlinkSync (fs.js:1028:18)
      at assert (C:\try\vinyl-fs\test\symlink.js:166:27)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  17) symlink stream can create relative links:
     Uncaught Error: ENOENT: no such file or directory, readlink 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)
      at Object.fs.readlinkSync (fs.js:1028:18)
      at assert (C:\try\vinyl-fs\test\symlink.js:191:27)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  18) symlink stream creates a link for a file with streaming contents:
     Uncaught Error: ENOENT: no such file or directory, readlink 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)
      at Object.fs.readlinkSync (fs.js:1028:18)
      at assert (C:\try\vinyl-fs\test\symlink.js:216:27)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  19) symlink stream (windows) options can disable junctions for a directory:
     Uncaught Error: ENOENT: no such file or directory, stat 'C:\try\vinyl-fs\test\out-fixtures\foo'
      at Error (native)
      at Object.fs.statSync (fs.js:1000:11)
      at Object.statSync (C:\try\vinyl-fs\node_modules\graceful-fs\polyfills.js:297:22)
      at assert (C:\try\vinyl-fs\test\symlink.js:324:22)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  20) symlink stream (windows) options can disable junctions for a directory (as a function):
     Uncaught Error: ENOENT: no such file or directory, stat 'C:\try\vinyl-fs\test\out-fixtures\foo'
      at Error (native)
      at Object.fs.statSync (fs.js:1000:11)
      at Object.statSync (C:\try\vinyl-fs\node_modules\graceful-fs\polyfills.js:297:22)
      at assert (C:\try\vinyl-fs\test\symlink.js:367:22)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  21) symlink stream (windows) supports relativeSymlinks option when link is not for a directory:
     Uncaught Error: ENOENT: no such file or directory, readlink 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)
      at Object.fs.readlinkSync (fs.js:1028:18)
      at assert (C:\try\vinyl-fs\test\symlink.js:476:27)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  22) symlink stream (windows) can create relative links for directories when junctions are disabled:
     Uncaught Error: ENOENT: no such file or directory, stat 'C:\try\vinyl-fs\test\out-fixtures\foo'
      at Error (native)
      at Object.fs.statSync (fs.js:1000:11)
      at Object.statSync (C:\try\vinyl-fs\node_modules\graceful-fs\polyfills.js:297:22)
      at assert (C:\try\vinyl-fs\test\symlink.js:509:22)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  23) symlink stream does not overwrite links with overwrite option set to false:

      Uncaught Error: Expected 0 to equal 1
      + expected - actual

      -0
      +1

      at assert (C:\try\vinyl-fs\node_modules\expect\lib\assert.js:29:9)
      at Expectation.toEqual (C:\try\vinyl-fs\node_modules\expect\lib\Expectation.js:81:30)
      at assert (C:\try\vinyl-fs\test\symlink.js:599:28)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  24) symlink stream overwrites links with overwrite option set to true:
     Uncaught Error: ENOENT: no such file or directory, open 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)
      at Object.fs.openSync (fs.js:641:18)
      at Object.fs.readFileSync (fs.js:509:33)
      at assert (C:\try\vinyl-fs\test\symlink.js:624:31)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  25) symlink stream does not overwrite links with overwrite option set to a function that returns false:

      Uncaught Error: Expected 0 to equal 1
      + expected - actual

      -0
      +1

      at assert (C:\try\vinyl-fs\node_modules\expect\lib\assert.js:29:9)
      at Expectation.toEqual (C:\try\vinyl-fs\node_modules\expect\lib\Expectation.js:81:30)
      at assert (C:\try\vinyl-fs\test\symlink.js:658:28)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  26) symlink stream overwrites links with overwrite option set to a function that returns true:
     Uncaught Error: ENOENT: no such file or directory, open 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)
      at Object.fs.openSync (fs.js:641:18)
      at Object.fs.readFileSync (fs.js:509:33)
      at assert (C:\try\vinyl-fs\test\symlink.js:688:31)
      at ConcatStream.<anonymous> (C:\try\vinyl-fs\node_modules\concat-stream\index.js:36:43)
      at finishMaybe (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:607:14)
      at endWritable (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:615:3)
      at ConcatStream.Writable.end (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:571:41)
      at ConcatStream.Writable._destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\_stream_writable.js:662:8)
      at ConcatStream.destroy (C:\try\vinyl-fs\node_modules\readable-stream\lib\internal\streams\destroy.js:36:8)
      at C:\try\vinyl-fs\node_modules\pump\index.js:43:45
      at call (C:\try\vinyl-fs\node_modules\pump\index.js:50:3)
      at Array.forEach (native)
      at C:\try\vinyl-fs\node_modules\pump\index.js:70:25
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  27) symlink stream emits a finish event:
     Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.
      at Timeout.<anonymous> (C:\try\vinyl-fs\node_modules\mocha\lib\runnable.js:226:19)

  28) symlink stream does not get clogged by highWaterMark:
     Error: EPERM: operation not permitted, symlink 'C:\try\vinyl-fs\test\fixtures\test.txt' -> 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)

  29) symlink stream allows backpressure when piped to another, slower stream:
     Error: EPERM: operation not permitted, symlink 'C:\try\vinyl-fs\test\fixtures\test.txt' -> 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)

  30) symlink stream respects readable listeners on symlink stream:

      Uncaught Error: Expected 0 to equal 1
      + expected - actual

      -0
      +1

      at assert (C:\try\vinyl-fs\node_modules\expect\lib\assert.js:29:9)
      at Expectation.toEqual (C:\try\vinyl-fs\node_modules\expect\lib\Expectation.js:81:30)
      at assert (C:\try\vinyl-fs\test\symlink.js:801:25)
      at C:\try\vinyl-fs\node_modules\pump\index.js:73:7
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  31) symlink stream respects data listeners on symlink stream:

      Uncaught Error: Expected 0 to equal 1
      + expected - actual

      -0
      +1

      at assert (C:\try\vinyl-fs\node_modules\expect\lib\assert.js:29:9)
      at Expectation.toEqual (C:\try\vinyl-fs\node_modules\expect\lib\Expectation.js:81:30)
      at assert (C:\try\vinyl-fs\test\symlink.js:826:21)
      at C:\try\vinyl-fs\node_modules\pump\index.js:73:7
      at f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.<anonymous> (C:\try\vinyl-fs\node_modules\pump\index.js:29:21)
      at Pumpify.f (C:\try\vinyl-fs\node_modules\once\once.js:25:25)
      at Pumpify.Duplexify._destroy (C:\try\vinyl-fs\node_modules\duplexify\index.js:184:15)
      at C:\try\vinyl-fs\node_modules\duplexify\index.js:175:10
      at _combinedTickCallback (internal/process/next_tick.js:73:7)
      at process._tickCallback (internal/process/next_tick.js:104:9)

  32) symlink stream sinks the stream if all the readable event handlers are removed:
     Error: EPERM: operation not permitted, symlink 'C:\try\vinyl-fs\test\fixtures\test.txt' -> 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)

  33) symlink stream sinks the stream if all the data event handlers are removed:
     Error: EPERM: operation not permitted, symlink 'C:\try\vinyl-fs\test\fixtures\test.txt' -> 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)

  34) symlink stream does not pass options on to through2:
     Error: EPERM: operation not permitted, symlink 'C:\try\vinyl-fs\test\fixtures\test.txt' -> 'C:\try\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)

npm ERR! Test failed.  See above for more details.
@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 1, 2017

note: I've updated the text above to reflect errors on the gitignore branch to eliminate those having to do with line endings.

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 1, 2017

Now running the tests with elevated permissions gets 100% pass rate. That suggests to me that it's all due to attmpts to create symlinks, rather than NTFS junction points, when running on Windows. Updated problem statement above to reflect this.

@erikkemperman
Copy link
Member

@BurtHarris Having ditched Windows a looong time ago (win98 was the last I've used) I am pretty far from being an expert here -- but a cursory search indicates that this might be due to an OS restriction and there might not be much we can do about it.

We've switched to using junctions instead of links for directories, which for some insane reason don't require elevated privileges, but no such escape is apparently available for links to regular files.

Some pages that seem relevant:

What does and doesn't work with symlinky things on Windows:
https://github.com/iarna/win-symlink-test#readme

Possible workaround by changing user/group settings:
nodejs/node-v0.x-archive#6342

Or, adapt your use case to work with links to directories instead of files, if that's even possible.

Having said all this, it does appear that the tests on Appveyor runs with elevated privileges or in an otherwise permissive environment. That the tests fail in a default Windows setup, presuming that's what you're trying, is something that ought to be addressed IMHO. Perhaps simply by skipping those on Windows.

Please understand, though, that the contributors to the gulp ecosystem, as far as I know, hardly work on this OS, so that's how things like this can slip through unfortunately...

So if you have suggestions, or would be willing to do a bit more figuring out, that'd be much appreciated!

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 2, 2017

@erikkemperman I retired after 17 years as a dev at Microsoft. I'm happy to try to fill in contributor ecosystem gap you mentioned. Feel free to assign these issues to me, I apparently can't self-assign them at this point.

I have very little *NIX / open source experience, so it will take a little experimenting for me to put together a PR you'll like. Sorry if that's been unclear, I'm looking for a an opportunity to contribute, is my protocol of reporting the issue before submitting a PR somehow off?

I think that the test code still has some cases where symbolic links could be replaced with junction points. For example, https://github.com/gulpjs/vinyl-fs/blob/master/test/src-symlinks.js#L37. If you can confirm I'm on the right track, I'd be happy to PR a fix.

I actually think the lack of 1:1 compatibility between symlinks and junction points was intentional.
If I remember correctly, the admittedly decisions were made because of some risk risk(s) associated with symlink that the Windows group didn't want to expose casual users to. Junction points were somehow judged safer, and thus OK to expose to end users.

The practice of developers running with elevated privileges is one some of use at Microsoft have tried hard to change. See for example my friend Aaron's blog: https://blogs.msdn.microsoft.com/aaron_margosis/

@phated
Copy link
Member

phated commented Aug 2, 2017

If I'm not mistaken, we have tests that specifically test that links can be created on Windows when permissions are elevated. Those tests should probably have a check to make sure permissions are elevated and skip otherwise. @BurtHarris Is there a way to check for elevated Windows permissions in node (since we can't access getuid)?

@BurtHarris
Copy link
Contributor Author

@phated I've not used it before but https://github.com/coreybutler/node-windows looks to be a well-designed windows support package for Node.js. The isAdminUser function does what you asked, but there are also functions to request elevation for execution of a specific command, much like sudo (a cleaner approach than assuming it.)

What would you think of a solution using that package?

@phated
Copy link
Member

phated commented Aug 2, 2017

I'd prefer not using another package for this. It looks like we need to exec NET SESSION on Windows to find out if there are elevated privileges. Thoughts?

@BurtHarris
Copy link
Contributor Author

We could do that, just used "NET SESSION" because it's a built-in command and will fail without elevated permissions. I was suggesting the package more for the elevate function, but understand your reluctance to add a dependency.

But what I'd rather do is instead of skipping the tests, adapt them so they can run on Windows without elevation. I'm trying a few experiments now.

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 2, 2017

Clarifying above with a few references:

  • Windows junctions behave more like hardlinks than symlinks. ref One of this restrictions this imposes is that nested or multi-level redirection using junctions does not work. While you can create a junction that points to another junction, but they fail to resolve recursively the way symlinks would. I believe this was by design.

  • On Windows, symlinks are considered to be a risk because their inadvertent or intentional misuse can lead to unexpected security vulnerabilities, particularly as some software (that might be run elevated) cannot or does not try to understand the behavior of symlinks. ref

It seems like vinyl-fs has made a choice to treat junctions as a symlink emulator, by making options.useJunctions default to true on Windows. I understand the reason for this, its probably a good idea, but junctions were not designed to be a symlink emulator.

The differences between junctions and symlinks may not be a problem for some common uses use of symlinks, but some of the tests, like the one shown below, are implicitly testing the nested or mult-level redirect; substituting a junction for symlink fails this test.

Perhaps what makes sense is separating the symlink tests into a "basic" set, which exercise and test behavior that junctions can emulate, and an advanced set that actually depend on symlink specific privildges. Has this already been done? Are there tests which are designed to cover the of the options.useJunctions feature? If so, then simply skipping the symlink advanced tests if the user does not have admin permissions makes sense.

It is simple to update tests to create junctions, but some "symlink" tests still fail because they are testing behavior that is depending on nested/mult-level behavior that junctions can't emulate (by design.) For example, in src-symlinks.js, the use of symlinkNestedFirst causes it to fail.

it('resolves symlinks correctly', function(done) {
    function assert(files) {
      expect(files.length).toEqual(1);
      // The path should be the symlink itself
      expect(files[0].path).toEqual(symlinkNestedFirst);
      // But the content should be what's in the actual file
      expect(files[0].contents.toString()).toEqual('symlink works\n');
      // And the stats should have been updated
      expect(files[0].stat.isSymbolicLink()).toEqual(false);
      expect(files[0].stat.isFile()).toEqual(true);
    }

I was initially confused by this failure because the description didn't imply use of nested links.

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 2, 2017

P.S. A unit-testing purist point-of-view might be that depending on behavior like resolving nested links goes above and beyond testing vinyl-fs itself. Its testing the behavior of an OS component external to Node.js, which contributes to brittleness in the form of tests aborting for reasons unrelated to the code in the package.

@phated
Copy link
Member

phated commented Aug 2, 2017

@BurtHarris if those tests are running on Windows, why do they pass on Appveyor?

@BurtHarris
Copy link
Contributor Author

P.S. Thinking of junctions like hardlinks may help explain some other restrictions and understand how to work around them. For example, while you are right that you can't create a file junction, only a directory junction, it is possible to create a file hardlink under windows, and that doesn't require elevated permissions either.

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 2, 2017

@phated the tests pass on Appveyor because the account they are running under has elevated permissions. It's like running as root. ref: http://help.appveyor.com/discussions/questions/1888-running-tests-with-reduced-privileges

@phated
Copy link
Member

phated commented Aug 2, 2017

@BurtHarris I think there's a disconnect here. tests/src-symlinks.js tests only read from symlinks. The thing that would actually causing problems would be the beforeEach block that uses node's fs.symlinkSync method. This is where we would need to check for elevated permissions and skip if not available.

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 3, 2017

Disconnect? Not sure about that, but I agree with you on this part: its not the actual production or test code that's causing an exception in src-symlinks, it's the fixture setup. But since (without root-like permission) beforeEach aborts, none of the actual tests in that module are attempted when running non-admin. That's, quite discouraging, people get worn by stuff like this; I know I'm feeling worn out. Perhaps that's why the gulp contributor community lacks any Windows devs.

Later...

@erikkemperman
Copy link
Member

Sorry you feel that way, I think we've been trying to be supportive here and to accommodate or failing that to take time to try and explain why things are the way they are. You've added some valuable ideas (like we should probably test the case with nested junctions) but keep in mind this is an effort of volunteers doing this in their spare time...

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 3, 2017

Erik, thanks. I appreciate your feedback too, however @phated's tendency to close issues/PRs rather than try to work out some compromise is what's so off-putting.

Another example, I've just wasted most of this morning trying to debug a fix for some of the above errors. I count my time wasted because it finally turned out the bug was in the outdated version of Mocha this project has devDependency on. Do I want to even ask if your open to upgrading Mocha?

This is recurrent: I think that's the third time that stale tool dependencies have wasted my "spare" time. It may be harsh, but I'll refer again to Martin Fowler definition:

a code smell is a surface indication that usually corresponds to a deeper problem in the system

The good news, is the problem is NOT in gulp's actual production code. I'm really glad because I plan on continuing to use gulp. The bad news is that the gulp project governance regarding devDependencies is pushing volunteers like me away.

@phated
Copy link
Member

phated commented Aug 3, 2017

Mocha supports node 0.10. If you plan to update it here, please go through our ~30 other modules and update them too. Much appreciated ❤️

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 3, 2017

I'll consider it. Have you considered a using a monorepo so that such a task isn't so big and distributed?

@phated
Copy link
Member

phated commented Aug 3, 2017

Yes, I've considered it but monorepos are an anti-pattern that has caught on because 1 person/company decided to build some tooling around them. Multi-repo projects just need a champion to build tooling around them in the same fashion.

@BurtHarris
Copy link
Contributor Author

Good luck with that too.

@erikkemperman
Copy link
Member

You mean the babel/lerna guys I guess? I would love to see some utilities for dealing with related multi-repo projects but would imagine it to be that much more complicated...

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 3, 2017

Yarn is in the process of added an interesting feature called "workspaces" that took some good ideas from Lerna, but incorporate them at the package manager level. I'll find the reference in a few minutes...

@BurtHarris
Copy link
Contributor Author

@BurtHarris
Copy link
Contributor Author

Of course that's still effectively a monorepo tool, not multi-repo, but Lerna is by no means alone.

@phated
Copy link
Member

phated commented Aug 3, 2017

yarn and lerna are (basically) both facebook's... Pointing to yarn doesn't strengthen any case for proper node devs (maybe it works with frontend devs?)

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 3, 2017

Back to vinyl-fs...

If vfs.symlink is called without opt.useJunctions, on Windows and without the needed privileges, should an exception get raised (or whatever the pipe-friendly equivlanent is?)

I'm thinking the answer should be yes...

@erikkemperman
Copy link
Member

Huh, interesting. I quite like yarn.

I guess I'm just a bit less concerned about where tools come from, so long as they work well, the license is ok (so not the +patents trojan FB have shackled react with) and the community is active and friendly.

Eg, I dislike MS as much as the next guy (I'm old enough to remember the Halloween memos) but I think typescript is actually pretty cool.

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 3, 2017

I'm obviously biased, but Facebook scares me much more than Microsoft. None the less, Yarn has my keen interest, the npm client is having some real stability problems.

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 3, 2017

I'm debugging it('passes through writes with cwd'... it fails at https://github.com/gulpjs/vinyl-fs/blob/master/test/symlink.js#L65 because the assert callback is called with zero files on Windows without elevated permissions..

I think this is related to the fact that the docs on misssippi.concat() say:

Note that miss.concat will not handle stream errors for you. To handle errors, use miss.pipe or handle the error event manually.

It seems like it would be better for the test to report the actual error from the symlink operation rather than complaining about files.length. Would it make sense to change assert to something like this:

   function assert(files) {
      if (files.length > 0) {
        expect(files).toInclude(file);
        expect(files[0].cwd).toEqual(__dirname, 'cwd should have changed');
      }
    }

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 3, 2017

That way the failure is a cleaner message indicating the reason:

  3) symlink stream passes through writes with cwd:
     Error: EPERM: operation not permitted, symlink 'C:\code\vinyl-fs\test\fixtures\test.txt' -> 'C:\code\vinyl-fs\test\out-fixtures\test.txt'
      at Error (native)

P.S. I'm being methodical, trying to get the test to report well before I fix the problem.

@phated
Copy link
Member

phated commented Aug 3, 2017

@BurtHarris that's super weird, I thought the outer-wrapping pipe would be catching an emitted error from the stream (as they are suggesting in your quoted docs).

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 3, 2017

It sort of does, but assert runs first and that's the error that gets reported.

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 3, 2017

There are a lot of places like this, perhaps we need a replacement function for mississippi.concat. I wouldn't want it to invoke the callback in case of an error.

@phated
Copy link
Member

phated commented Aug 3, 2017

Yep, likely. I didn't expect it to work that way. The stream should be torn down before concat gets called. We will probably need to make a custom implementation.

@BurtHarris
Copy link
Contributor Author

I'd be happy to give that a shot. Where should it go?

@phated
Copy link
Member

phated commented Aug 3, 2017

Stream utilities used for testing go in https://github.com/gulpjs/vinyl-fs/blob/master/test/utils/test-streams.js - Thanks for pointing this out. I'm currently looking into elevated permissions in AppVeyor (and if we can add non-elevated to the test matrix)

@BurtHarris
Copy link
Contributor Author

Good idea. There was a earlier note suggesting they didn't support it (http://help.appveyor.com/discussions/questions/1888-running-tests-with-reduced-privileges) but maybe that's changed.

@BurtHarris
Copy link
Contributor Author

Mini code review please:

/*
 * Creates a transform stream which concatenates objects from an object stream into an array.
 * At end-of-stream, optional callback is invoked with array of collected objects.
 * Array is also passed on to next object in pipeline, if any.
 */
function concat( cb ) {
  var array = [];

  var transform = through.obj( function( file, enc, done ) {
    array.push(file);
    done(null, file);
  }, function(done) { // Flush
    cb && cb(array);
    this.push(array);
    done();
  });

  return transform;
}

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 4, 2017

The above seems to be working well, but I've noticed that I'm getting a timeout on symlink stream emits a finish event, I think it's new, and when I run it under debugger the timeout is a pain 'cause I generally turn off timeouts with the debugger.

@phated
Copy link
Member

phated commented Aug 4, 2017

It's probably related because a "through" stream doesn't finish. Try using flush-write-stream which is exposed as to in mississippi (I believe).

@BurtHarris
Copy link
Contributor Author

Thanks, that's a big help.

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 4, 2017

@phated I see your efforts on the appveyor-restrict branch. psexec may be a workable approach, but I'm sure working it out without an interactive windows box at your disposal is a pain. Much easier to work it out interactively on a windows dev box; I'll take care of it if you want.

@phated
Copy link
Member

phated commented Aug 4, 2017

@BurtHarris thanks. I eventually got the psexec stuff running but limited permissions is actually lower than a standard user so I am getting errors on mkdir when it shouldn't. I don't know if this can actually be solved in CI.

@BurtHarris
Copy link
Contributor Author

Understood. I've hit those same problems w/ mkdir too. I'm sure I'll be able to come up with something, I've got a number of contacts who understand Windows security features better than I do.

@BurtHarris
Copy link
Contributor Author

BurtHarris commented Aug 6, 2017

@phated, I've got a prototype to run with limited privileges using PowerShell Jobs. I'll clean it up a bit and submit another PR. The reason that psexec didn't work easily is it's -l option actually marks the process to be low-trust, which would require changing the mandatory ACLs, not just the discretionary ACLs. I don't think low-trust processes are the primary use case, so PowerShell Jobs seems like a more direct rout.

@phated
Copy link
Member

phated commented Aug 19, 2017

@BurtHarris where do we stand on the above? It seems you can actually specify a test script to run in powershell using the ps: prefix.

@BurtHarris
Copy link
Contributor Author

Hi @phated .

I've been busy elsewhere, but should be able to look at this again this week.

By the way, I ran into an interesting blogpost about a change in Windows symlink support: https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10. It appears that for developers only recent builds of Windows 10 can avoid needing elevation to create symlinks! That's potentially big. What do you think?

@phated phated added this to Nice to Have in v5 Oct 21, 2020
@phated phated changed the title Windows 10 test failures not reflected in Appveyor CI Windows 10 test failures not reflected in CI Jun 11, 2023
@phated phated removed this from Nice to Have in v5 Jun 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

No branches or pull requests

3 participants