]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/testsuite.cpp
Merge pull request #1157 from SaberUK/insp20+fix-cron-restart
[user/henk/code/inspircd.git] / src / testsuite.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009 Robin Burchell <robin+git@viroteck.net>
5  *   Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
6  *   Copyright (C) 2008 Dennis Friis <peavey@inspircd.org>
7  *
8  * This file is part of InspIRCd.  InspIRCd is free software: you can
9  * redistribute it and/or modify it under the terms of the GNU General Public
10  * License as published by the Free Software Foundation, version 2.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21
22 /* $Core */
23
24 #include "inspircd.h"
25 #include "testsuite.h"
26 #include "threadengine.h"
27 #include <iostream>
28
29 class TestSuiteThread : public Thread
30 {
31  public:
32         TestSuiteThread() : Thread()
33         {
34         }
35
36         virtual ~TestSuiteThread()
37         {
38         }
39
40         virtual void Run()
41         {
42                 while (GetExitFlag() == false)
43                 {
44                         std::cout << "Test suite thread run...\n";
45                         sleep(5);
46                 }
47         }
48 };
49
50 TestSuite::TestSuite()
51 {
52         std::cout << "\n\n*** STARTING TESTSUITE ***\n";
53
54         std::string modname;
55         char choice;
56
57         while (1)
58         {
59                 std::cout << "(1) Call all module OnRunTestSuite() methods\n";
60                 std::cout << "(2) Load a module\n";
61                 std::cout << "(3) Unload a module\n";
62                 std::cout << "(4) Threading tests\n";
63                 std::cout << "(5) Wildcard and CIDR tests\n";
64                 std::cout << "(6) Comma sepstream tests\n";
65                 std::cout << "(7) Space sepstream tests\n";
66                 std::cout << "(8) UID generation tests\n";
67
68                 std::cout << std::endl << "(X) Exit test suite\n";
69
70                 std::cout << "\nChoices (Enter one or more options as a list then press enter, e.g. 15X): ";
71                 std::cin >> choice;
72
73                 if (!choice)
74                         continue;
75
76                 switch (choice)
77                 {
78                         case '1':
79                                 FOREACH_MOD(I_OnRunTestSuite, OnRunTestSuite());
80                                 break;
81                         case '2':
82                                 std::cout << "Enter module filename to load: ";
83                                 std::cin >> modname;
84                                 std::cout << (ServerInstance->Modules->Load(modname.c_str()) ? "\nSUCCESS!\n" : "\nFAILURE\n");
85                                 break;
86                         case '3':
87                                 std::cout << "Enter module filename to unload: ";
88                                 std::cin >> modname;
89                                 {
90                                         Module* m = ServerInstance->Modules->Find(modname);
91                                         std::cout << (ServerInstance->Modules->Unload(m) ? "\nSUCCESS!\n" : "\nFAILURE\n");
92                                         ServerInstance->AtomicActions.Run();
93                                 }
94                                 break;
95                         case '4':
96                                 std::cout << (DoThreadTests() ? "\nSUCCESS!\n" : "\nFAILURE\n");
97                                 break;
98                         case '5':
99                                 std::cout << (DoWildTests() ? "\nSUCCESS!\n" : "\nFAILURE\n");
100                                 break;
101                         case '6':
102                                 std::cout << (DoCommaSepStreamTests() ? "\nSUCCESS!\n" : "\nFAILURE\n");
103                                 break;
104                         case '7':
105                                 std::cout << (DoSpaceSepStreamTests() ? "\nSUCCESS!\n" : "\nFAILURE\n");
106                                 break;
107                         case '8':
108                                 std::cout << (DoGenerateUIDTests() ? "\nSUCCESS!\n" : "\nFAILURE\n");
109                                 break;
110                         case 'X':
111                                 return;
112                                 break;
113                         default:
114                                 std::cout << "Invalid option\n";
115                                 break;
116                 }
117                 std::cout << std::endl;
118         }
119 }
120
121 /* Test that x matches y with match() */
122 #define WCTEST(x, y) std::cout << "match(\"" << x << "\",\"" << y "\") " << ((passed = (InspIRCd::Match(x, y, NULL))) ? " SUCCESS!\n" : " FAILURE\n")
123 /* Test that x does not match y with match() */
124 #define WCTESTNOT(x, y) std::cout << "!match(\"" << x << "\",\"" << y "\") " << ((passed = ((!InspIRCd::Match(x, y, NULL)))) ? " SUCCESS!\n" : " FAILURE\n")
125
126 /* Test that x matches y with match() and cidr enabled */
127 #define CIDRTEST(x, y) std::cout << "match(\"" << x << "\",\"" << y "\", true) " << ((passed = (InspIRCd::MatchCIDR(x, y, NULL))) ? " SUCCESS!\n" : " FAILURE\n")
128 /* Test that x does not match y with match() and cidr enabled */
129 #define CIDRTESTNOT(x, y) std::cout << "!match(\"" << x << "\",\"" << y "\", true) " << ((passed = ((!InspIRCd::MatchCIDR(x, y, NULL)))) ? " SUCCESS!\n" : " FAILURE\n")
130
131 bool TestSuite::DoWildTests()
132 {
133         std::cout << "\n\nWildcard and CIDR tests\n\n";
134         bool passed = false;
135
136         WCTEST("foobar", "*");
137         WCTEST("foobar", "foo*");
138         WCTEST("foobar", "*bar");
139         WCTEST("foobar", "foo??r");
140         WCTEST("foobar.test", "fo?bar.*t");
141         WCTEST("foobar.test", "fo?bar.t*t");
142         WCTEST("foobar.tttt", "fo?bar.**t");
143         WCTEST("foobar", "foobar");
144         WCTEST("foobar", "foo***bar");
145         WCTEST("foobar", "*foo***bar");
146         WCTEST("foobar", "**foo***bar");
147         WCTEST("foobar", "**foobar*");
148         WCTEST("foobar", "**foobar**");
149         WCTEST("foobar", "**foobar");
150         WCTEST("foobar", "**f?*?ar");
151         WCTEST("foobar", "**f?*b?r");
152         WCTEST("foofar", "**f?*f*r");
153         WCTEST("foofar", "**f?*f*?");
154         WCTEST("r", "*");
155         WCTEST("", "");
156         WCTEST("test@foo.bar.test", "*@*.bar.test");
157         WCTEST("test@foo.bar.test", "*test*@*.bar.test");
158         WCTEST("test@foo.bar.test", "*@*test");
159
160         WCTEST("a", "*a");
161         WCTEST("aa", "*a");
162         WCTEST("aaa", "*a");
163         WCTEST("aaaa", "*a");
164         WCTEST("aaaaa", "*a");
165         WCTEST("aaaaaa", "*a");
166         WCTEST("aaaaaaa", "*a");
167         WCTEST("aaaaaaaa", "*a");
168         WCTEST("aaaaaaaaa", "*a");
169         WCTEST("aaaaaaaaaa", "*a");
170         WCTEST("aaaaaaaaaaa", "*a");
171
172         WCTESTNOT("foobar", "bazqux");
173         WCTESTNOT("foobar", "*qux");
174         WCTESTNOT("foobar", "foo*x");
175         WCTESTNOT("foobar", "baz*");
176         WCTESTNOT("foobar", "foo???r");
177         WCTESTNOT("foobar", "foobars");
178         WCTESTNOT("foobar", "**foobar**h");
179         WCTESTNOT("foobar", "**foobar**h*");
180         WCTESTNOT("foobar", "**f??*bar?");
181         WCTESTNOT("foobar", "");
182         WCTESTNOT("", "foobar");
183         WCTESTNOT("OperServ", "O");
184         WCTESTNOT("O", "OperServ");
185         WCTESTNOT("foobar.tst", "fo?bar.*g");
186         WCTESTNOT("foobar.test", "fo?bar.*tt");
187
188         CIDRTEST("brain@1.2.3.4", "*@1.2.0.0/16");
189         CIDRTEST("brain@1.2.3.4", "*@1.2.3.0/24");
190         CIDRTEST("192.168.3.97", "192.168.3.0/24");
191
192         CIDRTESTNOT("brain@1.2.3.4", "x*@1.2.0.0/16");
193         CIDRTESTNOT("brain@1.2.3.4", "*@1.3.4.0/24");
194         CIDRTESTNOT("1.2.3.4", "1.2.4.0/24");
195         CIDRTESTNOT("brain@1.2.3.4", "*@/24");
196         CIDRTESTNOT("brain@1.2.3.4", "@1.2.3.4/9");
197         CIDRTESTNOT("brain@1.2.3.4", "@");
198         CIDRTESTNOT("brain@1.2.3.4", "");
199
200         return true;
201 }
202
203
204 #define STREQUALTEST(x, y) std::cout << "==(\"" << x << ",\"" << y "\") " << ((passed = (x == y)) ? "SUCCESS\n" : "FAILURE\n")
205
206 bool TestSuite::DoCommaSepStreamTests()
207 {
208         bool passed = false;
209         irc::commasepstream items("this,is,a,comma,stream");
210         std::string item;
211         int idx = 0;
212
213         while (items.GetToken(item))
214         {
215                 idx++;
216
217                 switch (idx)
218                 {
219                         case 1:
220                                 STREQUALTEST(item, "this");
221                                 break;
222                         case 2:
223                                 STREQUALTEST(item, "is");
224                                 break;
225                         case 3:
226                                 STREQUALTEST(item, "a");
227                                 break;
228                         case 4:
229                                 STREQUALTEST(item, "comma");
230                                 break;
231                         case 5:
232                                 STREQUALTEST(item, "stream");
233                                 break;
234                         default:
235                                 std::cout << "COMMASEPSTREAM: FAILURE: Got an index too many! " << idx << " items\n";
236                                 break;
237                 }
238         }
239
240         return true;
241 }
242
243 bool TestSuite::DoSpaceSepStreamTests()
244 {
245         bool passed = false;
246
247         irc::spacesepstream list("this is a space stream");
248         std::string item;
249         int idx = 0;
250
251         while (list.GetToken(item))
252         {
253                 idx++;
254
255                 switch (idx)
256                 {
257                         case 1:
258                                 STREQUALTEST(item, "this");
259                                 break;
260                         case 2:
261                                 STREQUALTEST(item, "is");
262                                 break;
263                         case 3:
264                                 STREQUALTEST(item, "a");
265                                 break;
266                         case 4:
267                                 STREQUALTEST(item, "space");
268                                 break;
269                         case 5:
270                                 STREQUALTEST(item, "stream");
271                                 break;
272                         default:
273                                 std::cout << "SPACESEPSTREAM: FAILURE: Got an index too many! " << idx << " items\n";
274                                 break;
275                 }
276         }
277         return true;
278 }
279
280 bool TestSuite::DoThreadTests()
281 {
282         std::string anything;
283         ThreadEngine* te = NULL;
284
285         std::cout << "Creating new ThreadEngine class...\n";
286         try
287         {
288                 te = new ThreadEngine;
289         }
290         catch (...)
291         {
292                 std::cout << "Creation failed, test failure.\n";
293                 return false;
294         }
295         std::cout << "Creation success, type " << te->GetName() << "\n";
296
297         std::cout << "Allocate: new TestSuiteThread...\n";
298         TestSuiteThread* tst = new TestSuiteThread();
299
300         std::cout << "ThreadEngine::Create on TestSuiteThread...\n";
301         try
302         {
303                 try
304                 {
305                         te->Start(tst);
306                 }
307                 catch (CoreException &ce)
308                 {
309                         std::cout << "Failure: " << ce.GetReason() << std::endl;
310                 }
311         }
312         catch (...)
313         {
314                 std::cout << "Failure, unhandled exception\n";
315         }
316
317         std::cout << "Type any line and press enter to end test.\n";
318         std::cin >> anything;
319
320         /* Thread engine auto frees thread on delete */
321         std::cout << "Waiting for thread to exit... " << std::flush;
322         delete tst;
323         std::cout << "Done!\n";
324
325         std::cout << "Delete ThreadEngine... ";
326         delete te;
327         std::cout << "Done!\n";
328
329         return true;
330 }
331
332 bool TestSuite::DoGenerateUIDTests()
333 {
334         bool success = RealGenerateUIDTests();
335
336         // Reset the UID generation state so running the tests multiple times won't mess things up
337         for (unsigned int i = 0; i < 3; i++)
338                 ServerInstance->current_uid[i] = ServerInstance->Config->sid[i];
339         for (unsigned int i = 3; i < UUID_LENGTH-1; i++)
340                 ServerInstance->current_uid[i] = '9';
341
342         ServerInstance->current_uid[UUID_LENGTH-1] = '\0';
343
344         return success;
345 }
346
347 bool TestSuite::RealGenerateUIDTests()
348 {
349         std::string first_uid = ServerInstance->GetUID();
350         if (first_uid.length() != UUID_LENGTH-1)
351         {
352                 std::cout << "GENERATEUID: Generated UID is " << first_uid.length() << " characters long instead of " << UUID_LENGTH-1 << std::endl;
353                 return false;
354         }
355
356         if (ServerInstance->current_uid[UUID_LENGTH-1] != '\0')
357         {
358                 std::cout << "GENERATEUID: The null terminator is missing from the end of current_uid" << std::endl;
359                 return false;
360         }
361
362         // The correct UID when generating one for the first time is ...AAAAAA
363         std::string correct_uid = ServerInstance->Config->sid + std::string(UUID_LENGTH - 4, 'A');
364         if (first_uid != correct_uid)
365         {
366                 std::cout << "GENERATEUID: Generated an invalid first UID: " << first_uid << " instead of " << correct_uid << std::endl;
367                 return false;
368         }
369
370         // Set current_uid to be ...Z99999
371         ServerInstance->current_uid[3] = 'Z';
372         for (unsigned int i = 4; i < UUID_LENGTH-1; i++)
373                 ServerInstance->current_uid[i] = '9';
374
375         // Store the UID we'll be incrementing so we can display what's wrong later if necessary
376         std::string before_increment(ServerInstance->current_uid);
377         std::string generated_uid = ServerInstance->GetUID();
378
379         // Correct UID after incrementing ...Z99999 is ...0AAAAA
380         correct_uid = ServerInstance->Config->sid + "0" + std::string(UUID_LENGTH - 5, 'A');
381
382         if (generated_uid != correct_uid)
383         {
384                 std::cout << "GENERATEUID: Generated an invalid UID after incrementing " << before_increment << ": " << generated_uid << " instead of " << correct_uid << std::endl;
385                 return false;
386         }
387
388         // Set current_uid to be ...999999 to see if it rolls over correctly
389         for (unsigned int i = 3; i < UUID_LENGTH-1; i++)
390                 ServerInstance->current_uid[i] = '9';
391
392         before_increment.assign(ServerInstance->current_uid);
393         generated_uid = ServerInstance->GetUID();
394
395         // Correct UID after rolling over is the first UID we've generated (...AAAAAA)
396         if (generated_uid != first_uid)
397         {
398                 std::cout << "GENERATEUID: Generated an invalid UID after incrementing " << before_increment << ": " << generated_uid << " instead of " << first_uid << std::endl;
399                 return false;
400         }
401
402         return true;
403 }
404
405 TestSuite::~TestSuite()
406 {
407         std::cout << "\n\n*** END OF TEST SUITE ***\n";
408 }
409