1 2 /** 3 * Copyright (C) 2018-present MongoDB, Inc. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the Server Side Public License, version 1, 7 * as published by MongoDB, Inc. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * Server Side Public License for more details. 13 * 14 * You should have received a copy of the Server Side Public License 15 * along with this program. If not, see 16 * <http://www.mongodb.com/licensing/server-side-public-license>. 17 * 18 * As a special exception, the copyright holders give permission to link the 19 * code of portions of this program with the OpenSSL library under certain 20 * conditions as described in each individual source file and distribute 21 * linked combinations including the program with the OpenSSL library. You 22 * must comply with the Server Side Public License in all respects for 23 * all of the code used other than as permitted herein. If you modify file(s) 24 * with this exception, you may extend this exception to your version of the 25 * file(s), but you are not obligated to do so. If you do not wish to do so, 26 * delete this exception statement from your version. If you delete this 27 * exception statement from all source files in the program, then also delete 28 * it in the license file. 29 */ 30 31 #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault 32 33 #include <memory> 34 35 #include "mongo/transport/mock_session.h" 36 #include "mongo/transport/mock_ticket.h" 37 #include "mongo/transport/transport_layer.h" 38 #include "mongo/unittest/unittest.h" 39 #include "mongo/util/net/message.h" 40 #include "mongo/util/time_support.h" 41 42 namespace mongo { 43 44 class ServiceEntryPoint; 45 struct SSLPeerInfo; 46 47 /** 48 * Test class. Uses a mock TransportLayer to test that the ServiceEntryPoint 49 * calls the expected methods on the TransportLayer in the expected order, 50 * and with the expected parameters. 51 * 52 * Usage: 53 * 54 * TEST_F(ServiceEntryPointTestSuite, ServiceEntryPointImplTest) { 55 * // Set up our ServiceEntryPoint 56 * auto sepFactory = [](TransportLayer* tl){ 57 * return stdx::make_unique<ServiceEntryPointImpl>(tl); 58 * }; 59 * 60 * setServiceEntryPoint(sepFactory); 61 * 62 * // Run some tests 63 * fullLifeCycleTest(); 64 * } 65 */ 66 class ServiceEntryPointTestSuite : public mongo::unittest::Test { 67 public: 68 // Need a function that takes a TransportLayer* and returns a new 69 // ServiceEntryPoint 70 using ServiceEntryPointFactory = 71 stdx::function<std::unique_ptr<ServiceEntryPoint>(transport::TransportLayer*)>; 72 73 void setUp() override; 74 75 void setServiceEntryPoint(ServiceEntryPointFactory factory); 76 77 // Lifecycle Tests 78 void noLifeCycleTest(); 79 void halfLifeCycleTest(); 80 void fullLifeCycleTest(); 81 82 // Concurrent Session Tests 83 void interruptingSessionTest(); 84 85 // Stress Tests 86 void burstStressTest(int numSessions = 1000, 87 int numCycles = 1, 88 Milliseconds delay = Milliseconds(0)); 89 void longSessionStressTest(); 90 91 class SEPTestSession; 92 using SEPTestSessionHandle = std::shared_ptr<SEPTestSession>; 93 94 /** 95 * This class mocks the TransportLayer and allows us to insert hooks beneath 96 * its methods. 97 */ 98 class MockTLHarness : public transport::TransportLayer { 99 public: 100 friend class SEPTestSession; 101 102 MockTLHarness(); 103 104 transport::Ticket sourceMessage( 105 const transport::SessionHandle& session, 106 Message* message, 107 Date_t expiration = transport::Ticket::kNoExpirationDate) override; 108 transport::Ticket sinkMessage( 109 const transport::SessionHandle& session, 110 const Message& message, 111 Date_t expiration = transport::Ticket::kNoExpirationDate) override; 112 Status wait(transport::Ticket&& ticket) override; 113 void asyncWait(transport::Ticket&& ticket, TicketCallback callback) override; 114 115 void end(const transport::SessionHandle& session) override; 116 Status setup() override; 117 Status start() override; 118 void shutdown() override; 119 120 transport::MockTicket* getMockTicket(const transport::Ticket& ticket); 121 122 // Mocked method hooks 123 stdx::function<transport::Ticket(const transport::SessionHandle&, Message*, Date_t)> 124 _sourceMessage; 125 stdx::function<transport::Ticket(const transport::SessionHandle&, const Message&, Date_t)> 126 _sinkMessage; 127 stdx::function<Status(transport::Ticket)> _wait; 128 stdx::function<void(transport::Ticket, TicketCallback)> _asyncWait; 129 stdx::function<void(const transport::SessionHandle&)> _end; 130 stdx::function<void(SEPTestSession& session)> _destroy_hook; 131 stdx::function<Status(void)> _start = [] { return Status::OK(); }; 132 stdx::function<void(void)> _shutdown = [] {}; 133 134 // Pre-set hook methods 135 transport::Ticket _defaultSource(const transport::SessionHandle& s, Message* m, Date_t d); 136 transport::Ticket _defaultSink(const transport::SessionHandle& s, const Message&, Date_t d); 137 transport::Ticket _sinkThenErrorOnWait(const transport::SessionHandle& s, 138 const Message& m, 139 Date_t d); 140 141 Status _defaultWait(transport::Ticket ticket); 142 Status _waitError(transport::Ticket ticket); 143 Status _waitOnceThenError(transport::Ticket ticket); 144 145 // Reset all hooks to their defaults 146 void _resetHooks(); 147 148 private: 149 void _destroy(SEPTestSession& session); 150 }; 151 152 /** 153 * A light wrapper around the mock session class, to handle our destroy logic. 154 */ 155 class SEPTestSession : public transport::MockSession { 156 MockTLHarness* _mockTL; 157 158 public: create(MockTLHarness * tl)159 static std::shared_ptr<SEPTestSession> create(MockTLHarness* tl) { 160 std::shared_ptr<SEPTestSession> handle(new SEPTestSession(tl)); 161 return handle; 162 } 163 ~SEPTestSession()164 ~SEPTestSession() { 165 _mockTL->_destroy(*this); 166 } 167 168 private: SEPTestSession(MockTLHarness * tl)169 explicit SEPTestSession(MockTLHarness* tl) : transport::MockSession(tl), _mockTL(tl) {} 170 }; 171 172 private: 173 std::unique_ptr<MockTLHarness> _tl; 174 std::unique_ptr<ServiceEntryPoint> _sep; 175 }; 176 177 } // namespace mongo 178