| Server IP : 3.96.16.70 / Your IP : 216.73.216.15 Web Server : Apache System : Linux ip-172-31-26-103.ca-central-1.compute.internal 6.1.163-186.299.amzn2023.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Feb 24 16:35:42 UTC 2026 x86_64 User : ec2-user ( 1000) PHP Version : 8.4.18 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/html/prod1.wondermakr.com/phpmyadmin/test/classes/ |
Upload File : |
<?php
declare(strict_types=1);
namespace PhpMyAdmin\Tests;
use PhpMyAdmin\Cache;
use PhpMyAdmin\ConfigStorage\RelationParameters;
use PhpMyAdmin\DatabaseInterface;
use PhpMyAdmin\Tests\Stubs\DummyResult;
use PhpMyAdmin\Tracker;
use PhpMyAdmin\Util;
use ReflectionMethod;
/**
* @covers \PhpMyAdmin\Tracker
*/
class TrackerTest extends AbstractTestCase
{
/**
* Setup function for test cases
*/
protected function setUp(): void
{
parent::setUp();
/**
* SET these to avoid undefined index error
*/
$GLOBALS['server'] = 1;
$GLOBALS['cfg']['Server']['tracking_add_drop_table'] = '';
$GLOBALS['cfg']['Server']['tracking_add_drop_view'] = '';
$GLOBALS['cfg']['Server']['tracking_add_drop_database'] = '';
$GLOBALS['cfg']['Server']['tracking_default_statements'] = '';
$GLOBALS['cfg']['Server']['tracking_version_auto_create'] = '';
$GLOBALS['cfg']['Server']['DisableIS'] = false;
$_SESSION['relation'] = [];
$_SESSION['relation'][$GLOBALS['server']] = RelationParameters::fromArray([
'db' => 'pmadb',
'trackingwork' => true,
'tracking' => 'tracking',
])->toArray();
$dbi = $this->getMockBuilder(DatabaseInterface::class)
->disableOriginalConstructor()
->getMock();
$dbi->expects($this->any())->method('escapeString')
->will($this->returnArgument(0));
}
/**
* Test for Tracker::enable
*/
public function testEnabled(): void
{
self::assertFalse(Cache::has(Tracker::TRACKER_ENABLED_CACHE_KEY));
Tracker::enable();
self::assertTrue(Cache::get(Tracker::TRACKER_ENABLED_CACHE_KEY));
}
/**
* Test for Tracker::isActive()
*/
public function testIsActive(): void
{
self::assertFalse(Cache::has(Tracker::TRACKER_ENABLED_CACHE_KEY));
self::assertFalse(Tracker::isActive());
Tracker::enable();
$_SESSION['relation'] = [];
$_SESSION['relation'][$GLOBALS['server']] = RelationParameters::fromArray([])->toArray();
self::assertFalse(Tracker::isActive());
$_SESSION['relation'] = [];
$_SESSION['relation'][$GLOBALS['server']] = RelationParameters::fromArray([
'trackingwork' => true,
'db' => 'pmadb',
'tracking' => 'tracking',
])->toArray();
self::assertTrue(Tracker::isActive());
}
/**
* Test for Tracker::getTableName()
*
* @param string $string String to test against
* @param string $expected Expected Table Name
*
* @dataProvider getTableNameData
*/
public function testGetTableName(string $string, string $expected): void
{
self::assertSame($expected, $this->callFunction(null, Tracker::class, 'getTableName', [$string]));
}
/**
* Data Provider for testGetTableName
*
* @return array Test data
*/
public static function getTableNameData(): array
{
return [
[
'`tbl`;',
'tbl',
],
[
' `pma.table` ',
'table',
],
[
" `pma.table\nfoobar` ",
'table',
],
];
}
/**
* Test for Tracker::isTracked()
*/
public function testIsTracked(): void
{
self::assertFalse(Cache::has(Tracker::TRACKER_ENABLED_CACHE_KEY));
self::assertFalse(Tracker::isTracked('', ''));
Tracker::enable();
$_SESSION['relation'] = [];
$_SESSION['relation'][$GLOBALS['server']] = RelationParameters::fromArray([])->toArray();
self::assertFalse(Tracker::isTracked('', ''));
$_SESSION['relation'] = [];
$_SESSION['relation'][$GLOBALS['server']] = RelationParameters::fromArray([
'trackingwork' => true,
'db' => 'pmadb',
'tracking' => 'tracking',
])->toArray();
self::assertTrue(Tracker::isTracked('pma_test_db', 'pma_test_table'));
self::assertFalse(Tracker::isTracked('pma_test_db', 'pma_test_table2'));
}
/**
* Test for Tracker::getLogComment()
*/
public function testGetLogComment(): void
{
$date = Util::date('Y-m-d H:i:s');
$GLOBALS['cfg']['Server']['user'] = 'pma_test_user';
self::assertSame('# log ' . $date . " pma_test_user\n", Tracker::getLogComment());
}
/**
* Test for Tracker::createVersion()
*
* @requires PHPUnit < 10
*/
public function testCreateVersion(): void
{
$GLOBALS['cfg']['Server']['tracking_add_drop_table'] = true;
$GLOBALS['cfg']['Server']['tracking_add_drop_view'] = true;
$GLOBALS['cfg']['Server']['user'] = 'pma_test_user';
$resultStub = $this->createMock(DummyResult::class);
$dbi = $this->getMockBuilder(DatabaseInterface::class)
->disableOriginalConstructor()
->getMock();
/**
* set up mock objects
* passing null to with() for an argument is equivalent
* to passing $this->anything()
*/
$getColumnsResult = [
[
'Field' => 'field1',
'Type' => 'int(11)',
'Key' => 'PRI',
],
[
'Field' => 'field2',
'Type' => 'text',
'Key' => '',
],
];
$dbi->expects($this->once())->method('getColumns')
->with('pma_test', 'pma_tbl')
->will($this->returnValue($getColumnsResult));
$getIndexesResult = [
[
'Table' => 'pma_tbl',
'Field' => 'field1',
'Key' => 'PRIMARY',
],
];
$dbi->expects($this->once())->method('getTableIndexes')
->with('pma_test', 'pma_tbl')
->will($this->returnValue($getIndexesResult));
$dbi->expects($this->exactly(3))
->method('tryQuery')
->withConsecutive(
["SHOW TABLE STATUS FROM `pma_test` WHERE Name = 'pma_tbl'"],
['USE `pma_test`'],
['SHOW CREATE TABLE `pma_test`.`pma_tbl`']
)
->willReturnOnConsecutiveCalls($resultStub, $resultStub, $resultStub);
$dbi->expects($this->any())->method('query')
->will($this->returnValue($resultStub));
$dbi->expects($this->any())->method('escapeString')
->will($this->returnArgument(0));
$dbi->expects($this->any())->method('getCompatibilities')
->will($this->returnValue([]));
$GLOBALS['dbi'] = $dbi;
self::assertTrue(Tracker::createVersion('pma_test', 'pma_tbl', '1', '11', true));
}
/**
* Test for Tracker::deleteTracking()
*/
public function testDeleteTracking(): void
{
$resultStub = $this->createMock(DummyResult::class);
$dbi = $this->getMockBuilder(DatabaseInterface::class)
->disableOriginalConstructor()
->getMock();
$sql_query = "/*NOTRACK*/\n"
. 'DELETE FROM `pmadb`.`tracking`'
. " WHERE `db_name` = 'testdb'"
. " AND `table_name` = 'testtable'";
$dbi->expects($this->exactly(1))
->method('queryAsControlUser')
->with($sql_query)
->will($this->returnValue($resultStub));
$dbi->expects($this->any())->method('escapeString')
->will($this->returnArgument(0));
$GLOBALS['dbi'] = $dbi;
self::assertTrue(Tracker::deleteTracking('testdb', 'testtable'));
}
/**
* Test for Tracker::createDatabaseVersion()
*/
public function testCreateDatabaseVersion(): void
{
$GLOBALS['cfg']['Server']['tracking_add_drop_table'] = true;
$GLOBALS['cfg']['Server']['tracking_add_drop_view'] = true;
$GLOBALS['cfg']['Server']['user'] = 'pma_test_user';
$resultStub = $this->createMock(DummyResult::class);
$dbi = $this->getMockBuilder(DatabaseInterface::class)
->disableOriginalConstructor()
->getMock();
$expectedMainQuery = '/*NOTRACK*/' . "\n" . 'INSERT INTO `pmadb`.`tracking` (db_name, table_name, version,'
. ' date_created, date_updated, schema_snapshot, schema_sql, data_sql, tracking)'
. ' values (\'pma_test\', \'\', \'1\', \'%d-%d-%d %d:%d:%d\', \'%d-%d-%d %d:%d:%d\','
. ' \'\', \'# log %d-%d-%d %d:%d:%d pma_test_user' . "\n" . 'SHOW DATABASES\', \'' . "\n"
. '\', \'CREATE DATABASE,ALTER DATABASE,DROP DATABASE\')';
$dbi->expects($this->exactly(1))
->method('queryAsControlUser')
->with($this->matches($expectedMainQuery))
->will($this->returnValue($resultStub));
$dbi->expects($this->any())->method('escapeString')
->will($this->returnArgument(0));
$GLOBALS['dbi'] = $dbi;
self::assertTrue(Tracker::createDatabaseVersion('pma_test', '1', 'SHOW DATABASES'));
}
/**
* Test for Tracker::changeTracking(). This test is also invoked by two
* other tests: testActivateTracking() and testDeactivateTracking()
*
* @param string $dbname Database name
* @param string $tablename Table name
* @param string $version Version
* @param string|int $new_state State to change to
* @param string $type Type of test
*/
public function testChangeTracking(
string $dbname = 'pma_db',
string $tablename = 'pma_tbl',
string $version = '0.1',
$new_state = '1',
?string $type = null
): void {
$dbi = $this->getMockBuilder(DatabaseInterface::class)
->disableOriginalConstructor()
->getMock();
$resultStub = $this->createMock(DummyResult::class);
$sql_query = 'UPDATE `pmadb`.`tracking` SET `tracking_active` = ' .
"'" . $new_state . "'" .
" WHERE `db_name` = '" . $dbname . "'" .
" AND `table_name` = '" . $tablename . "'" .
" AND `version` = '" . $version . "'";
$dbi->expects($this->exactly(1))
->method('queryAsControlUser')
->with($sql_query)
->will($this->returnValue($resultStub));
$dbi->expects($this->any())->method('escapeString')
->will($this->returnArgument(0));
$GLOBALS['dbi'] = $dbi;
if ($type === null) {
$method = new ReflectionMethod(Tracker::class, 'changeTracking');
$method->setAccessible(true);
$method->invoke(null, $dbname, $tablename, $version, $new_state);
} elseif ($type === 'activate') {
Tracker::activateTracking($dbname, $tablename, $version);
} elseif ($type === 'deactivate') {
Tracker::deactivateTracking($dbname, $tablename, $version);
}
// What's the success criteria? What is the expected result?
}
/**
* Test for Tracker::testChangeTrackingData()
*/
public function testChangeTrackingData(): void
{
self::assertFalse(Tracker::changeTrackingData('', '', '', '', ''));
$dbi = $this->getMockBuilder(DatabaseInterface::class)
->disableOriginalConstructor()
->getMock();
$sql_query_1 = 'UPDATE `pmadb`.`tracking`' .
" SET `schema_sql` = '# new_data_processed'" .
" WHERE `db_name` = 'pma_db'" .
" AND `table_name` = 'pma_table'" .
" AND `version` = '1.0'";
$date = Util::date('Y-m-d H:i:s');
$new_data = [
[
'username' => 'user1',
'statement' => 'test_statement1',
],
[
'username' => 'user2',
'statement' => 'test_statement2',
],
];
$sql_query_2 = 'UPDATE `pmadb`.`tracking`' .
" SET `data_sql` = '# log " . $date . " user1test_statement1\n" .
'# log ' . $date . " user2test_statement2\n'" .
" WHERE `db_name` = 'pma_db'" .
" AND `table_name` = 'pma_table'" .
" AND `version` = '1.0'";
$resultStub1 = $this->createMock(DummyResult::class);
$resultStub2 = $this->createMock(DummyResult::class);
$dbi->method('queryAsControlUser')
->will(
$this->returnValueMap(
[
[
$sql_query_1,
$resultStub1,
],
[
$sql_query_2,
$resultStub2,
],
]
)
);
$dbi->expects($this->any())->method('escapeString')
->will($this->returnArgument(0));
$GLOBALS['dbi'] = $dbi;
self::assertTrue(Tracker::changeTrackingData(
'pma_db',
'pma_table',
'1.0',
'DDL',
'# new_data_processed'
));
self::assertTrue(Tracker::changeTrackingData(
'pma_db',
'pma_table',
'1.0',
'DML',
$new_data
));
}
/**
* Test for Tracker::activateTracking()
*/
public function testActivateTracking(): void
{
$this->testChangeTracking('pma_db', 'pma_tbl', '0.1', 1, 'activate');
}
/**
* Test for Tracker::deactivateTracking()
*/
public function testDeactivateTracking(): void
{
$this->testChangeTracking('pma_db', 'pma_tbl', '0.1', '0', 'deactivate');
}
/**
* Test for PMA_Tracker::getTrackedData()
*
* @param array $fetchArrayReturn Value to be returned by mocked fetchArray
* @param array $expectedArray Expected array
*
* @dataProvider getTrackedDataProvider
*/
public function testGetTrackedData(array $fetchArrayReturn, array $expectedArray): void
{
$resultStub = $this->createMock(DummyResult::class);
$dbi = $this->getMockBuilder(DatabaseInterface::class)
->disableOriginalConstructor()
->getMock();
$dbi->expects($this->once())
->method('queryAsControlUser')
->will($this->returnValue($resultStub));
$resultStub->expects($this->once())
->method('fetchAssoc')
->will($this->returnValue($fetchArrayReturn));
$dbi->expects($this->any())
->method('escapeString')
->will(
$this->returnValueMap(
[
[
"pma'db",
"pma\'db",
],
[
"pma'table",
"pma\'table",
],
[
'1.0',
'1.0',
],
]
)
);
$GLOBALS['dbi'] = $dbi;
$result = Tracker::getTrackedData("pma'db", "pma'table", '1.0');
self::assertEquals($expectedArray, $result);
}
/**
* Data provider for testGetTrackedData
*
* @return array Test data
*/
public static function getTrackedDataProvider(): array
{
$fetchArrayReturn = [
[
'schema_sql' => "# log 20-03-2013 23:33:58 user1\nstat1" .
"# log 20-03-2013 23:39:58 user2\n",
'data_sql' => '# log ',
'schema_snapshot' => 'dataschema',
'tracking' => 'SELECT, DELETE',
],
];
$data = [
[
'date_from' => '20-03-2013 23:33:58',
'date_to' => '20-03-2013 23:39:58',
'ddlog' => [
[
'date' => '20-03-2013 23:33:58',
'username' => 'user1',
'statement' => "\nstat1",
],
[
'date' => '20-03-2013 23:39:58',
'username' => 'user2',
'statement' => '',
],
],
'dmlog' => [],
'schema_snapshot' => 'dataschema',
'tracking' => 'SELECT, DELETE',
],
];
$fetchArrayReturn[1] = [
'schema_sql' => "# log 20-03-2012 23:33:58 user1\n" .
"# log 20-03-2012 23:39:58 user2\n",
'data_sql' => "# log 20-03-2013 23:33:58 user3\n" .
"# log 20-03-2013 23:39:58 user4\n",
'schema_snapshot' => 'dataschema',
'tracking' => 'SELECT, DELETE',
];
$data[1] = [
'date_from' => '20-03-2012 23:33:58',
'date_to' => '20-03-2013 23:39:58',
'ddlog' => [
[
'date' => '20-03-2012 23:33:58',
'username' => 'user1',
'statement' => '',
],
[
'date' => '20-03-2012 23:39:58',
'username' => 'user2',
'statement' => '',
],
],
'dmlog' => [
[
'date' => '20-03-2013 23:33:58',
'username' => 'user3',
'statement' => '',
],
[
'date' => '20-03-2013 23:39:58',
'username' => 'user4',
'statement' => '',
],
],
'schema_snapshot' => 'dataschema',
'tracking' => 'SELECT, DELETE',
];
return [
[
$fetchArrayReturn[0],
$data[0],
],
[
$fetchArrayReturn[1],
$data[1],
],
];
}
/**
* Test for Tracker::parseQuery
*
* @param string $query Query to parse
* @param string $type Expected type
* @param string $identifier Expected identifier
* @param string|null $tablename Expected tablename
* @param string|null $db Expected dbname
* @param string|null $tablename_after_rename Expected name after rename
*
* @dataProvider parseQueryData
*/
public function testParseQuery(
string $query,
string $type,
string $identifier,
?string $tablename,
?string $db = null,
?string $tablename_after_rename = null
): void {
$result = Tracker::parseQuery($query);
self::assertSame($type, $result['type']);
self::assertSame($identifier, $result['identifier']);
self::assertSame($tablename, $result['tablename']);
if ($db) {
self::assertSame($db, $GLOBALS['db']);
}
if (! $tablename_after_rename) {
return;
}
self::assertSame($result['tablename_after_rename'], $tablename_after_rename);
}
/**
* Data provider for testParseQuery
*
* @return array Test data
*/
public static function parseQueryData(): array
{
// query
// type
// identifier
// table name
// db (optional)
// table name after rename (optional)
$query = [];
/* TODO: Should test fail when USE is in conjunction with * identifiers?
$query[] = array(
" - USE db1;\n- CREATE VIEW db1.v AS SELECT * FROM t;",
"DDL",
"CREATE VIEW",
"v",
"db1"
);
*/
$query[] = [
'CREATE VIEW v AS SELECT * FROM t;',
'DDL',
'CREATE VIEW',
'v',
];
$query[] = [
'ALTER VIEW db1.v AS SELECT col1, col2, col3, col4 FROM t',
'DDL',
'ALTER VIEW',
'v',
];
$query[] = [
'DROP VIEW db1.v;',
'DDL',
'DROP VIEW',
'v',
];
$query[] = [
'DROP VIEW IF EXISTS db1.v;',
'DDL',
'DROP VIEW',
'v',
];
$query[] = [
'CREATE DATABASE db1;',
'DDL',
'CREATE DATABASE',
'',
'db1',
];
$query[] = [
'ALTER DATABASE db1;',
'DDL',
'ALTER DATABASE',
'',
];
$query[] = [
'DROP DATABASE db1;',
'DDL',
'DROP DATABASE',
'',
'db1',
];
$query[] = [
'CREATE TABLE db1.t1 (c1 INT);',
'DDL',
'CREATE TABLE',
't1',
];
$query[] = [
'ALTER TABLE db1.t1 ADD c2 TEXT;',
'DDL',
'ALTER TABLE',
't1',
];
$query[] = [
'DROP TABLE db1.t1',
'DDL',
'DROP TABLE',
't1',
];
$query[] = [
'DROP TABLE IF EXISTS db1.t1',
'DDL',
'DROP TABLE',
't1',
];
$query[] = [
'CREATE INDEX ind ON db1.t1 (c2(10));',
'DDL',
'CREATE INDEX',
't1',
];
$query[] = [
'CREATE UNIQUE INDEX ind ON db1.t1 (c2(10));',
'DDL',
'CREATE INDEX',
't1',
];
$query[] = [
'CREATE SPATIAL INDEX ind ON db1.t1 (c2(10));',
'DDL',
'CREATE INDEX',
't1',
];
$query[] = [
'DROP INDEX ind ON db1.t1;',
'DDL',
'DROP INDEX',
't1',
];
$query[] = [
'RENAME TABLE db1.t1 TO db1.t2',
'DDL',
'RENAME TABLE',
't1',
'',
't2',
];
$query[] = [
'UPDATE db1.t1 SET a = 2',
'DML',
'UPDATE',
't1',
];
$query[] = [
'INSERT INTO db1.t1 (a, b, c) VALUES(1, 2, 3)',
'DML',
'INSERT',
't1',
];
$query[] = [
'DELETE FROM db1.t1',
'DML',
'DELETE',
't1',
];
$query[] = [
'TRUNCATE db1.t1',
'DML',
'TRUNCATE',
't1',
];
$query[] = [
'create table event(' . "\n"
. 'eventID varchar(10) not null,' . "\n"
. 'b char(30),' . "\n"
. 'c varchar(20),' . "\n"
. 'd TIME,' . "\n"
. 'e Date,' . "\n"
. 'f int,' . "\n"
. 'g char(70),' . "\n"
. 'h char(90),' . "\n"
. 'primary key(eventID)' . "\n"
. ')' . "\n",
'DDL',
'CREATE TABLE',
null,// switch this to 'event' when sql-parse is fixed
];
return $query;
}
}