11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ciconst common = require('../common');
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ciif (common.isWindows) {
51cb0ef41Sopenharmony_ci  // https://github.com/nodejs/node/issues/48300
61cb0ef41Sopenharmony_ci  common.skip('Does not work with cygwin quirks on Windows');
71cb0ef41Sopenharmony_ci}
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ciconst assert = require('assert');
101cb0ef41Sopenharmony_ciconst path = require('path');
111cb0ef41Sopenharmony_ciconst fs = require('fs');
121cb0ef41Sopenharmony_ciconst spawn = require('child_process').spawn;
131cb0ef41Sopenharmony_ciconst tmpdir = require('../common/tmpdir');
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_cilet cat, grep, wc;
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ciconst KB = 1024;
181cb0ef41Sopenharmony_ciconst MB = KB * KB;
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ci// Make sure process chaining allows desired data flow:
221cb0ef41Sopenharmony_ci// check cat <file> | grep 'x' | wc -c === 1MB
231cb0ef41Sopenharmony_ci// This helps to make sure no data is lost between pipes.
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci{
261cb0ef41Sopenharmony_ci  tmpdir.refresh();
271cb0ef41Sopenharmony_ci  const file = path.resolve(tmpdir.path, 'data.txt');
281cb0ef41Sopenharmony_ci  const buf = Buffer.alloc(MB).fill('x');
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci  // Most OS commands that deal with data, attach special meanings to new line -
311cb0ef41Sopenharmony_ci  // for example, line buffering. So cut the buffer into lines at some points,
321cb0ef41Sopenharmony_ci  // forcing data flow to be split in the stream. Do not use os.EOL for \n as
331cb0ef41Sopenharmony_ci  // that is 2 characters on Windows and is sometimes converted to 1 character
341cb0ef41Sopenharmony_ci  // which causes the test to fail.
351cb0ef41Sopenharmony_ci  for (let i = 1; i < KB; i++)
361cb0ef41Sopenharmony_ci    buf.write('\n', i * KB);
371cb0ef41Sopenharmony_ci  fs.writeFileSync(file, buf.toString());
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci  cat = spawn('cat', [file]);
401cb0ef41Sopenharmony_ci  grep = spawn('grep', ['x'], { stdio: [cat.stdout, 'pipe', 'pipe'] });
411cb0ef41Sopenharmony_ci  wc = spawn('wc', ['-c'], { stdio: [grep.stdout, 'pipe', 'pipe'] });
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci  // Extra checks: We never try to start reading data ourselves.
441cb0ef41Sopenharmony_ci  cat.stdout._handle.readStart = common.mustNotCall();
451cb0ef41Sopenharmony_ci  grep.stdout._handle.readStart = common.mustNotCall();
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci  // Keep an array of error codes and assert on them during process exit. This
481cb0ef41Sopenharmony_ci  // is because stdio can still be open when a child process exits, and we don't
491cb0ef41Sopenharmony_ci  // want to lose information about what caused the error.
501cb0ef41Sopenharmony_ci  const errors = [];
511cb0ef41Sopenharmony_ci  process.on('exit', () => {
521cb0ef41Sopenharmony_ci    assert.deepStrictEqual(errors, []);
531cb0ef41Sopenharmony_ci  });
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci  [cat, grep, wc].forEach((child, index) => {
561cb0ef41Sopenharmony_ci    const errorHandler = (thing, type) => {
571cb0ef41Sopenharmony_ci      // Don't want to assert here, as we might miss error code info.
581cb0ef41Sopenharmony_ci      console.error(`unexpected ${type} from child #${index}:\n${thing}`);
591cb0ef41Sopenharmony_ci    };
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci    child.stderr.on('data', (d) => { errorHandler(d, 'data'); });
621cb0ef41Sopenharmony_ci    child.on('error', (err) => { errorHandler(err, 'error'); });
631cb0ef41Sopenharmony_ci    child.on('exit', common.mustCall((code) => {
641cb0ef41Sopenharmony_ci      if (code !== 0) {
651cb0ef41Sopenharmony_ci        errors.push(`child ${index} exited with code ${code}`);
661cb0ef41Sopenharmony_ci      }
671cb0ef41Sopenharmony_ci    }));
681cb0ef41Sopenharmony_ci  });
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci  let wcBuf = '';
711cb0ef41Sopenharmony_ci  wc.stdout.on('data', common.mustCall((data) => {
721cb0ef41Sopenharmony_ci    wcBuf += data;
731cb0ef41Sopenharmony_ci  }));
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci  process.on('exit', () => {
761cb0ef41Sopenharmony_ci    // Grep always adds one extra byte at the end.
771cb0ef41Sopenharmony_ci    assert.strictEqual(wcBuf.trim(), (MB + 1).toString());
781cb0ef41Sopenharmony_ci  });
791cb0ef41Sopenharmony_ci}
80