/** * Copyright (C) 2020-present MongoDB, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the Server Side Public License, version 1, * as published by MongoDB, Inc. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * Server Side Public License for more details. * * You should have received a copy of the Server Side Public License * along with this program. If not, see * . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the Server Side Public License in all respects for * all of the code used other than as permitted herein. If you modify file(s) * with this exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. If you delete this * exception statement from all source files in the program, then also delete * it in the license file. */ #pragma once #include #include "mongo/executor/network_interface_mock.h" #include "mongo/stdx/thread.h" namespace mongo { class BSONObj; using executor::RemoteCommandResponse; namespace test { namespace mock { /** * MockNetwork wraps the NetworkInterfaceMock to provide a declarative approach to specify * expected behaviors on the network and to hide the interaction with NetworkInterfaceMock. * We refer to the behaviors we are testing as "expectations". * * Expectations: * All expectations are unordered by default, unless otherwise specified (see Sequences below). * There are two types of expectations: default expectations and user expectations. * The purpose of default expectations is to cover uninteresting calls that are typically * repeated throughout a set of tests, so that individual tests can focus on the specific * behaviors they are meant to evaluate. Default expectations may be matched any number of times * (including zero). * User expectations represent the concrete requirements of a test. They must all be matched * the exact number of times required. For example: * * // Earlier in the test fixture * mock.defaultExpect(...); // A * mock.defaultExpect(...); // B * * ... * * // In individual tests * mock.expect(...).times(...); // C * mock.expect(...).times(...); // D * * ... * * // Later in those tests * mock.runUntilExpectationsSatisfied(); * * We have no requirements here on matching A or B, but C and D must be satisfied in full. * You may omit the times() call if you would like to use the default of 1 "times". * * To run expectations, use runUntilExpectationsSatisfied(), which will block until all * expectations have been fully satisfied. You may also use runUntil() if you only want to * advance to a particular time. If you would like to still check that your expectations have * been satisfied (or explicitly demonstrate that they haven't), call verifyExpectations(). * * Sequences: * The Sequence class provides a way to specify order of expectations. A test may have all * expectations in a sequence, or a subset, or none at all. It may also include any number of * sequences. Note that sequences only specify partial ordering, which means it is acceptable to * interleave other expectations in between sequence members (including expectations belonging to * other sequences) so long as all sequences are run in their required order. We enforce ordering * by refusing to match an expectation if it has unsatisfied prerequisites. * * To specify a sequence, use the InSequence RAII type, which will add all Expectations in its * scope to an anonymous sequence. For example: * * * { * MockNetwork::InSequence seq(mock); * * mock.expect(...); // A * mock.expect(...); // B * } * * mock.expect(...); // C * * * In this example, we only require that A comes before B. We have no requirements for when C * is executed. Therefore, all of {ABC, ACB, CAB} are valid, but {BAC, BCA, CBA} are not valid. */ class MockNetwork { public: using MatcherFunc = std::function; using ActionFunc = std::function; class Matcher { public: Matcher(const char* cmdName) : Matcher(std::string(cmdName)) {} Matcher(const std::string& cmdName) { _matcherFunc = [=](const BSONObj& request) { return request.firstElementFieldNameStringData() == cmdName; }; } Matcher(const BSONObj& matcherQuery); Matcher(MatcherFunc matcherFunc) : _matcherFunc(std::move(matcherFunc)) {} bool operator()(const BSONObj& request) { return _matcherFunc(request); } private: MatcherFunc _matcherFunc; }; class Action { public: Action(ActionFunc func) : _actionFunc(std::move(func)){}; Action(const BSONObj& response) { _actionFunc = [=](const BSONObj& request) { return RemoteCommandResponse(response, Milliseconds(0)); }; } Action(const RemoteCommandResponse& commandResponse) { _actionFunc = [=](const BSONObj& request) { return commandResponse; }; } RemoteCommandResponse operator()(const BSONObj& request) { return _actionFunc(request); } private: ActionFunc _actionFunc; }; class Expectation { public: Expectation(Matcher matcher, Action action) : _matcher(std::move(matcher)), _action(std::move(action)) {} virtual ~Expectation() {} // We should only try to match an expectation if all its prerequisites in the sequence are // satisfied (or if it is not part of a sequence in the first place). // Default expectations should always match, as they cannot form sequences, and because we // generally have no restrictions on when and how many times they match. virtual bool prerequisitesMet() { return true; } bool match(const BSONObj& request) { return _matcher(request); } RemoteCommandResponse run(const BSONObj& request) { if (!isDefault()) { _allowedTimes--; } return _action(request); } virtual bool isDefault() const { return _allowedTimes == std::numeric_limits::max(); } bool isSatisfied() const { return _allowedTimes == 0; } // May throw. virtual void checkSatisfied() {} protected: int _allowedTimes = std::numeric_limits::max(); private: Matcher _matcher; Action _action; }; class UserExpectation : public Expectation { public: UserExpectation(Matcher matcher, Action action) : Expectation(matcher, action) { // Default value, may be overriden by calling times(). _allowedTimes = 1; } // We forbid matching if we have unsatisfied prerequisites and allow it otherwise. bool prerequisitesMet() override { // No prerequisites at all - okay to match. if (!_prevInSequence) { return true; } // If this expectation's immediate prerequisite is satisfied, that implies the // previous ones in the chain have also been satisfied. return _prevInSequence->isSatisfied(); } Expectation& times(int t) { _allowedTimes = t; return *this; } bool isDefault() const override { return false; } void checkSatisfied() override { uassert(5015501, "UserExpectation not satisfied", isSatisfied()); } // The expectation that comes before this on in the sequence, if applicable. UserExpectation* _prevInSequence = nullptr; }; class DefaultExpectation : public Expectation { public: DefaultExpectation(Matcher matcher, Action action) : Expectation(matcher, action) {} bool isDefault() const override { return true; } }; class Sequence { public: void addExpectation(UserExpectation& exp) { exp._prevInSequence = _lastExpectation; _lastExpectation = &exp; } private: UserExpectation* _lastExpectation = nullptr; }; // RAII construct to handle expectations declared as part of a sequence. class InSequence { public: InSequence(MockNetwork& mock) : _mock(mock) { invariant(!_mock._activeSequence); _mock._activeSequence = std::make_unique(); }; ~InSequence() { _mock._activeSequence.reset(); }; private: MockNetwork& _mock; }; explicit MockNetwork(executor::NetworkInterfaceMock* net) : _net(net) {} // Accept anything that Matcher's and Action's constructors allow. // Use expect() to mandate the exact calls each test expects. They must all be satisfied // or the test fails. template UserExpectation& expect(MatcherType&& matcher, Action action) { auto exp = std::make_unique(Matcher(std::forward(matcher)), std::move(action)); auto& ref = *exp; _expectations.emplace_back(std::move(exp)); if (_activeSequence) { _activeSequence.get()->addExpectation(ref); } return ref; } // Accept anything that Matcher's and Action's constructors allow. // Use defaultExpect() to specify shared behavior in test fixtures. This is best for // uninteresting calls common to a class of tests. // For these reasons, you are not allowed to declare further default expecations after // having already enqueued user expectations. template DefaultExpectation& defaultExpect(MatcherType&& matcher, Action action) { auto order = std::none_of(_expectations.begin(), _expectations.end(), [](const auto& exp) { return !exp->isDefault(); }); uassert( 5015502, "All default expectations must be declared before user expectations.", order); auto exp = std::make_unique(Matcher(std::forward(matcher)), std::move(action)); auto& ref = *exp; _expectations.emplace_back(std::move(exp)); return ref; } void verifyExpectations() { for (auto& exp : _expectations) { // This expectation will throw if it has not been met. exp->checkSatisfied(); } } // Removes user expectations only. void clearExpectations() { _expectations.erase(std::remove_if(_expectations.begin(), _expectations.end(), [&](auto& exp) { return !exp->isDefault(); }), _expectations.end()); } // Carries over default expectations but clears user expectations. Checks that the latter // have all been satisfied in the process. void verifyAndClearExpectations() { // May throw. verifyExpectations(); clearExpectations(); } // Advance time to the target. Run network operations and process requests along the way. void runUntil(Date_t targetTime); // Run until both the executor and the network are idle and all expectations are satisfied. // Otherwise, it hangs forever. void runUntilExpectationsSatisfied(); private: void _runUntilIdle(); bool _allExpectationsSatisfied() const; std::vector> _expectations; std::unique_ptr _activeSequence; executor::NetworkInterfaceMock* _net; }; } // namespace mock } // namespace test } // namespace mongo