Skip to content

test: write concern test cleanup #2342

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

Merged
merged 6 commits into from
Dec 8, 2020
Merged

test: write concern test cleanup #2342

merged 6 commits into from
Dec 8, 2020

Conversation

emadum
Copy link
Contributor

@emadum emadum commented May 2, 2020

Description

Cleans up duplication and deprecation warnings in write concern command construction tests.

What changed?

Are there any files to ignore?

@emadum emadum requested review from mbroadst and reggi May 2, 2020 23:40
@mbroadst
Copy link
Member

mbroadst commented May 3, 2020

I agree with you that these tests are a whole bunch of copy-pasta! Your approach looks similar to the ReplSetFixture we used in some of our core test, but I wonder if we can design a better way out of this situation..

Ultimately, we are testing command construction here. The tests boil down to something like the following:

client.connect((err, client) => {
  expect(err).to.not.exist;
  const db = client.db(this.configuration.db);

  db.collection('test')
    .aggregate([{ $match: {} }, { $out: 'someOtherDb' }], {
      w: 2,
      wtimeout: 1000
    })
    .toArray(err => {
      expect(err).to.not.exist;
      expect(constructedCommand)
        .property('writeConcern').to.eql({ w: 2, wtimeout: 1000 });

      client.close(done);
    });
});

where constructedCommand is captured during execution. We don't need a mock server simulating a replicaset here, or even a mock server at all! Sometimes I think the mock server was written before a time when tools like sinon made this easy.

It might be a bit tricky to figure out at first, but I think we can use some existing examples of stubbing the Topology/Server classes in order to provide the same functionality without actually setting up TCP sockets. Alternatively, we could convert these to actual functional tests, connect them to real servers, and use command monitoring to verify that the writeConcern is constructed properly. I think both are fine solutions, and better than what we've got in the source today

@emadum
Copy link
Contributor Author

emadum commented May 3, 2020

Your approach looks similar to the ReplSetFixture we used in some of our core test, but I wonder if we can design a better way out of this situation..

Haha yeah as I was writing it I was thinking "this is a very general pattern, someone has probably done this before somewhere." Creating the class was simple though, so I didn't spend time grepping. The laborious part was stripping the boilerplate - it should be trivial to convert these tests to a better underlying paradigm now.

It might be a bit tricky to figure out at first, but I think we can use some existing examples of stubbing the Topology/Server classes in order to provide the same functionality without actually setting up TCP sockets.

Agreed, this sounds like a better solution.

Alternatively, we could convert these to actual functional tests, connect them to real servers, and use command monitoring to verify that the writeConcern is constructed properly.

I'm not sure I see any benefit to that, since these tests feel like they should be unit tests since the server they are running against is irrelevant. I could see a future optimization to our evergreen setup where we only run unit tests once per environment, and then we'd have an incentive to keep tests that don't really need a server from using one.

@mbroadst
Copy link
Member

mbroadst commented May 3, 2020

Great, glad we agree on the stubbed approach. I think we could very likely end up with a fantastic new helper like:

it('should build writeConcern properly', withStubbedClient((client, commands, done) => {
  client.connect((err, client) => {
    expect(err).to.not.exist;
    const db = client.db(this.configuration.db);
  
    db.collection('test')
      .aggregate([{ $match: {} }, { $out: 'someOtherDb' }], {
        w: 2,
        wtimeout: 1000
      })
      .toArray(err => {
        expect(err).to.not.exist;
        expect(commands)
          .property('[0].writeConcern').to.eql({ w: 2, wtimeout: 1000 });
  
        client.close(done);
      });
  });
});

I'm sure there's something I'm missing here though, here are some thoughts that occur to me immediately:

  • commands would have to track all built wire protocol commands, but I think at this point it might be enough to stub command on the connection or something).
  • you might not want every one of those commands 🤷

@emadum
Copy link
Contributor Author

emadum commented May 3, 2020

we could very likely end up with a fantastic new helper

Yeah that would be awesome! I've refactored all of the tests to use a writeConcernTest helper, which in turn uses a withStubbedClient helper, which just wraps around the existing WriteConcernTest class. However, it should now be really easy to simply update the helpers without further modifying the tests.

}
}

function withStubbedClient(testFn) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you going to further refactor this to use sinon or are we deferring that work to a later PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I was planning to follow up by extracting withStubbedClient to test/functional/shared.js and making it use sinon.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

follow up in this PR or a subsequent one? Just trying to decide on whether to approve or not :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no rush to get this cleanup in so might as well do it in this PR, I'll mark it as a draft for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created a ticket to track this work: NODE-2603

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given we're probably not getting to NODE-2603 particularly soon, I think it's a good idea to merge this PR in for now for the boilerplate reduction, so it doesn't sit around any longer. cc @nbbeeken

@emadum emadum marked this pull request as draft May 4, 2020 14:49
@emadum emadum removed the request for review from reggi May 4, 2020 14:49
@emadum emadum marked this pull request as ready for review December 5, 2020 19:07
@emadum emadum marked this pull request as draft December 5, 2020 19:07
@emadum emadum marked this pull request as ready for review December 7, 2020 22:30
@emadum emadum requested a review from nbbeeken December 7, 2020 22:31
@emadum emadum merged commit cdb614d into 3.6 Dec 8, 2020
@emadum emadum deleted the write-concern-test-cleanup branch December 8, 2020 23:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants