*/ public static function accessorProvider() { return [ 'thresholds' => ['get_allowed_thresholds'], 'logs' => ['get_allowed_threshold_logs'], ]; } /** * @dataProvider accessorProvider * * @param string $function * * @return void */ public function testGraphIdIsBoundRatherThanInterpolated($function): void { $total = 0; $function('', 'td.name', '', $total, -1, 42); $call = CactiStubs::callsTo('db_fetch_assoc_prepared')[0]; $this->assertStringContainsString('gl.id = ?', $call['sql']); $this->assertStringNotContainsString('42', $call['sql']); $this->assertSame([42], $call['params']); } /** * A caller injecting SQL through $graph_id must end up with the payload as * an inert bound value, never as query text. * * @dataProvider accessorProvider * * @param string $function * * @return void */ public function testMaliciousGraphIdNeverReachesQueryText($function): void { $payload = '1 UNION SELECT password FROM user_auth'; $total = 0; $function('', 'td.name', '', $total, -1, $payload); foreach (CactiStubs::$calls as $call) { $this->assertStringNotContainsString('UNION', $call['sql']); } } /** * The $graph_id placeholder is appended after the caller's fragment, so the * caller's own values have to come first in $sql_params for the binding to * line up. * * @dataProvider accessorProvider * * @param string $function * * @return void */ public function testCallerParametersAreBoundBeforeTheGraphIdParameter($function): void { $total = 0; $function('td.thold_type = ?', 'td.name', '', $total, -1, 7, [3]); $call = CactiStubs::callsTo('db_fetch_assoc_prepared')[0]; $this->assertSame([3, 7], $call['params']); $this->assertStringContainsString('td.thold_type = ? AND gl.id = ?', $call['sql']); } /** * @dataProvider accessorProvider * * @param string $function * * @return void */ public function testNoWhereClauseIsEmittedWhenNothingFiltersTheQuery($function): void { $total = 0; $function('', 'td.name', '', $total, -1, 0); $call = CactiStubs::callsTo('db_fetch_assoc_prepared')[0]; $this->assertStringNotContainsString('WHERE', $call['sql']); $this->assertSame([], $call['params']); } /** * The row-count query reuses the same WHERE clause, so it has to receive * the same bound values. * * @dataProvider accessorProvider * * @param string $function * * @return void */ public function testRowCountQueryBindsTheSameParameters($function): void { $total = 0; $function('td.thold_type = ?', 'td.name', '', $total, -1, 7, [3]); $count = CactiStubs::callsTo('db_fetch_cell_prepared')[0]; $this->assertSame([3, 7], $count['params']); } /** * @dataProvider accessorProvider * * @param string $function * * @return void */ public function testOrderByAndLimitAreAppliedToTheQuery($function): void { $total = 0; $function('', 'td.id DESC', '0,30', $total, -1, 0); $call = CactiStubs::callsTo('db_fetch_assoc_prepared')[0]; $this->assertStringContainsString('ORDER BY td.id DESC', $call['sql']); $this->assertStringContainsString('LIMIT 0,30', $call['sql']); } /** * @dataProvider accessorProvider * * @param string $function * * @return void */ public function testResultRowsAreReturnedToTheCaller($function): void { CactiStubs::willReturn('db_fetch_assoc_prepared', [['id' => 5]]); $total = 0; $rows = $function('', 'td.name', '', $total, -1, 0); $this->assertSame([['id' => 5]], $rows); } /** * @dataProvider accessorProvider * * @param string $function * * @return void */ public function testTotalRowsIsSetByReference($function): void { CactiStubs::willReturn('db_fetch_cell_prepared', 17); $total = 0; $function('', 'td.name', '', $total, -1, 3); $this->assertSame(17, $total); } /** * With authentication on and no session, there is no user to resolve * permissions against, so the query must not run at all. * * @dataProvider accessorProvider * * @param string $function * * @return void */ public function testNoQueryRunsWhenAuthenticationIsOnAndNoUserIsResolved($function): void { CactiStubs::$configOptions['auth_method'] = 1; unset($_SESSION['sess_user_id']); $total = 0; $rows = $function('', 'td.name', '', $total, 0, 0); $this->assertSame([], $rows); $this->assertSame([], CactiStubs::callsTo('db_fetch_assoc_prepared')); } /** * @dataProvider accessorProvider * * @param string $function * * @return void */ public function testPolicyWhereIsAppliedWhenPermissionsAreNotSimple($function): void { CactiStubs::$configOptions['auth_method'] = 1; CactiStubs::willReturn('get_simple_graph_perms', false); CactiStubs::willReturn('get_policy_where', 'WHERE policy_applied = 1'); $_SESSION['sess_user_id'] = 9; $total = 0; $function('', 'td.name', '', $total, 0, 0); unset($_SESSION['sess_user_id']); $call = CactiStubs::callsTo('db_fetch_assoc_prepared')[0]; $this->assertStringContainsString('policy_applied = 1', $call['sql']); } }