MediaWiki  1.29.2
DatabaseTest.php
Go to the documentation of this file.
1 <?php
2 
4 
13  protected $db;
14 
15  private $functionTest = false;
16 
17  protected function setUp() {
18  parent::setUp();
19  $this->db = wfGetDB( DB_MASTER );
20  }
21 
22  protected function tearDown() {
23  parent::tearDown();
24  if ( $this->functionTest ) {
25  $this->dropFunctions();
26  $this->functionTest = false;
27  }
28  $this->db->restoreFlags( IDatabase::RESTORE_INITIAL );
29  }
30 
34  public function testAddQuotesNull() {
35  $check = "NULL";
36  if ( $this->db->getType() === 'sqlite' || $this->db->getType() === 'oracle' ) {
37  $check = "''";
38  }
39  $this->assertEquals( $check, $this->db->addQuotes( null ) );
40  }
41 
42  public function testAddQuotesInt() {
43  # returning just "1234" should be ok too, though...
44  # maybe
45  $this->assertEquals(
46  "'1234'",
47  $this->db->addQuotes( 1234 ) );
48  }
49 
50  public function testAddQuotesFloat() {
51  # returning just "1234.5678" would be ok too, though
52  $this->assertEquals(
53  "'1234.5678'",
54  $this->db->addQuotes( 1234.5678 ) );
55  }
56 
57  public function testAddQuotesString() {
58  $this->assertEquals(
59  "'string'",
60  $this->db->addQuotes( 'string' ) );
61  }
62 
63  public function testAddQuotesStringQuote() {
64  $check = "'string''s cause trouble'";
65  if ( $this->db->getType() === 'mysql' ) {
66  $check = "'string\'s cause trouble'";
67  }
68  $this->assertEquals(
69  $check,
70  $this->db->addQuotes( "string's cause trouble" ) );
71  }
72 
73  private function getSharedTableName( $table, $database, $prefix, $format = 'quoted' ) {
75 
76  $this->db->setTableAliases( [
77  $table => [
78  'dbname' => $database,
79  'schema' => null,
80  'prefix' => $prefix
81  ]
82  ] );
83 
84  $ret = $this->db->tableName( $table, $format );
85 
86  $this->db->setTableAliases( array_fill_keys(
88  [
89  'dbname' => $wgSharedDB,
90  'schema' => $wgSharedSchema,
91  'prefix' => $wgSharedPrefix
92  ]
93  ) );
94 
95  return $ret;
96  }
97 
98  private function prefixAndQuote( $table, $database = null, $prefix = null, $format = 'quoted' ) {
99  if ( $this->db->getType() === 'sqlite' || $format !== 'quoted' ) {
100  $quote = '';
101  } elseif ( $this->db->getType() === 'mysql' ) {
102  $quote = '`';
103  } elseif ( $this->db->getType() === 'oracle' ) {
104  $quote = '/*Q*/';
105  } else {
106  $quote = '"';
107  }
108 
109  if ( $database !== null ) {
110  if ( $this->db->getType() === 'oracle' ) {
111  $database = $quote . $database . '.';
112  } else {
113  $database = $quote . $database . $quote . '.';
114  }
115  }
116 
117  if ( $prefix === null ) {
118  $prefix = $this->dbPrefix();
119  }
120 
121  if ( $this->db->getType() === 'oracle' ) {
122  return strtoupper( $database . $quote . $prefix . $table );
123  } else {
124  return $database . $quote . $prefix . $table . $quote;
125  }
126  }
127 
128  public function testTableNameLocal() {
129  $this->assertEquals(
130  $this->prefixAndQuote( 'tablename' ),
131  $this->db->tableName( 'tablename' )
132  );
133  }
134 
135  public function testTableNameRawLocal() {
136  $this->assertEquals(
137  $this->prefixAndQuote( 'tablename', null, null, 'raw' ),
138  $this->db->tableName( 'tablename', 'raw' )
139  );
140  }
141 
142  public function testTableNameShared() {
143  $this->assertEquals(
144  $this->prefixAndQuote( 'tablename', 'sharedatabase', 'sh_' ),
145  $this->getSharedTableName( 'tablename', 'sharedatabase', 'sh_' )
146  );
147 
148  $this->assertEquals(
149  $this->prefixAndQuote( 'tablename', 'sharedatabase', null ),
150  $this->getSharedTableName( 'tablename', 'sharedatabase', null )
151  );
152  }
153 
154  public function testTableNameRawShared() {
155  $this->assertEquals(
156  $this->prefixAndQuote( 'tablename', 'sharedatabase', 'sh_', 'raw' ),
157  $this->getSharedTableName( 'tablename', 'sharedatabase', 'sh_', 'raw' )
158  );
159 
160  $this->assertEquals(
161  $this->prefixAndQuote( 'tablename', 'sharedatabase', null, 'raw' ),
162  $this->getSharedTableName( 'tablename', 'sharedatabase', null, 'raw' )
163  );
164  }
165 
166  public function testTableNameForeign() {
167  $this->assertEquals(
168  $this->prefixAndQuote( 'tablename', 'databasename', '' ),
169  $this->db->tableName( 'databasename.tablename' )
170  );
171  }
172 
173  public function testTableNameRawForeign() {
174  $this->assertEquals(
175  $this->prefixAndQuote( 'tablename', 'databasename', '', 'raw' ),
176  $this->db->tableName( 'databasename.tablename', 'raw' )
177  );
178  }
179 
180  public function testStoredFunctions() {
181  if ( !in_array( wfGetDB( DB_MASTER )->getType(), [ 'mysql', 'postgres' ] ) ) {
182  $this->markTestSkipped( 'MySQL or Postgres required' );
183  }
184  global $IP;
185  $this->dropFunctions();
186  $this->functionTest = true;
187  $this->assertTrue(
188  $this->db->sourceFile( "$IP/tests/phpunit/data/db/{$this->db->getType()}/functions.sql" )
189  );
190  $res = $this->db->query( 'SELECT mw_test_function() AS test', __METHOD__ );
191  $this->assertEquals( 42, $res->fetchObject()->test );
192  }
193 
194  private function dropFunctions() {
195  $this->db->query( 'DROP FUNCTION IF EXISTS mw_test_function'
196  . ( $this->db->getType() == 'postgres' ? '()' : '' )
197  );
198  }
199 
201  $res = $this->db->select( 'page', '*', [ 'page_id' => 1 ] );
202  $this->assertFalse( $this->db->tableExists( 'foobarbaz' ) );
203  $this->assertInternalType( 'int', $res->numRows() );
204  }
205 
206  public function testTransactionIdle() {
207  $db = $this->db;
208 
209  $db->setFlag( DBO_TRX );
210  $called = false;
211  $flagSet = null;
212  $db->onTransactionIdle(
213  function () use ( $db, &$flagSet, &$called ) {
214  $called = true;
215  $flagSet = $db->getFlag( DBO_TRX );
216  },
217  __METHOD__
218  );
219  $this->assertFalse( $flagSet, 'DBO_TRX off in callback' );
220  $this->assertTrue( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
221  $this->assertTrue( $called, 'Callback reached' );
222 
223  $db->clearFlag( DBO_TRX );
224  $flagSet = null;
225  $db->onTransactionIdle(
226  function () use ( $db, &$flagSet ) {
227  $flagSet = $db->getFlag( DBO_TRX );
228  },
229  __METHOD__
230  );
231  $this->assertFalse( $flagSet, 'DBO_TRX off in callback' );
232  $this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
233 
234  $db->clearFlag( DBO_TRX );
235  $db->onTransactionIdle(
236  function () use ( $db ) {
237  $db->setFlag( DBO_TRX );
238  },
239  __METHOD__
240  );
241  $this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
242  }
243 
244  public function testTransactionResolution() {
245  $db = $this->db;
246 
247  $db->clearFlag( DBO_TRX );
248  $db->begin( __METHOD__ );
249  $called = false;
250  $db->onTransactionResolution( function () use ( $db, &$called ) {
251  $called = true;
252  $db->setFlag( DBO_TRX );
253  } );
254  $db->commit( __METHOD__ );
255  $this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
256  $this->assertTrue( $called, 'Callback reached' );
257 
258  $db->clearFlag( DBO_TRX );
259  $db->begin( __METHOD__ );
260  $called = false;
261  $db->onTransactionResolution( function () use ( $db, &$called ) {
262  $called = true;
263  $db->setFlag( DBO_TRX );
264  } );
265  $db->rollback( __METHOD__, IDatabase::FLUSHING_ALL_PEERS );
266  $this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
267  $this->assertTrue( $called, 'Callback reached' );
268  }
269 
273  public function testTransactionListener() {
274  $db = $this->db;
275 
276  $db->setTransactionListener( 'ping', function () use ( $db, &$called ) {
277  $called = true;
278  } );
279 
280  $called = false;
281  $db->begin( __METHOD__ );
282  $db->commit( __METHOD__ );
283  $this->assertTrue( $called, 'Callback reached' );
284 
285  $called = false;
286  $db->begin( __METHOD__ );
287  $db->commit( __METHOD__ );
288  $this->assertTrue( $called, 'Callback still reached' );
289 
290  $called = false;
291  $db->begin( __METHOD__ );
292  $db->rollback( __METHOD__ );
293  $this->assertTrue( $called, 'Callback reached' );
294 
295  $db->setTransactionListener( 'ping', null );
296  $called = false;
297  $db->begin( __METHOD__ );
298  $db->commit( __METHOD__ );
299  $this->assertFalse( $called, 'Callback not reached' );
300  }
301 
305  public function testFlushSnapshot() {
306  $db = $this->db;
307 
308  $db->flushSnapshot( __METHOD__ ); // ok
309  $db->flushSnapshot( __METHOD__ ); // ok
310 
311  $db->setFlag( DBO_TRX, $db::REMEMBER_PRIOR );
312  $db->query( 'SELECT 1', __METHOD__ );
313  $this->assertTrue( (bool)$db->trxLevel(), "Transaction started." );
314  $db->flushSnapshot( __METHOD__ ); // ok
315  $db->restoreFlags( $db::RESTORE_PRIOR );
316 
317  $this->assertFalse( (bool)$db->trxLevel(), "Transaction cleared." );
318  }
319 
320  public function testGetScopedLock() {
321  $db = $this->db;
322 
323  $db->setFlag( DBO_TRX );
324  try {
325  $this->badLockingMethodImplicit( $db );
326  } catch ( RunTimeException $e ) {
327  $this->assertTrue( $db->trxLevel() > 0, "Transaction not committed." );
328  }
329  $db->clearFlag( DBO_TRX );
330  $db->rollback( __METHOD__, IDatabase::FLUSHING_ALL_PEERS );
331  $this->assertTrue( $db->lockIsFree( 'meow', __METHOD__ ) );
332 
333  try {
334  $this->badLockingMethodExplicit( $db );
335  } catch ( RunTimeException $e ) {
336  $this->assertTrue( $db->trxLevel() > 0, "Transaction not committed." );
337  }
338  $db->rollback( __METHOD__, IDatabase::FLUSHING_ALL_PEERS );
339  $this->assertTrue( $db->lockIsFree( 'meow', __METHOD__ ) );
340  }
341 
342  private function badLockingMethodImplicit( IDatabase $db ) {
343  $lock = $db->getScopedLockAndFlush( 'meow', __METHOD__, 1 );
344  $db->query( "SELECT 1" ); // trigger DBO_TRX
345  throw new RunTimeException( "Uh oh!" );
346  }
347 
348  private function badLockingMethodExplicit( IDatabase $db ) {
349  $lock = $db->getScopedLockAndFlush( 'meow', __METHOD__, 1 );
350  $db->begin( __METHOD__ );
351  throw new RunTimeException( "Uh oh!" );
352  }
353 
359  public function testFlagSetting() {
360  $db = $this->db;
361  $origTrx = $db->getFlag( DBO_TRX );
362  $origSsl = $db->getFlag( DBO_SSL );
363 
364  $origTrx
365  ? $db->clearFlag( DBO_TRX, $db::REMEMBER_PRIOR )
366  : $db->setFlag( DBO_TRX, $db::REMEMBER_PRIOR );
367  $this->assertEquals( !$origTrx, $db->getFlag( DBO_TRX ) );
368 
369  $origSsl
370  ? $db->clearFlag( DBO_SSL, $db::REMEMBER_PRIOR )
371  : $db->setFlag( DBO_SSL, $db::REMEMBER_PRIOR );
372  $this->assertEquals( !$origSsl, $db->getFlag( DBO_SSL ) );
373 
374  $db->restoreFlags( $db::RESTORE_INITIAL );
375  $this->assertEquals( $origTrx, $db->getFlag( DBO_TRX ) );
376  $this->assertEquals( $origSsl, $db->getFlag( DBO_SSL ) );
377 
378  $origTrx
379  ? $db->clearFlag( DBO_TRX, $db::REMEMBER_PRIOR )
380  : $db->setFlag( DBO_TRX, $db::REMEMBER_PRIOR );
381  $origSsl
382  ? $db->clearFlag( DBO_SSL, $db::REMEMBER_PRIOR )
383  : $db->setFlag( DBO_SSL, $db::REMEMBER_PRIOR );
384 
385  $db->restoreFlags();
386  $this->assertEquals( $origSsl, $db->getFlag( DBO_SSL ) );
387  $this->assertEquals( !$origTrx, $db->getFlag( DBO_TRX ) );
388 
389  $db->restoreFlags();
390  $this->assertEquals( $origSsl, $db->getFlag( DBO_SSL ) );
391  $this->assertEquals( $origTrx, $db->getFlag( DBO_TRX ) );
392  }
393 
398  public function testMutators() {
399  $old = $this->db->tablePrefix();
400  $this->assertType( 'string', $old, 'Prefix is string' );
401  $this->assertEquals( $old, $this->db->tablePrefix(), "Prefix unchanged" );
402  $this->assertEquals( $old, $this->db->tablePrefix( 'xxx' ) );
403  $this->assertEquals( 'xxx', $this->db->tablePrefix(), "Prefix set" );
404  $this->db->tablePrefix( $old );
405  $this->assertNotEquals( 'xxx', $this->db->tablePrefix() );
406 
407  $old = $this->db->dbSchema();
408  $this->assertType( 'string', $old, 'Schema is string' );
409  $this->assertEquals( $old, $this->db->dbSchema(), "Schema unchanged" );
410  $this->assertEquals( $old, $this->db->dbSchema( 'xxx' ) );
411  $this->assertEquals( 'xxx', $this->db->dbSchema(), "Schema set" );
412  $this->db->dbSchema( $old );
413  $this->assertNotEquals( 'xxx', $this->db->dbSchema() );
414  }
415 }
DatabaseTest\testTableNameLocal
testTableNameLocal()
Definition: DatabaseTest.php:128
DatabaseTest\dropFunctions
dropFunctions()
Definition: DatabaseTest.php:194
DatabaseTest\prefixAndQuote
prefixAndQuote( $table, $database=null, $prefix=null, $format='quoted')
Definition: DatabaseTest.php:98
DatabaseTest\testAddQuotesFloat
testAddQuotesFloat()
Definition: DatabaseTest.php:50
DatabaseTest\testTableNameRawShared
testTableNameRawShared()
Definition: DatabaseTest.php:154
DatabaseTest\setUp
setUp()
Definition: DatabaseTest.php:17
DatabaseTest\testTableNameRawLocal
testTableNameRawLocal()
Definition: DatabaseTest.php:135
$wgSharedTables
$wgSharedTables
Definition: DefaultSettings.php:1887
DatabaseTest\badLockingMethodImplicit
badLockingMethodImplicit(IDatabase $db)
Definition: DatabaseTest.php:342
$wgSharedSchema
$wgSharedSchema
Definition: DefaultSettings.php:1893
DatabaseTest\$db
Database $db
Definition: DatabaseTest.php:13
$wgSharedDB
$wgSharedDB
Shared database for multiple wikis.
Definition: DefaultSettings.php:1877
DatabaseTest\testAddQuotesNull
testAddQuotesNull()
Database::dropTable.
Definition: DatabaseTest.php:34
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
DatabaseTest\badLockingMethodExplicit
badLockingMethodExplicit(IDatabase $db)
Definition: DatabaseTest.php:348
DBO_SSL
const DBO_SSL
Definition: defines.php:17
DatabaseTest\testTableNameForeign
testTableNameForeign()
Definition: DatabaseTest.php:166
$res
$res
Definition: database.txt:21
DatabaseTest\testUnknownTableCorruptsResults
testUnknownTableCorruptsResults()
Definition: DatabaseTest.php:200
DBO_TRX
const DBO_TRX
Definition: defines.php:12
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:40
DatabaseTest\testAddQuotesString
testAddQuotesString()
Definition: DatabaseTest.php:57
DatabaseTest\$functionTest
$functionTest
Definition: DatabaseTest.php:15
MediaWikiTestCase\$called
$called
$called tracks whether the setUp and tearDown method has been called.
Definition: MediaWikiTestCase.php:36
DatabaseTest\testAddQuotesInt
testAddQuotesInt()
Definition: DatabaseTest.php:42
DatabaseTest\testTableNameRawForeign
testTableNameRawForeign()
Definition: DatabaseTest.php:173
DatabaseTest\testFlagSetting
testFlagSetting()
Database::getFlag( Database::setFlag() Database::restoreFlags()
Definition: DatabaseTest.php:359
DatabaseTest\testGetScopedLock
testGetScopedLock()
Definition: DatabaseTest.php:320
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:3060
MediaWikiTestCase
Definition: MediaWikiTestCase.php:13
DatabaseTest\testStoredFunctions
testStoredFunctions()
Definition: DatabaseTest.php:180
$IP
$IP
Definition: update.php:3
$wgSharedPrefix
$wgSharedPrefix
Definition: DefaultSettings.php:1882
DatabaseTest\testTransactionResolution
testTransactionResolution()
Definition: DatabaseTest.php:244
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
DB_MASTER
const DB_MASTER
Definition: defines.php:26
$e
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException' returning false will NOT prevent logging $e
Definition: hooks.txt:2122
MediaWikiTestCase\dbPrefix
dbPrefix()
Definition: MediaWikiTestCase.php:919
DatabaseTest\testTransactionListener
testTransactionListener()
Database::setTransactionListener()
Definition: DatabaseTest.php:273
$ret
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:1956
DatabaseTest\testFlushSnapshot
testFlushSnapshot()
Database::flushSnapshot()
Definition: DatabaseTest.php:305
DatabaseTest\testTransactionIdle
testTransactionIdle()
Definition: DatabaseTest.php:206
DatabaseTest\tearDown
tearDown()
Definition: DatabaseTest.php:22
DatabaseTest\testMutators
testMutators()
Database::tablePrefix() Database::dbSchema()
Definition: DatabaseTest.php:398
DatabaseTest
Database Database.
Definition: DatabaseTest.php:9
DatabaseTest\testAddQuotesStringQuote
testAddQuotesStringQuote()
Definition: DatabaseTest.php:63
MediaWikiTestCase\assertType
assertType( $type, $actual, $message='')
Asserts the type of the provided value.
Definition: MediaWikiTestCase.php:1605
DatabaseTest\getSharedTableName
getSharedTableName( $table, $database, $prefix, $format='quoted')
Definition: DatabaseTest.php:73
DatabaseTest\testTableNameShared
testTableNameShared()
Definition: DatabaseTest.php:142