Search code examples
node.jstap

Asserting streams


How would you go about stream assertions? that is, you care about the sequence of inputs but not that they are exclusive (something may come in between).

Listening to events in each stage is of course doable but it gets incredibly verbose, looking for a more pragmatic solution.

Brute approach would be something like the following tape test

t.plan(3);

var exe = child.spawn(...);
exe.stdout.once('data', first function(data) {
  // first expected output is always 1
  t.equal(data.toString(), '1\n');

    // next, 2, 3, 4 is coming but in unknown order.
    // the test only tests for 2
    exe.stdout.on('data', function second(data) {
      if (data.toString() !== '2\n') {
        // skip, don't care about this entry
        return;
      }

      exe.stdout.removeListener('data', second);
      t.equal(data.toString(), '2\n');

      // next is 5, 6, 7, again in unknown order but they are
      // AFTER the previous sequence
      exe.stdout.on('data', function third(data) {
        if (data.toString() !== '7\n') {
          // skip, don't care about this entry
          return;
        }

        exe.stdout.removeListener('data', third);        
        t.equal(data.toString(), '7\n');
      });
    });
  });
});

Solution

  • Here's a potential solution. We add a single data listener, and each time we get an event we check if it matches the next thing we expect, and if so drop that from the array of expected values. Finally, when we've emptied the array we call the callback. I assume you have a callback to call when you've gotten the expected responses. You will probably want to make sure there's a timeout on this test; otherwise it will wait forever and never fail.

    assertStreamWithGaps = function(stream, strs, next) {
      stream.on('data', function(data) {
        if(data.toString() === strs[0]) {
          strs.shift();
          if(strs.length === 0) {
            next();
          }
        }
      });
    }
    

    You would call this in your example like:

    assertStreamWithGaps(exe.stdout, ['1\n', '2\n', '7\n']);
    

    This doesn't quite match your example, because you expect there to be no leading gaps. Its not clear to me whether that was intentional, so I skipped it. It would probably be easy to add that functionality.

    Also, I'm not sure what t is or how to use it, so I didn't.