From 431450a23752752cda8b88ccc39829ab09888a13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 3 Feb 2016 18:59:17 +0100 Subject: [PATCH 1/3] Make test run even without runkit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- libraries/core.lib.php | 4 ++ libraries/plugins/auth/AuthenticationHttp.php | 12 ++-- .../plugin/auth/AuthenticationHttpTest.php | 70 ++++++++++--------- 3 files changed, 47 insertions(+), 39 deletions(-) diff --git a/libraries/core.lib.php b/libraries/core.lib.php index de55573192..f4bd9e1396 100644 --- a/libraries/core.lib.php +++ b/libraries/core.lib.php @@ -488,6 +488,10 @@ function PMA_getenv($var_name) */ function PMA_sendHeaderLocation($uri, $use_refresh = false) { + if (defined('TESTSUITE') && ! defined('PMA_TEST_HEADERS')) { + return; + } + if (PMA_IS_IIS && mb_strlen($uri) > 600) { include_once './libraries/js_escape.lib.php'; PMA\libraries\Response::getInstance()->disable(); diff --git a/libraries/plugins/auth/AuthenticationHttp.php b/libraries/plugins/auth/AuthenticationHttp.php index 065b39d405..b693bd5869 100644 --- a/libraries/plugins/auth/AuthenticationHttp.php +++ b/libraries/plugins/auth/AuthenticationHttp.php @@ -72,11 +72,13 @@ class AuthenticationHttp extends AuthenticationPlugin $realm_message = $GLOBALS['cfg']['Server']['auth_http_realm']; } // remove non US-ASCII to respect RFC2616 - $realm_message = preg_replace('/[^\x20-\x7e]/i', '', $realm_message); - header('WWW-Authenticate: Basic realm="' . $realm_message . '"'); - header('HTTP/1.0 401 Unauthorized'); - if (php_sapi_name() !== 'cgi-fcgi') { - header('status: 401 Unauthorized'); + if (! defined('TESTSUITE') || defined('PMA_TEST_HEADERS')) { + $realm_message = preg_replace('/[^\x20-\x7e]/i', '', $realm_message); + header('WWW-Authenticate: Basic realm="' . $realm_message . '"'); + header('HTTP/1.0 401 Unauthorized'); + if (php_sapi_name() !== 'cgi-fcgi') { + header('status: 401 Unauthorized'); + } } /* HTML header */ diff --git a/test/classes/plugin/auth/AuthenticationHttpTest.php b/test/classes/plugin/auth/AuthenticationHttpTest.php index 8fe2818a99..1498d054c6 100644 --- a/test/classes/plugin/auth/AuthenticationHttpTest.php +++ b/test/classes/plugin/auth/AuthenticationHttpTest.php @@ -58,12 +58,6 @@ class AuthenticationHttpTest extends PMATestCase */ public function testAuth() { - if (! defined('PMA_TEST_HEADERS')) { - $this->markTestSkipped( - 'Cannot redefine constant/function - missing runkit extension' - ); - } - $_REQUEST['old_usr'] = '1'; $GLOBALS['cfg']['Server']['LogoutURL'] = 'http://phpmyadmin.net/logout'; @@ -71,10 +65,12 @@ class AuthenticationHttpTest extends PMATestCase $this->object->auth() ); - $this->assertContains( - 'Location: http://phpmyadmin.net/logout', - $GLOBALS['header'][0] - ); + if (defined('PMA_TEST_HEADERS')) { + $this->assertContains( + 'Location: http://phpmyadmin.net/logout', + $GLOBALS['header'][0] + ); + } // case 2 @@ -143,14 +139,16 @@ class AuthenticationHttpTest extends PMATestCase $this->object->auth() ); - $this->assertEquals( - array( - 'WWW-Authenticate: Basic realm="phpMyAdmin verboseMessag"', - 'HTTP/1.0 401 Unauthorized', - 'status: 401 Unauthorized' - ), - $GLOBALS['header'] - ); + if (defined('PMA_TEST_HEADERS')) { + $this->assertEquals( + array( + 'WWW-Authenticate: Basic realm="phpMyAdmin verboseMessag"', + 'HTTP/1.0 401 Unauthorized', + 'status: 401 Unauthorized' + ), + $GLOBALS['header'] + ); + } $attrInstance->setValue($restoreInstance); @@ -163,14 +161,16 @@ class AuthenticationHttpTest extends PMATestCase $this->object->auth() ); - $this->assertEquals( - array( - 'WWW-Authenticate: Basic realm="phpMyAdmin hst"', - 'HTTP/1.0 401 Unauthorized', - 'status: 401 Unauthorized' - ), - $GLOBALS['header'] - ); + if (defined('PMA_TEST_HEADERS')) { + $this->assertEquals( + array( + 'WWW-Authenticate: Basic realm="phpMyAdmin hst"', + 'HTTP/1.0 401 Unauthorized', + 'status: 401 Unauthorized' + ), + $GLOBALS['header'] + ); + } // case 4 @@ -181,14 +181,16 @@ class AuthenticationHttpTest extends PMATestCase $this->object->auth() ); - $this->assertEquals( - array( - 'WWW-Authenticate: Basic realm="realmmessage"', - 'HTTP/1.0 401 Unauthorized', - 'status: 401 Unauthorized' - ), - $GLOBALS['header'] - ); + if (defined('PMA_TEST_HEADERS')) { + $this->assertEquals( + array( + 'WWW-Authenticate: Basic realm="realmmessage"', + 'HTTP/1.0 401 Unauthorized', + 'status: 401 Unauthorized' + ), + $GLOBALS['header'] + ); + } } /** From ca9fbec4c2ec21964d48791d37162aa846889115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 3 Feb 2016 19:14:54 +0100 Subject: [PATCH 2/3] Use newer phpunit (for withConsecutive) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Čihař --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2de9a8621d..8747b47e78 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ }, "require-dev": { "satooshi/php-coveralls": "~0.6", - "phpunit/phpunit": "~3.7", + "phpunit/phpunit": "~4.1", "codacy/coverage": "dev-master", "phpunit/phpunit-selenium": "~1.2", "squizlabs/php_codesniffer": "2.*" From c2b41b829a10a5a6ff838f83c340620e4825c4cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 3 Feb 2016 19:48:18 +0100 Subject: [PATCH 3/3] Wrap header() and headers_sent() in response MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows us to test the code without using runkit. Currenly only AuthenticationHttp is migrated to new code, but others will follow. Signed-off-by: Michal Čihař --- libraries/Response.php | 21 ++- libraries/core.lib.php | 18 +-- libraries/plugins/auth/AuthenticationHttp.php | 16 +- .../plugin/auth/AuthenticationHttpTest.php | 148 +++++++++--------- 4 files changed, 106 insertions(+), 97 deletions(-) diff --git a/libraries/Response.php b/libraries/Response.php index dc37f6701f..f66982da3a 100644 --- a/libraries/Response.php +++ b/libraries/Response.php @@ -389,5 +389,24 @@ class Response $buffer->flush(); exit; } -} + /** + * Wrapper around PHP's header() function. + * + * @return void + */ + public function header($text) + { + header($text); + } + + /** + * Wrapper around PHP's headers_sent() function. + * + * @return bool + */ + public function headersSent() + { + return headers_sent(); + } +} diff --git a/libraries/core.lib.php b/libraries/core.lib.php index f4bd9e1396..1acd47ffa9 100644 --- a/libraries/core.lib.php +++ b/libraries/core.lib.php @@ -488,10 +488,6 @@ function PMA_getenv($var_name) */ function PMA_sendHeaderLocation($uri, $use_refresh = false) { - if (defined('TESTSUITE') && ! defined('PMA_TEST_HEADERS')) { - return; - } - if (PMA_IS_IIS && mb_strlen($uri) > 600) { include_once './libraries/js_escape.lib.php'; PMA\libraries\Response::getInstance()->disable(); @@ -502,21 +498,23 @@ function PMA_sendHeaderLocation($uri, $use_refresh = false) return; } + $response = PMA\libraries\Response::getInstance(); + if (SID) { if (mb_strpos($uri, '?') === false) { - header('Location: ' . $uri . '?' . SID); + $response->header('Location: ' . $uri . '?' . SID); } else { $separator = PMA_URL_getArgSeparator(); - header('Location: ' . $uri . $separator . SID); + $response->header('Location: ' . $uri . $separator . SID); } return; } session_write_close(); - if (headers_sent()) { + if ($response->headersSent()) { if (function_exists('debug_print_backtrace')) { echo '
';
-            debug_print_backtrace();
+#            debug_print_backtrace();
             echo '
'; } trigger_error( @@ -528,9 +526,9 @@ function PMA_sendHeaderLocation($uri, $use_refresh = false) // results in a blank page // but we need it when coming from the cookie login panel) if (PMA_IS_IIS && $use_refresh) { - header('Refresh: 0; ' . $uri); + $response->header('Refresh: 0; ' . $uri); } else { - header('Location: ' . $uri); + $response->header('Location: ' . $uri); } } diff --git a/libraries/plugins/auth/AuthenticationHttp.php b/libraries/plugins/auth/AuthenticationHttp.php index b693bd5869..170d7c1e0e 100644 --- a/libraries/plugins/auth/AuthenticationHttp.php +++ b/libraries/plugins/auth/AuthenticationHttp.php @@ -71,18 +71,18 @@ class AuthenticationHttp extends AuthenticationPlugin } else { $realm_message = $GLOBALS['cfg']['Server']['auth_http_realm']; } + + $response = Response::getInstance(); + // remove non US-ASCII to respect RFC2616 - if (! defined('TESTSUITE') || defined('PMA_TEST_HEADERS')) { - $realm_message = preg_replace('/[^\x20-\x7e]/i', '', $realm_message); - header('WWW-Authenticate: Basic realm="' . $realm_message . '"'); - header('HTTP/1.0 401 Unauthorized'); - if (php_sapi_name() !== 'cgi-fcgi') { - header('status: 401 Unauthorized'); - } + $realm_message = preg_replace('/[^\x20-\x7e]/i', '', $realm_message); + $response->header('WWW-Authenticate: Basic realm="' . $realm_message . '"'); + $response->header('HTTP/1.0 401 Unauthorized'); + if (php_sapi_name() !== 'cgi-fcgi') { + $response->header('status: 401 Unauthorized'); } /* HTML header */ - $response = Response::getInstance(); $footer = $response->getFooter(); $footer->setMinimal(); $header = $response->getHeader(); diff --git a/test/classes/plugin/auth/AuthenticationHttpTest.php b/test/classes/plugin/auth/AuthenticationHttpTest.php index 1498d054c6..20e5b81b33 100644 --- a/test/classes/plugin/auth/AuthenticationHttpTest.php +++ b/test/classes/plugin/auth/AuthenticationHttpTest.php @@ -51,29 +51,8 @@ class AuthenticationHttpTest extends PMATestCase unset($this->object); } - /** - * Test for PMA\libraries\plugins\auth\AuthenticationHttp::auth - * - * @return void - */ - public function testAuth() + public function doMockResponse($set_minimal, $body_id, $set_title) { - $_REQUEST['old_usr'] = '1'; - $GLOBALS['cfg']['Server']['LogoutURL'] = 'http://phpmyadmin.net/logout'; - - $this->assertFalse( - $this->object->auth() - ); - - if (defined('PMA_TEST_HEADERS')) { - $this->assertContains( - 'Location: http://phpmyadmin.net/logout', - $GLOBALS['header'][0] - ); - } - - // case 2 - $restoreInstance = PMA\libraries\Response::getInstance(); // mock footer @@ -82,7 +61,7 @@ class AuthenticationHttpTest extends PMATestCase ->setMethods(array('setMinimal')) ->getMock(); - $mockFooter->expects($this->once()) + $mockFooter->expects($this->exactly($set_minimal)) ->method('setMinimal') ->with(); @@ -95,35 +74,40 @@ class AuthenticationHttpTest extends PMATestCase ) ->getMock(); - $mockHeader->expects($this->once()) + $mockHeader->expects($this->exactly($body_id)) ->method('setBodyId') ->with('loginform'); - $mockHeader->expects($this->once()) + $mockHeader->expects($this->exactly($set_title)) ->method('setTitle') ->with('Access denied!'); - $mockHeader->expects($this->once()) + $mockHeader->expects($this->exactly($set_title)) ->method('disableMenuAndConsole') ->with(); // set mocked headers and footers $mockResponse = $this->getMockBuilder('PMA\libraries\Response') ->disableOriginalConstructor() - ->setMethods(array('getHeader', 'getFooter', 'addHTML')) + ->setMethods(array('getHeader', 'getFooter', 'addHTML', 'header', 'headersSent')) ->getMock(); - $mockResponse->expects($this->once()) + $mockResponse->expects($this->exactly($set_title)) ->method('getFooter') ->with() ->will($this->returnValue($mockFooter)); - $mockResponse->expects($this->once()) + $mockResponse->expects($this->exactly($set_title)) ->method('getHeader') ->with() ->will($this->returnValue($mockHeader)); - $mockResponse->expects($this->exactly(6)) + $mockResponse->expects($this->any()) + ->method('headersSent') + ->with() + ->will($this->returnValue(false)); + + $mockResponse->expects($this->exactly($set_title * 6)) ->method('addHTML') ->with(); @@ -131,66 +115,74 @@ class AuthenticationHttpTest extends PMATestCase $attrInstance->setAccessible(true); $attrInstance->setValue($mockResponse); - $GLOBALS['header'] = array(); + $headers = array_slice(func_get_args(), 3); + + $header_method = $mockResponse->expects($this->exactly(count($headers))) + ->method('header'); + + call_user_func_array(array($header_method, 'withConsecutive'), $headers); + + $this->assertFalse( + $this->object->auth() + ); + + $attrInstance->setValue($restoreInstance); + } + + /** + * Test for PMA\libraries\plugins\auth\AuthenticationHttp::auth + * + * @return void + */ + public function testAuthLogoutUrl() + { + + $_REQUEST['old_usr'] = '1'; + $GLOBALS['cfg']['Server']['LogoutURL'] = 'http://phpmyadmin.net/logout'; + + $this->doMockResponse( + 0, 0, 0, + array('Location: http://phpmyadmin.net/logout') + ); + } + + public function testAuthVerbose() + { $_REQUEST['old_usr'] = ''; $GLOBALS['cfg']['Server']['verbose'] = 'verboseMessagê'; - $this->assertFalse( - $this->object->auth() + $this->doMockResponse( + 1, 1, 1, + array('WWW-Authenticate: Basic realm="phpMyAdmin verboseMessag"'), + array('HTTP/1.0 401 Unauthorized'), + array('status: 401 Unauthorized') ); + } - if (defined('PMA_TEST_HEADERS')) { - $this->assertEquals( - array( - 'WWW-Authenticate: Basic realm="phpMyAdmin verboseMessag"', - 'HTTP/1.0 401 Unauthorized', - 'status: 401 Unauthorized' - ), - $GLOBALS['header'] - ); - } - - $attrInstance->setValue($restoreInstance); - - // case 3 - - $GLOBALS['header'] = array(); + public function testAuthHost() + { $GLOBALS['cfg']['Server']['verbose'] = ''; $GLOBALS['cfg']['Server']['host'] = 'hòst'; - $this->assertFalse( - $this->object->auth() + + $this->doMockResponse( + 1, 1, 1, + array('WWW-Authenticate: Basic realm="phpMyAdmin hst"'), + array('HTTP/1.0 401 Unauthorized'), + array('status: 401 Unauthorized') ); + } - if (defined('PMA_TEST_HEADERS')) { - $this->assertEquals( - array( - 'WWW-Authenticate: Basic realm="phpMyAdmin hst"', - 'HTTP/1.0 401 Unauthorized', - 'status: 401 Unauthorized' - ), - $GLOBALS['header'] - ); - } - - // case 4 - - $GLOBALS['header'] = array(); + public function testAuthRealm() + { $GLOBALS['cfg']['Server']['host'] = ''; $GLOBALS['cfg']['Server']['auth_http_realm'] = 'rêäealmmessage'; - $this->assertFalse( - $this->object->auth() - ); - if (defined('PMA_TEST_HEADERS')) { - $this->assertEquals( - array( - 'WWW-Authenticate: Basic realm="realmmessage"', - 'HTTP/1.0 401 Unauthorized', - 'status: 401 Unauthorized' - ), - $GLOBALS['header'] - ); - } + $this->doMockResponse( + 1, 1, 1, + array('WWW-Authenticate: Basic realm="realmmessage"'), + array('HTTP/1.0 401 Unauthorized'), + array('status: 401 Unauthorized') + ); } /**