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