Rev 511 | Rev 783 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
557 | daniel-mar | 1 | #!/usr/bin/env php |
374 | daniel-mar | 2 | <?php |
3 | |||
4 | /* |
||
5 | * OIDplus 2.0 |
||
511 | daniel-mar | 6 | * Copyright 2019 - 2021 Daniel Marschall, ViaThinkSoft |
374 | daniel-mar | 7 | * |
8 | * Licensed under the Apache License, Version 2.0 (the "License"); |
||
9 | * you may not use this file except in compliance with the License. |
||
10 | * You may obtain a copy of the License at |
||
11 | * |
||
12 | * http://www.apache.org/licenses/LICENSE-2.0 |
||
13 | * |
||
14 | * Unless required by applicable law or agreed to in writing, software |
||
15 | * distributed under the License is distributed on an "AS IS" BASIS, |
||
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||
17 | * See the License for the specific language governing permissions and |
||
18 | * limitations under the License. |
||
19 | */ |
||
20 | |||
21 | // This script is used to detect problems with your database plugin |
||
22 | // ATTENTION: PLEASE DO NOT USE THIS SCRIPT ON A PRODUCTIVE DATABASE, |
||
23 | // BECAUSE IT ADDS AND CHANGES DATA DURING THE TESTING. |
||
24 | |||
25 | # --- |
||
26 | |||
27 | require_once __DIR__ . '/../includes/oidplus.inc.php'; |
||
28 | |||
29 | $num_errs = 0; |
||
30 | $num_succ = 0; |
||
31 | |||
502 | daniel-mar | 32 | if (PHP_SAPI != 'cli') echo '<pre>'; |
33 | |||
374 | daniel-mar | 34 | echo "OIDplus Database plugin testcases\n\n"; |
35 | |||
36 | OIDplus::init(true, true); |
||
37 | |||
38 | # Test MySQL |
||
502 | daniel-mar | 39 | try { |
40 | OIDplus::baseConfig()->setValue('DATABASE_PLUGIN', 'MySQL'); |
||
41 | OIDplus::init(true, true); |
||
42 | $db = OIDplus::db(); |
||
43 | OIDplus::init(true, true); |
||
44 | if (function_exists('mysqli_fetch_all')) { |
||
45 | OIDplus::baseConfig()->setValue('MYSQL_FORCE_MYSQLND_SUPPLEMENT', false); |
||
46 | echo "[With MySQLnd support] "; |
||
47 | dotest($db); |
||
48 | OIDplus::baseConfig()->setValue('MYSQL_FORCE_MYSQLND_SUPPLEMENT', true); |
||
49 | } |
||
50 | echo "[Without MySQLnd support] "; |
||
374 | daniel-mar | 51 | dotest($db); |
502 | daniel-mar | 52 | } catch (Exception $e) { |
53 | echo "MySQL:\n"; |
||
54 | echo redtext($e->getMessage())."\n\n"; |
||
374 | daniel-mar | 55 | } |
56 | |||
57 | # Test PDO |
||
502 | daniel-mar | 58 | try { |
59 | OIDplus::baseConfig()->setValue('DATABASE_PLUGIN', 'PDO'); |
||
60 | OIDplus::init(true, true); |
||
61 | $db = OIDplus::db(); |
||
62 | dotest($db); |
||
63 | } catch (Exception $e) { |
||
64 | echo "PDO:\n"; |
||
65 | echo redtext($e->getMessage())."\n\n"; |
||
66 | } |
||
374 | daniel-mar | 67 | |
68 | # Test ODBC |
||
502 | daniel-mar | 69 | try { |
70 | OIDplus::baseConfig()->setValue('DATABASE_PLUGIN', 'ODBC'); |
||
71 | OIDplus::init(true, true); |
||
72 | $db = OIDplus::db(); |
||
73 | dotest($db); |
||
74 | } catch (Exception $e) { |
||
75 | echo "ODBC:\n"; |
||
76 | echo redtext($e->getMessage())."\n\n"; |
||
77 | } |
||
374 | daniel-mar | 78 | |
79 | # Test PgSQL |
||
502 | daniel-mar | 80 | try { |
81 | OIDplus::baseConfig()->setValue('DATABASE_PLUGIN', 'PgSQL'); |
||
82 | OIDplus::init(true, true); |
||
83 | $db = OIDplus::db(); |
||
84 | dotest($db); |
||
85 | } catch (Exception $e) { |
||
86 | echo "PgSQL:\n"; |
||
87 | echo redtext($e->getMessage())."\n\n"; |
||
88 | } |
||
374 | daniel-mar | 89 | |
90 | # Test SQLite3 |
||
502 | daniel-mar | 91 | try { |
92 | OIDplus::baseConfig()->setValue('DATABASE_PLUGIN', 'SQLite'); |
||
93 | OIDplus::init(true, true); |
||
94 | $db = OIDplus::db(); |
||
95 | dotest($db); |
||
96 | } catch (Exception $e) { |
||
97 | echo "SQLite3:\n"; |
||
98 | echo redtext($e->getMessage())."\n\n"; |
||
99 | } |
||
374 | daniel-mar | 100 | |
101 | # --- |
||
102 | |||
502 | daniel-mar | 103 | if (PHP_SAPI != 'cli') { |
104 | die('</pre>'); |
||
105 | } else { |
||
106 | exit($num_errs > 0 ? 1 : 0); |
||
107 | } |
||
374 | daniel-mar | 108 | |
109 | # --- |
||
110 | |||
111 | function dotest($db) { |
||
112 | echo "Database: " . get_class($db) . "\n"; |
||
113 | try { |
||
114 | $db->connect(); |
||
115 | } catch (Exception $e) { |
||
116 | echo "Connection ".redtext("FAILED")." (check userdata/baseconfig/config.inc.php): ".$e->getMessage()."\n\n"; |
||
117 | return; |
||
118 | } |
||
119 | echo "Detected slang: " . $db->getSlang()::id()."\n"; |
||
120 | $db->query("delete from ###objects where parent = 'test:1'"); |
||
121 | $db->query("insert into ###objects (id, parent, title, description, confidential) values ('test:1.1', 'test:1', '', '', '0')"); |
||
122 | $db->query("insert into ###objects (id, parent, title, description, confidential) values ('test:1.2', 'test:1', '', '', '0')"); |
||
123 | try { |
||
124 | // --- "SQL Date" handling |
||
125 | |||
126 | try { |
||
127 | $res = $db->query("update ###objects set created = ".$db->sqlDate()." where id = 'test:1.1'"); |
||
128 | echo "SQLDate (".$db->sqlDate().') '.greentext('PASSED')."\n"; |
||
129 | } catch (Exception $e) { |
||
130 | echo "SQLDate (".$db->sqlDate().') '.redtext('FAILED')."\n"; |
||
131 | } |
||
132 | |||
133 | // --- "Num rows" handling |
||
502 | daniel-mar | 134 | |
135 | $res = $db->query("select id from ###objects where parent = ? order by id", array('test:XXXXXXXXX')); |
||
136 | try { |
||
137 | $num_rows = $res->num_rows(); |
||
138 | } catch (Exception $e) { |
||
139 | $num_rows = $e->getMessage(); |
||
140 | } |
||
141 | echo "Num rows empty: " . ($num_rows===0 ? greentext('PASSED') : redtext('FAILED'))." ($num_rows)\n"; |
||
374 | daniel-mar | 142 | |
143 | $res = $db->query("select id from ###objects where parent = ? order by id", array('test:1')); |
||
502 | daniel-mar | 144 | try { |
145 | $num_rows = $res->num_rows(); |
||
146 | } catch (Exception $e) { |
||
147 | $num_rows = $e->getMessage(); |
||
148 | } |
||
149 | echo "Num rows: " . ($num_rows===2 ? greentext('PASSED') : redtext('FAILED'))." ($num_rows)\n"; |
||
374 | daniel-mar | 150 | |
151 | $res->fetch_array(); |
||
502 | daniel-mar | 152 | try { |
153 | $num_rows = $res->num_rows(); |
||
154 | } catch (Exception $e) { |
||
155 | $num_rows = $e->getMessage(); |
||
156 | } |
||
157 | echo "Num rows after something fetched: " . ($num_rows===2 ? greentext('PASSED') : redtext('FAILED'))." ($num_rows)\n"; |
||
374 | daniel-mar | 158 | |
159 | $nextid = $res->fetch_array()['id']; |
||
160 | echo "Num rows does not change cursor: " . ($nextid == 'test:1.2' ? greentext('PASSED') : redtext('FAILED'))."\n"; |
||
161 | |||
162 | $next = $res->fetch_array(); |
||
163 | echo "Fetch after EOF gives null: " . (is_null($next) ? greentext('PASSED') : redtext('FAILED'))."\n"; |
||
164 | |||
165 | // --- Simultanous prepared statements |
||
502 | daniel-mar | 166 | |
167 | $errmsg = ''; |
||
168 | try { |
||
169 | $res = $db->query("select id from ###objects where parent = ? order by id", array('test:1')); |
||
170 | $passed = false; |
||
171 | //$res->num_rows(); // sponge |
||
172 | while ($row = $res->fetch_array()) { |
||
173 | $res2 = $db->query("select id from ###objects where parent = ? order by id", array($row['id'])); |
||
174 | while ($row2 = $res2->fetch_array()) { |
||
175 | } |
||
176 | if ($row['id'] == 'test:1.2') { |
||
177 | $passed = true; |
||
178 | } |
||
374 | daniel-mar | 179 | } |
502 | daniel-mar | 180 | } catch (Exception $e) { |
181 | $passed = false; |
||
182 | $errmsg = ' ('.$e->getMessage().')'; |
||
374 | daniel-mar | 183 | } |
502 | daniel-mar | 184 | echo "Simultanous prepared statements: ".($passed ? greentext('PASSED') : redtext('FAILED'))."$errmsg\n"; |
185 | |||
186 | if (!$passed) { |
||
187 | // We cannot continue because the connection is in a state that cannot be recovered easily |
||
188 | echo "Cancelled!\n\n"; |
||
189 | return; |
||
190 | } |
||
191 | |||
374 | daniel-mar | 192 | // --- Exception handling |
193 | |||
194 | try { |
||
502 | daniel-mar | 195 | $db->query("SELECT * from ABCDEF"); |
374 | daniel-mar | 196 | echo "Exception for DirectQuery: ".redtext('FAILED').", no Exception thrown\n"; |
197 | } catch (Exception $e) { |
||
198 | if (strpos($e->getMessage(), 'ABCDEF') !== false) { |
||
199 | echo "Exception for DirectQuery: ".greentext('PASSED')."\n"; |
||
200 | } else { |
||
201 | echo "Exception for DirectQuery: ".redtext('FAILED').", does probably not contain DBMS error string\n"; |
||
202 | } |
||
203 | } |
||
204 | |||
205 | $msg = $db->error(); |
||
206 | if (strpos($msg, 'ABCDEF') !== false) { |
||
207 | echo "Error-Function after failed direct query: ".greentext('PASSED')."\n"; |
||
208 | } else { |
||
209 | echo "Error-Function after failed direct query: ".redtext('FAILED').", does probably not contain DBMS error string ($msg)\n"; |
||
210 | } |
||
211 | |||
212 | try { |
||
502 | daniel-mar | 213 | $db->query("SELECT * from FEDCBA", array('')); |
374 | daniel-mar | 214 | echo "Exception for PreparedQuery: ".redtext('FAILED').", no Exception thrown\n"; |
215 | } catch (Exception $e) { |
||
216 | if (strpos($e->getMessage(), 'FEDCBA') !== false) { |
||
217 | echo "Exception for PreparedQuery: ".greentext('PASSED')."\n"; |
||
218 | } else { |
||
219 | echo "Exception for PreparedQuery: ".redtext('FAILED').", does probably not contain DBMS error string\n"; |
||
220 | } |
||
221 | } |
||
222 | |||
223 | $msg = $db->error(); |
||
224 | if (strpos($msg, 'FEDCBA') !== false) { |
||
225 | echo "Error-Function after failed prepared query: ".greentext('PASSED')."\n"; |
||
226 | } else { |
||
227 | echo "Error-Function after failed prepared query: ".redtext('FAILED').", does probably not contain DBMS error string ($msg)\n"; |
||
228 | } |
||
229 | |||
230 | $db->query("select 1"); |
||
231 | $msg = $db->error(); |
||
232 | if (!$msg) { |
||
233 | echo "Error-Function gets cleared after non-failed query: ".greentext('PASSED')."\n"; |
||
234 | } else { |
||
235 | echo "Error-Function gets cleared after non-failed query: ".redtext('FAILED').", does probably not contain DBMS error string\n"; |
||
236 | } |
||
237 | |||
238 | // --- Boolean handling |
||
239 | |||
240 | $db->query("update ###objects set confidential = ? where id = 'test:1.1'", array(true)); |
||
241 | $res = $db->query("select confidential from ###objects where id = 'test:1.1'"); |
||
242 | $val = $res->fetch_object()->confidential; |
||
502 | daniel-mar | 243 | echo "Boolean handling TRUE with prepared statement (fetch): " . ($val ? greentext('PASSED') : redtext('FAILED'))."\n"; |
244 | $res = $db->query("select * from ###objects where id = 'test:1.1' and confidential = ?", array(true)); |
||
245 | $val = $res->fetch_object(); |
||
246 | echo "Boolean handling TRUE with prepared statement (where): " . ($val ? greentext('PASSED') : redtext('FAILED'))."\n"; |
||
374 | daniel-mar | 247 | |
248 | $db->query("update ###objects set confidential = ? where id = 'test:1.1'", array(false)); |
||
249 | $res = $db->query("select confidential from ###objects where id = 'test:1.1'"); |
||
250 | $val = $res->fetch_object()->confidential; |
||
502 | daniel-mar | 251 | echo "Boolean handling FALSE with prepared statement (fetch): " . (!$val ? greentext('PASSED') : redtext('FAILED'))."\n"; |
252 | $res = $db->query("select * from ###objects where id = 'test:1.1' and confidential = ?", array(false)); |
||
253 | $val = $res->fetch_object(); |
||
254 | echo "Boolean handling FALSE with prepared statement (where): " . ($val ? greentext('PASSED') : redtext('FAILED'))."\n"; |
||
374 | daniel-mar | 255 | |
502 | daniel-mar | 256 | $db->query("update ###objects set confidential = '1' where id = 'test:1.1'"); // NOTE: DO NOT USE THIS IN THE SOURCE CODE! Always use prepared statements for constant booleans |
374 | daniel-mar | 257 | $res = $db->query("select confidential from ###objects where id = 'test:1.1'"); |
258 | $val = $res->fetch_object()->confidential; |
||
502 | daniel-mar | 259 | echo "Boolean handling TRUE with normal statement (fetch): " . ($val ? greentext('PASSED') : redtext('FAILED'))."\n"; |
260 | $res = $db->query("select * from ###objects where id = 'test:1.1' and confidential = 1"); // NOTE: DO NOT USE THIS IN THE SOURCE CODE! Always use prepared statements for constant booleans |
||
261 | $val = $res->fetch_object(); |
||
262 | echo "Boolean handling TRUE with normal statement (where): " . ($val ? greentext('PASSED') : redtext('FAILED'))."\n"; |
||
374 | daniel-mar | 263 | |
502 | daniel-mar | 264 | $db->query("update ###objects set confidential = '0' where id = 'test:1.1'"); // NOTE: DO NOT USE THIS IN THE SOURCE CODE! Always use prepared statements for constant booleans |
374 | daniel-mar | 265 | $res = $db->query("select confidential from ###objects where id = 'test:1.1'"); |
266 | $val = $res->fetch_object()->confidential; |
||
502 | daniel-mar | 267 | echo "Boolean handling FALSE with normal statement (fetch): " . (!$val ? greentext('PASSED') : redtext('FAILED'))."\n"; |
268 | $res = $db->query("select * from ###objects where id = 'test:1.1' and confidential = 0"); // NOTE: DO NOT USE THIS IN THE SOURCE CODE! Always use prepared statements for constant booleans |
||
269 | $val = $res->fetch_object(); |
||
270 | echo "Boolean handling FALSE with normal statement (where): " . ($val ? greentext('PASSED') : redtext('FAILED'))."\n"; |
||
271 | |||
374 | daniel-mar | 272 | // --- Check if transactions work |
502 | daniel-mar | 273 | |
274 | if ($db->transaction_supported()) { |
||
275 | echo "Transaction support: " . greentext('Supported') ."\n"; |
||
374 | daniel-mar | 276 | |
502 | daniel-mar | 277 | $db->query("update ###objects set title = 'A' where id = 'test:1.1'"); |
278 | $db->transaction_begin(); |
||
279 | $db->query("update ###objects set title = 'B' where id = 'test:1.1'"); |
||
280 | $db->transaction_rollback(); |
||
281 | $res = $db->query("select title from ###objects where id = 'test:1.1'"); |
||
282 | $val = $res->fetch_object()->title; |
||
283 | echo "Transaction rollback: " . ($val == 'A' ? greentext('PASSED') : redtext('FAILED'))."\n"; |
||
374 | daniel-mar | 284 | |
502 | daniel-mar | 285 | $db->query("update ###objects set title = 'A' where id = 'test:1.1'"); |
286 | $db->transaction_begin(); |
||
287 | $db->query("update ###objects set title = 'B' where id = 'test:1.1'"); |
||
288 | $db->transaction_commit(); |
||
289 | $res = $db->query("select title from ###objects where id = 'test:1.1'"); |
||
290 | $val = $res->fetch_object()->title; |
||
291 | echo "Transaction commit: " . ($val == 'B' ? greentext('PASSED') : redtext('FAILED'))."\n"; |
||
292 | } else { |
||
293 | echo "Transaction support: " . redtext('Not supported') ."\n"; |
||
294 | } |
||
374 | daniel-mar | 295 | |
296 | // --- Check natOrder feature |
||
297 | |||
298 | $db->query("delete from ###objects where parent = 'test:1'"); |
||
299 | $db->query("insert into ###objects (id, parent, title, description, confidential) values ('oid:3.1.10', 'test:1', '', '', '0')"); |
||
300 | $db->query("insert into ###objects (id, parent, title, description, confidential) values ('oid:3.1.2', 'test:1', '', '', '0')"); |
||
301 | $res = $db->query("select id from ###objects where parent = ? order by ".$db->natOrder('id'), array('test:1')); |
||
502 | daniel-mar | 302 | //$res->num_rows(); // sponge |
374 | daniel-mar | 303 | $val = $res->fetch_object()->id; |
304 | echo "Natural OID Sorting (< 16 Bit): " . ($val == 'oid:3.1.2' ? greentext('PASSED') : redtext('FAILED'))."\n"; |
||
305 | |||
306 | $db->query("delete from ###objects where parent = 'test:1'"); |
||
307 | $db->query("insert into ###objects (id, parent, title, description, confidential) values ('oid:2.25.317919736312109525688528068157180855579', 'test:1', '', '', '0')"); |
||
308 | $db->query("insert into ###objects (id, parent, title, description, confidential) values ('oid:2.25.67919736312109525688528068157180855579', 'test:1', '', '', '0')"); |
||
309 | $res = $db->query("select id from ###objects where parent = ? order by ".$db->natOrder('id'), array('test:1')); |
||
502 | daniel-mar | 310 | //$res->num_rows(); // sponge |
374 | daniel-mar | 311 | $val = $res->fetch_object()->id; |
312 | echo "Natural OID Sorting (128 Bit): " . ($val == 'oid:2.25.67919736312109525688528068157180855579' ? greentext('PASSED') : redtext('FAILED'))."\n"; |
||
313 | |||
314 | $db->query("delete from ###objects where parent = 'test:1'"); |
||
315 | $db->query("insert into ###objects (id, parent, title, description, confidential) values ('abc:3.1.10', 'test:1', '', '', '0')"); |
||
316 | $db->query("insert into ###objects (id, parent, title, description, confidential) values ('abc:3.1.2', 'test:1', '', '', '0')"); |
||
317 | $res = $db->query("select id from ###objects where parent = ? order by ".$db->natOrder('id'), array('test:1')); |
||
502 | daniel-mar | 318 | //$res->num_rows(); // sponge |
374 | daniel-mar | 319 | $val = $res->fetch_object()->id; |
320 | echo "Non-Natural Sorting for Non-OIDs: " . ($val == 'abc:3.1.10' ? greentext('PASSED') : redtext('FAILED'))."\n"; |
||
321 | |||
322 | // --- Test insert_id() |
||
323 | |||
324 | $db->query("delete from ###log_object where object = 'test:1'"); |
||
325 | $cur = $db->insert_id(); |
||
326 | echo "Insert ID on non-insert: " . ($cur == 0 ? greentext('PASSED') : redtext('FAILED'))." ($cur)\n"; |
||
502 | daniel-mar | 327 | $db->query("insert into ###log_object (log_id, severity, object) values (1000, 0, 'test:1')"); |
374 | daniel-mar | 328 | $prev = $db->insert_id(); |
502 | daniel-mar | 329 | $db->query("insert into ###log_object (log_id, severity, object) values (2000, 1, 'test:1')"); |
374 | daniel-mar | 330 | $cur = $db->insert_id(); |
331 | echo "Insert ID on actual inserts: " . ($cur == $prev+1 ? greentext('PASSED') : redtext('FAILED'))." ($prev => $cur)\n"; |
||
332 | if ($cur != $prev+1); |
||
333 | $db->query("delete from ###log_object where object = 'test:1'"); |
||
334 | $cur = $db->insert_id(); |
||
335 | echo "Non-Insert query will reset insert ID: " . ($cur == 0 ? greentext('PASSED') : redtext('FAILED'))." ($cur)\n"; |
||
336 | |||
337 | } finally { |
||
502 | daniel-mar | 338 | try { |
339 | $db->query("delete from ###objects where parent = 'test:1'"); |
||
340 | }catch(Exception $e) {} |
||
374 | daniel-mar | 341 | } |
342 | $db->disconnect(); |
||
343 | echo "\n"; |
||
344 | } |
||
345 | |||
346 | function redtext($str) { |
||
347 | global $num_errs; |
||
348 | $num_errs++; |
||
502 | daniel-mar | 349 | return PHP_SAPI == 'cli' ? "\033[31m$str\033[0m" : '<font color="red">'.$str.'</font>'; |
374 | daniel-mar | 350 | } |
351 | |||
352 | function greentext($str) { |
||
353 | global $num_succ; |
||
354 | $num_succ++; |
||
502 | daniel-mar | 355 | return PHP_SAPI == 'cli' ? "\033[32m$str\033[0m" : '<font color="green">'.$str.'</font>'; |
374 | daniel-mar | 356 | } |