Commit 7afeeebc authored by catch's avatar catch
Browse files

Issue #2585165 by pwolanin, alexpott, tarekdj, geertvd, dawehner, greggles:...

Issue #2585165 by pwolanin, alexpott, tarekdj, geertvd, dawehner, greggles: Don't include vendor test code (especially mink) in the Drupal webroot
parent b0e82e58
......@@ -37,6 +37,8 @@
},
"scripts": {
"pre-autoload-dump": "Drupal\\Core\\Composer\\Composer::preAutoloadDump",
"post-autoload-dump": "Drupal\\Core\\Composer\\Composer::ensureHtaccess"
"post-autoload-dump": "Drupal\\Core\\Composer\\Composer::ensureHtaccess",
"post-package-install": "Drupal\\Core\\Composer\\Composer::vendorTestCodeCleanup",
"post-package-update": "Drupal\\Core\\Composer\\Composer::vendorTestCodeCleanup"
}
}
......@@ -9,6 +9,7 @@
use Drupal\Component\PhpStorage\FileStorage;
use Composer\Script\Event;
use Composer\Installer\PackageEvent;
/**
* Provides static functions for composer script events.
......@@ -17,6 +18,55 @@
*/
class Composer {
protected static $packageToCleanup = [
'behat/mink' => ['tests', 'driver-testsuite'],
'behat/mink-browserkit-driver' => ['tests'],
'behat/mink-goutte-driver' => ['tests'],
'doctrine/cache' => ['tests'],
'doctrine/collections' => ['tests'],
'doctrine/common' => ['tests'],
'doctrine/inflector' => ['tests'],
'doctrine/instantiator' => ['tests'],
'egulias/email-validator' => ['documentation', 'tests'],
'fabpot/goutte' => ['Goutte/Tests'],
'guzzlehttp/promises' => ['tests'],
'guzzlehttp/psr7' => ['tests'],
'masterminds/html5' => ['test'],
'mikey179/vfsStream' => ['src/test'],
'phpdocumentor/reflection-docblock' => ['tests'],
'phpunit/php-code-coverage' => ['tests'],
'phpunit/php-timer' => ['tests'],
'phpunit/php-token-stream' => ['tests'],
'phpunit/phpunit' => ['tests'],
'phpunit/php-mock-objects' => ['tests'],
'sebastian/comparator' => ['tests'],
'sebastian/diff' => ['tests'],
'sebastian/environment' => ['tests'],
'sebastian/exporter' => ['tests'],
'sebastian/global-state' => ['tests'],
'sebastian/recursion-context' => ['tests'],
'stack/builder' => ['tests'],
'symfony/browser-kit' => ['Tests'],
'symfony/class-loader' => ['Tests'],
'symfony/console' => ['Tests'],
'symfony/css-selector' => ['Tests'],
'symfony/debug' => ['Tests'],
'symfony/dependency-injection' => ['Tests'],
'symfony/dom-crawler' => ['Tests'],
'symfony/event-dispatcher' => ['Tests'],
'symfony/http-foundation' => ['Tests'],
'symfony/http-kernel' => ['Tests'],
'symfony/process' => ['Tests'],
'symfony/psr-http-message-bridge' => ['Tests'],
'symfony/routing' => ['Tests'],
'symfony/serializer' => ['Tests'],
'symfony/translation' => ['Tests'],
'symfony/validator' => ['Tests'],
'symfony/yaml' => ['Tests'],
'symfony-cmf/routing' => ['Test', 'Tests'],
'twig/twig' => ['doc', 'ext', 'test'],
];
/**
* Add vendor classes to composers static classmap.
*/
......@@ -70,4 +120,90 @@ public static function ensureHtaccess(Event $event) {
}
}
/**
* Remove possibly problematic test files from vendored projects.
*
* @param \Composer\Script\Event $event
*/
public static function vendorTestCodeCleanup(PackageEvent $event) {
$vendor_dir = $event->getComposer()->getConfig()->get('vendor-dir');
$op = $event->getOperation();
if ($op->getJobType() == 'update') {
$package = $op->getTargetPackage();
}
else {
$package = $op->getPackage();
}
$package_key = static::findPackageKey($package->getName());
if ($package_key) {
foreach (static::$packageToCleanup[$package_key] as $path) {
$dir_to_remove = $vendor_dir . '/' . $package_key . '/' . $path;
if (is_dir($dir_to_remove)) {
if (!static::deleteRecursive($dir_to_remove)) {
throw new \RuntimeException(sprintf("Failure removing directory '%s' in package '%s'.", $path, $package->getPrettyName()));
}
}
else {
throw new \RuntimeException(sprintf("The directory '%s' in package '%s' does not exist.", $path, $package->getPrettyName()));
}
}
}
}
/**
* Find the array key for a given package name with a case-insensitive search.
*
* @param string $package_name
* The package name from composer. This is always already lower case.
*
* @return NULL|string
* The string key, or NULL if none was found.
*/
protected static function findPackageKey($package_name) {
$package_key = NULL;
// In most cases the package name is already used as the array key.
if (isset(static::$packageToCleanup[$package_name])) {
$package_key = $package_name;
}
else {
// Handle any mismatch in case between the package name and array key.
// For example, the array key 'mikey179/vfsStream' needs to be found
// when composer returns a package name of 'mikey179/vfsstream'.
foreach (static::$packageToCleanup as $key => $dirs) {
if (strtolower($key) === $package_name) {
$package_key = $key;
break;
}
}
}
return $package_key;
}
/**
* Helper method to remove directories and the files they contain.
*
* @param string $path
* The directory or file to remove. It must exist.
*
* @return bool
* TRUE on success or FALSE on failure.
*/
protected static function deleteRecursive($path) {
if (is_file($path) || is_link($path)) {
return unlink($path);
}
$success = TRUE;
$dir = dir($path);
while (($entry = $dir->read()) !== FALSE) {
if ($entry == '.' || $entry == '..') {
continue;
}
$entry_path = $path . '/' . $entry;
$success = static::deleteRecursive($entry_path) && $success;
}
$dir->close();
return rmdir($path) && $success;
}
}
File mode changed from 100755 to 100644
<?php
namespace Behat\Mink\Tests\Driver;
use Behat\Mink\Driver\BrowserKitDriver;
use Symfony\Component\HttpKernel\Client;
class BrowserKitConfig extends AbstractConfig
{
public static function getInstance()
{
return new self();
}
/**
* {@inheritdoc}
*/
public function createDriver()
{
$client = new Client(require(__DIR__.'/app.php'));
return new BrowserKitDriver($client);
}
/**
* {@inheritdoc}
*/
public function getWebFixturesUrl()
{
return 'http://localhost';
}
protected function supportsJs()
{
return false;
}
}
<?php
namespace Behat\Mink\Tests\Driver\Custom;
use Behat\Mink\Driver\BrowserKitDriver;
use Behat\Mink\Session;
use Symfony\Component\HttpKernel\Client;
/**
* @group functional
*/
class BaseUrlTest extends \PHPUnit_Framework_TestCase
{
public function testBaseUrl()
{
$client = new Client(require(__DIR__.'/../app.php'));
$driver = new BrowserKitDriver($client, 'http://localhost/foo/');
$session = new Session($driver);
$session->visit('http://localhost/foo/index.html');
$this->assertEquals(200, $session->getStatusCode());
$this->assertEquals('http://localhost/foo/index.html', $session->getCurrentUrl());
}
}
<?php
namespace Behat\Mink\Tests\Driver\Custom;
use Behat\Mink\Driver\BrowserKitDriver;
use Symfony\Component\BrowserKit\Client;
use Symfony\Component\BrowserKit\Response;
class ErrorHandlingTest extends \PHPUnit_Framework_TestCase
{
/**
* @var TestClient
*/
private $client;
protected function setUp()
{
$this->client = new TestClient();
}
public function testGetClient()
{
$this->assertSame($this->client, $this->getDriver()->getClient());
}
/**
* @expectedException \Behat\Mink\Exception\DriverException
* @expectedExceptionMessage Unable to access the response before visiting a page
*/
public function testGetResponseHeaderWithoutVisit()
{
$this->getDriver()->getResponseHeaders();
}
/**
* @expectedException \Behat\Mink\Exception\DriverException
* @expectedExceptionMessage Unable to access the response content before visiting a page
*/
public function testFindWithoutVisit()
{
$this->getDriver()->find('//html');
}
/**
* @expectedException \Behat\Mink\Exception\DriverException
* @expectedExceptionMessage Unable to access the request before visiting a page
*/
public function testGetCurrentUrlWithoutVisit()
{
$this->getDriver()->getCurrentUrl();
}
/**
* @expectedException \Behat\Mink\Exception\DriverException
* @expectedExceptionMessage The selected node has an invalid form attribute (foo)
*/
public function testNotMatchingHtml5FormId()
{
$html = <<<'HTML'
<html>
<body>
<form id="test">
<input name="test" value="foo" form="foo">
<input type="submit">
</form>
</body>
</html>
HTML;
$this->client->setNextResponse(new Response($html));
$driver = $this->getDriver();
$driver->visit('/index.php');
$driver->setValue('//input[./@name="test"]', 'bar');
}
/**
* @expectedException \Behat\Mink\Exception\DriverException
* @expectedExceptionMessage The selected node has an invalid form attribute (foo)
*/
public function testInvalidHtml5FormId()
{
$html = <<<'HTML'
<html>
<body>
<form id="test">
<input name="test" value="foo" form="foo">
<input type="submit">
</form>
<div id="foo"></div>
</body>
</html>
HTML;
$this->client->setNextResponse(new Response($html));
$driver = $this->getDriver();
$driver->visit('/index.php');
$driver->setValue('//input[./@name="test"]', 'bar');
}
/**
* @expectedException \Behat\Mink\Exception\DriverException
* @expectedExceptionMessage The selected node does not have a form ancestor.
*/
public function testManipulateInputWithoutForm()
{
$html = <<<'HTML'
<html>
<body>
<form id="test">
<input type="submit">
</form>
<div id="foo">
<input name="test" value="foo">
</div>
</body>
</html>
HTML;
$this->client->setNextResponse(new Response($html));
$driver = $this->getDriver();
$driver->visit('/index.php');
$driver->setValue('//input[./@name="test"]', 'bar');
}
/**
* @expectedException \Behat\Mink\Exception\DriverException
* @expectedExceptionMessage Behat\Mink\Driver\BrowserKitDriver supports clicking on links and submit or reset buttons only. But "div" provided
*/
public function testClickOnUnsupportedElement()
{
$html = <<<'HTML'
<html>
<body>
<div></div>
</body>
</html>
HTML;
$this->client->setNextResponse(new Response($html));
$driver = $this->getDriver();
$driver->visit('/index.php');
$driver->click('//div');
}
private function getDriver()
{
return new BrowserKitDriver($this->client);
}
}
class TestClient extends Client
{
protected $nextResponse = null;
protected $nextScript = null;
public function setNextResponse(Response $response)
{
$this->nextResponse = $response;
}
public function setNextScript($script)
{
$this->nextScript = $script;
}
protected function doRequest($request)
{
if (null === $this->nextResponse) {
return new Response();
}
$response = $this->nextResponse;
$this->nextResponse = null;
return $response;
}
}
<?php
namespace app;
$app = new \Silex\Application();
$app->register(new \Silex\Provider\SessionServiceProvider());
$def = realpath(__DIR__.'/../vendor/behat/mink/driver-testsuite/web-fixtures');
$ovr = realpath(__DIR__.'/web-fixtures');
$cbk = function ($file) use ($app, $def, $ovr) {
$file = str_replace('.file', '.php', $file);
$path = file_exists($ovr.'/'.$file) ? $ovr.'/'.$file : $def.'/'.$file;
$resp = null;
ob_start();
include($path);
$content = ob_get_clean();
if ($resp) {
if ('' === $resp->getContent()) {
$resp->setContent($content);
}
return $resp;
}
return $content;
};
$app->get('/{file}', $cbk)->assert('file', '.*');
$app->post('/{file}', $cbk)->assert('file', '.*');
$app['debug'] = true;
$app['exception_handler']->disable();
$app['session.test'] = true;
return $app;
<?php
$resp = new Symfony\Component\HttpFoundation\Response('Sorry, page not found', 404);
<?php
$resp = new Symfony\Component\HttpFoundation\Response('Sorry, a server error happened', 500);
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>Advanced form save</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
</head>
<body>
<?php
error_reporting(0);
$request = $app['request'];
$POST = $request->request->all();
$FILES = $request->files->all();
if (isset($POST['select_multiple_numbers']) && false !== strpos($POST['select_multiple_numbers'][0], ',')) {
$POST['select_multiple_numbers'] = explode(',', $POST['select_multiple_numbers'][0]);
}
// checkbox can have any value and will be successful in case "on"
// http://www.w3.org/TR/html401/interact/forms.html#checkbox
$POST['agreement'] = isset($POST['agreement']) ? 'on' : 'off';
ksort($POST);
echo str_replace('>', '', var_export($POST, true)) . "\n";
if (isset($FILES['about']) && file_exists($FILES['about']->getPathname())) {
echo $FILES['about']->getClientOriginalName() . "\n";
echo file_get_contents($FILES['about']->getPathname());
} else {
echo "no file";
}
?>
</body>
</html>
<?php
$SERVER = $app['request']->server->all();
$username = isset($SERVER['PHP_AUTH_USER']) ? $SERVER['PHP_AUTH_USER'] : false;
$password = isset($SERVER['PHP_AUTH_PW']) ? $SERVER['PHP_AUTH_PW'] : false;
if ($username == 'mink-user' && $password == 'mink-password') {
echo 'is authenticated';
} else {
$resp = new \Symfony\Component\HttpFoundation\Response();
$resp->setStatusCode(401);
$resp->headers->set('WWW-Authenticate', 'Basic realm="Mink Testing Area"');
echo 'is not authenticated';
}
<?php ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>Basic Form Saving</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<h1>Anket for <?php echo $app['request']->request->get('first_name') ?></h1>
<span id="first">Firstname: <?php echo $app['request']->request->get('first_name') ?></span>
<span id="last">Lastname: <?php echo $app['request']->request->get('last_name') ?></span>
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>Basic Get Form</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<h1>Basic Get Form Page</h1>
<div id="serach">
<?php
$GET = $app['request']->query->all();
echo isset($GET['q']) && $GET['q'] ? $GET['q'] : 'No search query'
?>
</div>
<form>
<input name="q" value="" type="text" />
<input type="submit" value="Find" />
</form>
</body>
</html>
<?php
$resp = new Symfony\Component\HttpFoundation\Response();
$cook = new Symfony\Component\HttpFoundation\Cookie('srvr_cookie', 'srv_var_is_set', 0, '/');
$resp->headers->setCookie($cook);
?>
<!doctype html public "-//w3c//dtd xhtml 1.1//en" "http://www.w3.org/tr/xhtml11/dtd/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>basic form</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<script>
</script>
</head>
<body>
basic page with cookie set from server side
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
<title>Basic Form</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<script>
</script>
</head>
<body>
Previous cookie: <?php
echo $app['request']->cookies->has('srvr_cookie') ? $app['request']->cookies->get('srvr_cookie') : 'NO';
?>
</body>
</html>
<?php
$hasCookie = $app['request']->cookies->has('foo');
$resp = new Symfony\Component\HttpFoundation\Response();
$cook = new Symfony\Component\HttpFoundation\Cookie('foo', 'bar');
$resp->headers->setCookie($cook);
?>