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 #pragma once
32 
33 #include "mongo/db/logical_session_id.h"
34 #include "mongo/db/sessions_collection.h"
35 #include "mongo/stdx/functional.h"
36 #include "mongo/stdx/mutex.h"
37 #include "mongo/stdx/unordered_map.h"
38 
39 namespace mongo {
40 
41 /**
42  * To allow us to move a MockSessionCollection into the session cache while
43  * maintaining a hold on it from within our unit tests, the MockSessionCollection
44  * will have an internal pointer to a MockSessionsCollectionImpl object that the
45  * test creates and controls.
46  *
47  * This class can operate in two modes:
48  *
49  * - if no custom hooks are set, then the test caller may add() and remove() items
50  *   from the _sessions map, and this class will simply perform the required
51  *   operations against that set.
52  *
53  * - if custom hooks are set, then the hooks will be run instead of the provided
54  *   defaults, and the internal _sessions map will NOT be updated.
55  */
56 class MockSessionsCollectionImpl {
57 public:
58     using SessionMap =
59         stdx::unordered_map<LogicalSessionId, LogicalSessionRecord, LogicalSessionIdHash>;
60 
61     MockSessionsCollectionImpl();
62 
63     using RefreshHook = stdx::function<Status(const LogicalSessionRecordSet&)>;
64     using RemoveHook = stdx::function<Status(const LogicalSessionIdSet&)>;
65 
66     // Set custom hooks to override default behavior
67     void setRefreshHook(RefreshHook hook);
68     void setRemoveHook(RemoveHook hook);
69 
70     // Reset all hooks to their defaults
71     void clearHooks();
72 
73     // Forwarding methods from the MockSessionsCollection
74     Status refreshSessions(const LogicalSessionRecordSet& sessions);
75     Status removeRecords(const LogicalSessionIdSet& sessions);
76 
77     // Test-side methods that operate on the _sessions map
78     void add(LogicalSessionRecord record);
79     void remove(LogicalSessionId lsid);
80     bool has(LogicalSessionId lsid);
81     void clearSessions();
82     const SessionMap& sessions() const;
83 
84     StatusWith<LogicalSessionIdSet> findRemovedSessions(OperationContext* opCtx,
85                                                         const LogicalSessionIdSet& sessions);
86 
87 private:
88     // Default implementations, may be overridden with custom hooks.
89     Status _refreshSessions(const LogicalSessionRecordSet& sessions);
90     Status _removeRecords(const LogicalSessionIdSet& sessions);
91 
92     stdx::mutex _mutex;
93     SessionMap _sessions;
94 
95     RefreshHook _refresh;
96     RemoveHook _remove;
97 };
98 
99 /**
100  * To allow us to move this into the session cache while maintaining a hold
101  * on it from the test side, the MockSessionCollection will have an internal pointer
102  * to an impl that we maintain access to.
103  */
104 class MockSessionsCollection : public SessionsCollection {
105 public:
MockSessionsCollection(std::shared_ptr<MockSessionsCollectionImpl> impl)106     explicit MockSessionsCollection(std::shared_ptr<MockSessionsCollectionImpl> impl)
107         : _impl(std::move(impl)) {}
108 
setupSessionsCollection(OperationContext * opCtx)109     Status setupSessionsCollection(OperationContext* opCtx) override {
110         return Status::OK();
111     }
112 
checkSessionsCollectionExists(OperationContext * opCtx)113     Status checkSessionsCollectionExists(OperationContext* opCtx) override {
114         return Status::OK();
115     }
116 
refreshSessions(OperationContext * opCtx,const LogicalSessionRecordSet & sessions)117     Status refreshSessions(OperationContext* opCtx,
118                            const LogicalSessionRecordSet& sessions) override {
119         return _impl->refreshSessions(sessions);
120     }
121 
removeRecords(OperationContext * opCtx,const LogicalSessionIdSet & sessions)122     Status removeRecords(OperationContext* opCtx, const LogicalSessionIdSet& sessions) override {
123         return _impl->removeRecords(sessions);
124     }
125 
findRemovedSessions(OperationContext * opCtx,const LogicalSessionIdSet & sessions)126     StatusWith<LogicalSessionIdSet> findRemovedSessions(
127         OperationContext* opCtx, const LogicalSessionIdSet& sessions) override {
128         return _impl->findRemovedSessions(opCtx, sessions);
129     }
130 
removeTransactionRecords(OperationContext * opCtx,const LogicalSessionIdSet & sessions)131     Status removeTransactionRecords(OperationContext* opCtx,
132                                     const LogicalSessionIdSet& sessions) override {
133         return Status::OK();
134     }
135 
136 private:
137     std::shared_ptr<MockSessionsCollectionImpl> _impl;
138 };
139 
140 }  // namespace mongo
141