Skip to content

Regression: Stub pseudo randomness broken #525

@simlu

Description

@simlu

Describe the bug

Stubbing of pseudo randomness no longer feasible / working with this change

The below example works reliably with 8.3.0 but breaks with 8.3.1

How to reproduce

const crypto = require('crypto');
const { v4: uuid } = require('uuid');

crypto.randomBytes = (size, cb) => {
  let result = crypto.createHash('sha256').update('some-seed').digest();
  while (result.length < size) {
    result = Buffer.concat([result, crypto.createHash('sha256').update(result).digest()]);
  }
  result = result.slice(0, size);
  return cb ? cb(null, result) : result;
};
crypto.randomFillSync = (buffer, offset, size) => {
  const o = offset || 0;
  const s = size || buffer.byteLength;
  crypto.randomBytes(s, (err, res) => {
    res.copy(buffer, o, 0, s);
  });
  return buffer;
};

console.log(uuid(), uuid());
// => 0ad40e47-01e4-4acb-afa0-ad8c30a6aa42, 0ad40e47-01e4-4acb-afa0-ad8c30a6aa42

Above can probably be made even more minimal. The example was distilled from here.

Expected behavior

It should be feasible to stub the uuid generation with a PRNG at any given point in time. With the optimization introduces in 8.3.1 this is no longer possible without re-requiring uuid before every randomness "reset".

Runtime

  • OS: Linux
  • Runtime: Node.js
  • Runtime Version: v10.22.1

Additional information

Background: I'm the maintainer of a test framework that supports pseudo randomness injection. The use case of making uuid generation consistent between test executions is very important to us to e.g. make requests fingerprints consistent since we are using nock.

I'm sure the discussion above is going to go towards "why is above example even necessary", ie it should be enough to seed once? The problem is that state was introduced with uuid v8.3.1. So randomness can no longer be "reset" when necessary (i.e. between running different tests). That means that to reset the randomness state one needs to re-require the uuid import. This is very ugly and leads to memory leaks.

I am very happy to explain this further and give more background if needed!

Maybe there is a way that we can do both: keep the ability for stubbing as well as the optimization that was introduced. But I'm not sure how just yet. Very much looking forward to having a good discussion here. Cheers!

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions