]> git.lizzy.rs Git - dragonfireclient.git/blob - src/unittest/test_authdatabase.cpp
Revert "Replace MyEventReceiver KeyList with std::unordered_set" (#10622)
[dragonfireclient.git] / src / unittest / test_authdatabase.cpp
1 /*
2 Minetest
3 Copyright (C) 2018 bendeutsch, Ben Deutsch <ben@bendeutsch.de>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "test.h"
21
22 #include <algorithm>
23 #include "database/database-files.h"
24 #include "database/database-sqlite3.h"
25 #include "util/string.h"
26 #include "filesys.h"
27
28 namespace
29 {
30 // Anonymous namespace to create classes that are only
31 // visible to this file
32 //
33 // These are helpers that return a *AuthDatabase and
34 // allow us to run the same tests on different databases and
35 // database acquisition strategies.
36
37 class AuthDatabaseProvider
38 {
39 public:
40         virtual ~AuthDatabaseProvider() = default;
41         virtual AuthDatabase *getAuthDatabase() = 0;
42 };
43
44 class FixedProvider : public AuthDatabaseProvider
45 {
46 public:
47         FixedProvider(AuthDatabase *auth_db) : auth_db(auth_db){};
48         virtual ~FixedProvider(){};
49         virtual AuthDatabase *getAuthDatabase() { return auth_db; };
50
51 private:
52         AuthDatabase *auth_db;
53 };
54
55 class FilesProvider : public AuthDatabaseProvider
56 {
57 public:
58         FilesProvider(const std::string &dir) : dir(dir){};
59         virtual ~FilesProvider() { delete auth_db; };
60         virtual AuthDatabase *getAuthDatabase()
61         {
62                 delete auth_db;
63                 auth_db = new AuthDatabaseFiles(dir);
64                 return auth_db;
65         };
66
67 private:
68         std::string dir;
69         AuthDatabase *auth_db = nullptr;
70 };
71
72 class SQLite3Provider : public AuthDatabaseProvider
73 {
74 public:
75         SQLite3Provider(const std::string &dir) : dir(dir){};
76         virtual ~SQLite3Provider() { delete auth_db; };
77         virtual AuthDatabase *getAuthDatabase()
78         {
79                 delete auth_db;
80                 auth_db = new AuthDatabaseSQLite3(dir);
81                 return auth_db;
82         };
83
84 private:
85         std::string dir;
86         AuthDatabase *auth_db = nullptr;
87 };
88 }
89
90 class TestAuthDatabase : public TestBase
91 {
92 public:
93         TestAuthDatabase() { TestManager::registerTestModule(this); }
94         const char *getName() { return "TestAuthDatabase"; }
95
96         void runTests(IGameDef *gamedef);
97         void runTestsForCurrentDB();
98
99         void testRecallFail();
100         void testCreate();
101         void testRecall();
102         void testChange();
103         void testRecallChanged();
104         void testChangePrivileges();
105         void testRecallChangedPrivileges();
106         void testListNames();
107         void testDelete();
108
109 private:
110         AuthDatabaseProvider *auth_provider;
111 };
112
113 static TestAuthDatabase g_test_instance;
114
115 void TestAuthDatabase::runTests(IGameDef *gamedef)
116 {
117         // fixed directory, for persistence
118         thread_local const std::string test_dir = getTestTempDirectory();
119
120         // Each set of tests is run twice for each database type:
121         // one where we reuse the same AuthDatabase object (to test local caching),
122         // and one where we create a new AuthDatabase object for each call
123         // (to test actual persistence).
124
125         rawstream << "-------- Files database (same object)" << std::endl;
126
127         AuthDatabase *auth_db = new AuthDatabaseFiles(test_dir);
128         auth_provider = new FixedProvider(auth_db);
129
130         runTestsForCurrentDB();
131
132         delete auth_db;
133         delete auth_provider;
134
135         // reset database
136         fs::DeleteSingleFileOrEmptyDirectory(test_dir + DIR_DELIM + "auth.txt");
137
138         rawstream << "-------- Files database (new objects)" << std::endl;
139
140         auth_provider = new FilesProvider(test_dir);
141
142         runTestsForCurrentDB();
143
144         delete auth_provider;
145
146         rawstream << "-------- SQLite3 database (same object)" << std::endl;
147
148         auth_db = new AuthDatabaseSQLite3(test_dir);
149         auth_provider = new FixedProvider(auth_db);
150
151         runTestsForCurrentDB();
152
153         delete auth_db;
154         delete auth_provider;
155
156         // reset database
157         fs::DeleteSingleFileOrEmptyDirectory(test_dir + DIR_DELIM + "auth.sqlite");
158
159         rawstream << "-------- SQLite3 database (new objects)" << std::endl;
160
161         auth_provider = new SQLite3Provider(test_dir);
162
163         runTestsForCurrentDB();
164
165         delete auth_provider;
166 }
167
168 ////////////////////////////////////////////////////////////////////////////////
169
170 void TestAuthDatabase::runTestsForCurrentDB()
171 {
172         TEST(testRecallFail);
173         TEST(testCreate);
174         TEST(testRecall);
175         TEST(testChange);
176         TEST(testRecallChanged);
177         TEST(testChangePrivileges);
178         TEST(testRecallChangedPrivileges);
179         TEST(testListNames);
180         TEST(testDelete);
181         TEST(testRecallFail);
182 }
183
184 void TestAuthDatabase::testRecallFail()
185 {
186         AuthDatabase *auth_db = auth_provider->getAuthDatabase();
187         AuthEntry authEntry;
188
189         // no such user yet
190         UASSERT(!auth_db->getAuth("TestName", authEntry));
191 }
192
193 void TestAuthDatabase::testCreate()
194 {
195         AuthDatabase *auth_db = auth_provider->getAuthDatabase();
196         AuthEntry authEntry;
197
198         authEntry.name = "TestName";
199         authEntry.password = "TestPassword";
200         authEntry.privileges.emplace_back("shout");
201         authEntry.privileges.emplace_back("interact");
202         authEntry.last_login = 1000;
203         UASSERT(auth_db->createAuth(authEntry));
204 }
205
206 void TestAuthDatabase::testRecall()
207 {
208         AuthDatabase *auth_db = auth_provider->getAuthDatabase();
209         AuthEntry authEntry;
210
211         UASSERT(auth_db->getAuth("TestName", authEntry));
212         UASSERTEQ(std::string, authEntry.name, "TestName");
213         UASSERTEQ(std::string, authEntry.password, "TestPassword");
214         // the order of privileges is unimportant
215         std::sort(authEntry.privileges.begin(), authEntry.privileges.end());
216         UASSERTEQ(std::string, str_join(authEntry.privileges, ","), "interact,shout");
217 }
218
219 void TestAuthDatabase::testChange()
220 {
221         AuthDatabase *auth_db = auth_provider->getAuthDatabase();
222         AuthEntry authEntry;
223
224         UASSERT(auth_db->getAuth("TestName", authEntry));
225         authEntry.password = "NewPassword";
226         authEntry.last_login = 1002;
227         UASSERT(auth_db->saveAuth(authEntry));
228 }
229
230 void TestAuthDatabase::testRecallChanged()
231 {
232         AuthDatabase *auth_db = auth_provider->getAuthDatabase();
233         AuthEntry authEntry;
234
235         UASSERT(auth_db->getAuth("TestName", authEntry));
236         UASSERTEQ(std::string, authEntry.password, "NewPassword");
237         // the order of privileges is unimportant
238         std::sort(authEntry.privileges.begin(), authEntry.privileges.end());
239         UASSERTEQ(std::string, str_join(authEntry.privileges, ","), "interact,shout");
240         UASSERTEQ(u64, authEntry.last_login, 1002);
241 }
242
243 void TestAuthDatabase::testChangePrivileges()
244 {
245         AuthDatabase *auth_db = auth_provider->getAuthDatabase();
246         AuthEntry authEntry;
247
248         UASSERT(auth_db->getAuth("TestName", authEntry));
249         authEntry.privileges.clear();
250         authEntry.privileges.emplace_back("interact");
251         authEntry.privileges.emplace_back("fly");
252         authEntry.privileges.emplace_back("dig");
253         UASSERT(auth_db->saveAuth(authEntry));
254 }
255
256 void TestAuthDatabase::testRecallChangedPrivileges()
257 {
258         AuthDatabase *auth_db = auth_provider->getAuthDatabase();
259         AuthEntry authEntry;
260
261         UASSERT(auth_db->getAuth("TestName", authEntry));
262         // the order of privileges is unimportant
263         std::sort(authEntry.privileges.begin(), authEntry.privileges.end());
264         UASSERTEQ(std::string, str_join(authEntry.privileges, ","), "dig,fly,interact");
265 }
266
267 void TestAuthDatabase::testListNames()
268 {
269
270         AuthDatabase *auth_db = auth_provider->getAuthDatabase();
271         std::vector<std::string> list;
272
273         AuthEntry authEntry;
274
275         authEntry.name = "SecondName";
276         authEntry.password = "SecondPassword";
277         authEntry.privileges.emplace_back("shout");
278         authEntry.privileges.emplace_back("interact");
279         authEntry.last_login = 1003;
280         auth_db->createAuth(authEntry);
281
282         auth_db->listNames(list);
283         // not necessarily sorted, so sort before comparing
284         std::sort(list.begin(), list.end());
285         UASSERTEQ(std::string, str_join(list, ","), "SecondName,TestName");
286 }
287
288 void TestAuthDatabase::testDelete()
289 {
290         AuthDatabase *auth_db = auth_provider->getAuthDatabase();
291
292         UASSERT(!auth_db->deleteAuth("NoSuchName"));
293         UASSERT(auth_db->deleteAuth("TestName"));
294         // second try, expect failure
295         UASSERT(!auth_db->deleteAuth("TestName"));
296 }