From 6ee2ebccb8da4047c2e9184f5adab05fcde89488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Terje=20Br=C3=A5ten?= Date: Tue, 26 Mar 2019 13:04:56 +0000 Subject: [PATCH 1/9] Handle file uploads correct --- src/HttpCall/Request/BrowserKit.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/HttpCall/Request/BrowserKit.php b/src/HttpCall/Request/BrowserKit.php index 959bf8ff..45490521 100644 --- a/src/HttpCall/Request/BrowserKit.php +++ b/src/HttpCall/Request/BrowserKit.php @@ -59,9 +59,13 @@ public function getContent() public function send($method, $url, $parameters = [], $files = [], $content = null, $headers = []) { - foreach ($files as $originalName => &$file) { + $tmpFiles = []; + foreach ($files as $key => &$file) { if (is_string($file)) { - $file = new UploadedFile($file, $originalName); + $tmpName = tempnam(sys_get_temp_dir(), 'upload'); + copy($file, $tmpName); + $tmpFiles[] = $tmpName; + $file = new UploadedFile($tmpName, basename($file), null, null, true); } } @@ -72,6 +76,10 @@ public function send($method, $url, $parameters = [], $files = [], $content = nu $client->followRedirects(true); $this->resetHttpHeaders(); + foreach ($tmpFiles as $tmpName) { + @unlink($tmpName); + } + return $this->mink->getSession()->getPage(); } From e23f094c055cb7f0791229ddc47657fd91be51fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Terje=20Br=C3=A5ten?= Date: Tue, 26 Mar 2019 22:06:13 +0000 Subject: [PATCH 2/9] Do not use UploadFile for GoutteClient --- src/HttpCall/Request/BrowserKit.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/HttpCall/Request/BrowserKit.php b/src/HttpCall/Request/BrowserKit.php index 45490521..42d829e9 100644 --- a/src/HttpCall/Request/BrowserKit.php +++ b/src/HttpCall/Request/BrowserKit.php @@ -59,18 +59,20 @@ public function getContent() public function send($method, $url, $parameters = [], $files = [], $content = null, $headers = []) { + $client = $this->mink->getSession()->getDriver()->getClient(); + $tmpFiles = []; - foreach ($files as $key => &$file) { - if (is_string($file)) { - $tmpName = tempnam(sys_get_temp_dir(), 'upload'); - copy($file, $tmpName); - $tmpFiles[] = $tmpName; - $file = new UploadedFile($tmpName, basename($file), null, null, true); + if (!$client instanceof GoutteClient) { + foreach ($files as &$file) { + if (is_string($file)) { + $tmpName = tempnam(sys_get_temp_dir(), 'upload'); + copy($file, $tmpName); + $tmpFiles[] = $tmpName; + $file = new UploadedFile($tmpName, $file, null, null, true); + } } } - $client = $this->mink->getSession()->getDriver()->getClient(); - $client->followRedirects(false); $client->request($method, $url, $parameters, $files, $headers, $content); $client->followRedirects(true); From 3c99b79d3bcafca308cc7d1fa76843aeb11431e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Terje=20Br=C3=A5ten?= Date: Wed, 27 Mar 2019 00:34:21 +0000 Subject: [PATCH 3/9] Support array of files as well --- src/HttpCall/Request/BrowserKit.php | 42 +++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/src/HttpCall/Request/BrowserKit.php b/src/HttpCall/Request/BrowserKit.php index 42d829e9..e2fcc854 100644 --- a/src/HttpCall/Request/BrowserKit.php +++ b/src/HttpCall/Request/BrowserKit.php @@ -63,14 +63,7 @@ public function send($method, $url, $parameters = [], $files = [], $content = nu $tmpFiles = []; if (!$client instanceof GoutteClient) { - foreach ($files as &$file) { - if (is_string($file)) { - $tmpName = tempnam(sys_get_temp_dir(), 'upload'); - copy($file, $tmpName); - $tmpFiles[] = $tmpName; - $file = new UploadedFile($tmpName, $file, null, null, true); - } - } + $tmpFiles = $this->convertFilesToSymfonyUploadedFiles($files); } $client->followRedirects(false); @@ -151,4 +144,37 @@ protected function resetHttpHeaders() $client->restart(); } } + + private function convertFilesToSymfonyUploadedFiles(& $files) + { + $tmpFiles = []; + foreach ($files as $key => &$file) { + $tmpName = false; + if (is_string($file)) { + $tmpName = tempnam(sys_get_temp_dir(), 'upload'); + copy($file, $tmpName); + $tmpFiles[] = $tmpName; + $originalName = $file; + } elseif (is_array($file)) { + // This mirrors Goutte\Client::addPostFiles() called from Goutte\Client::doRequest() + // so that a Symfony\Component\HttpKernel\Client can have the same behaviour + if (isset($file['tmp_name'])) { + $tmpName = $file['tmp_name']; + if (isset($file['name'])) { + $originalName = $file['name']; + } else { + $originalName = $tmpName; + } + } else { + $subTmpFiles = $this->convertFilesToSymfonyUploadedFiles($file); + $tmpFiles = array_merge($tmpFiles, $subTmpFiles); + } + } + if ($tmpName) { + $file = new UploadedFile($tmpName, $originalName, null, null, true); + } + } + + return $tmpFiles; + } } From a83ae3680a9864e3af51cbf5b1b150a7854233a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Terje=20Br=C3=A5ten?= Date: Wed, 27 Mar 2019 07:44:51 +0000 Subject: [PATCH 4/9] Add behat test for browserKit driver (symfony2 behat extension) --- .travis.yml | 2 + behat.yml.dist | 20 ++++++ composer.json | 5 +- tests/features/bootstrap/Bootstrap.php | 1 + tests/features/symfony.feature | 19 +++++ .../www/app/Controller/RestController.php | 40 +++++++++++ tests/fixtures/www/app/Kernel.php | 72 +++++++++++++++++++ tests/fixtures/www/app/templates/rest.php | 32 +++++++++ .../fixtures/www/framework/config/bundles.php | 5 ++ .../framework/config/packages/framework.yaml | 9 +++ .../fixtures/www/framework/config/routes.yaml | 3 + .../www/framework/config/services.yaml | 32 +++++++++ 12 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 tests/features/symfony.feature create mode 100644 tests/fixtures/www/app/Controller/RestController.php create mode 100644 tests/fixtures/www/app/Kernel.php create mode 100644 tests/fixtures/www/app/templates/rest.php create mode 100644 tests/fixtures/www/framework/config/bundles.php create mode 100644 tests/fixtures/www/framework/config/packages/framework.yaml create mode 100644 tests/fixtures/www/framework/config/routes.yaml create mode 100644 tests/fixtures/www/framework/config/services.yaml diff --git a/.travis.yml b/.travis.yml index a1c5395d..4b799d5b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,8 @@ env: - DEPS=low PROFILE=default - DEPS=high PROFILE=symfony2 - DEPS=low PROFILE=symfony2 + - DEPS=high PROFILE=browserKit + - DEPS=low PROFILE=browserKit php: - 5.5 diff --git a/behat.yml.dist b/behat.yml.dist index 140bf0a6..8fa5ab3d 100644 --- a/behat.yml.dist +++ b/behat.yml.dist @@ -2,6 +2,8 @@ default: suites: default: paths: [ '%paths.base%/tests/features' ] + filters: + tags: '~@symfony' contexts: - Behat\MinkExtension\Context\MinkContext - behatch:context:browser: @@ -33,3 +35,21 @@ symfony2: extensions: Behat\MinkExtension: default_session: symfony2 + +browserKit: + suites: + default: + filters: + tags: '@symfony' + extensions: + Behat\Symfony2Extension: + kernel: + bootstrap: 'tests/features/bootstrap/Bootstrap.php' + class: App\Kernel + env: test + debug: false + Behat\MinkExtension: + default_session: browserKit + sessions: + browserKit: + symfony2: ~ diff --git a/composer.json b/composer.json index 7e39dd21..19ca2287 100644 --- a/composer.json +++ b/composer.json @@ -16,6 +16,8 @@ }, "require-dev": { + "symfony/templating": "^2.3|^3.0|^4.0", + "behat/symfony2-extension": "^2.1", "behat/mink-goutte-driver": "^1.1", "guzzlehttp/guzzle": "^6.3", "behat/mink-selenium2-driver": "^1.3", @@ -25,7 +27,8 @@ "autoload": { "psr-4": { - "Behatch\\": "src/" + "Behatch\\": "src/", + "App\\": "tests/fixtures/www/app" } }, diff --git a/tests/features/bootstrap/Bootstrap.php b/tests/features/bootstrap/Bootstrap.php index 31064234..ff54c3a1 100644 --- a/tests/features/bootstrap/Bootstrap.php +++ b/tests/features/bootstrap/Bootstrap.php @@ -1,3 +1,4 @@ files->all(); + $displayFiles = []; + /** @var UploadedFile $file */ + foreach ($files as $key => $file) { + $displayFiles[$key] = [ + 'name' => $file->getClientOriginalName(), + 'error' => $file->getError(), + 'size' => $file->getSize(), + ]; + $file->move('/tmp/moved'); + } + + $view = 'templates/rest.php'; + $parameters = [ + 'server' => $request->server->all(), + 'method' => $request->getMethod(), + 'request' => $request->request->all(), + 'files' => $displayFiles, + 'body' => $request->getContent(), + ]; + $content = $this->container->get('templating')->render($view, $parameters); + return new Response($content); + } +} diff --git a/tests/fixtures/www/app/Kernel.php b/tests/fixtures/www/app/Kernel.php new file mode 100644 index 00000000..db099a13 --- /dev/null +++ b/tests/fixtures/www/app/Kernel.php @@ -0,0 +1,72 @@ +projectDir) { + $this->projectDir = realpath(__DIR__ . '/../framework'); + } + + return $this->projectDir; + } + + public function getCacheDir() + { + return $this->getProjectDir().'/var/cache/'.$this->environment; + } + + public function getLogDir() + { + return $this->getProjectDir().'/var/log'; + } + + public function registerBundles() + { + $contents = require $this->getProjectDir().'/config/bundles.php'; + foreach ($contents as $class => $envs) { + if (isset($envs['all']) || isset($envs[$this->environment])) { + yield new $class(); + } + } + } + + protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader) + { + $container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php')); + // Feel free to remove the "container.autowiring.strict_mode" parameter + // if you are using symfony/dependency-injection 4.0+ as it's the default behavior + $container->setParameter('container.autowiring.strict_mode', true); + $container->setParameter('container.dumper.inline_class_loader', true); + $confDir = $this->getProjectDir().'/config'; + + $loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob'); + $loader->load($confDir.'/{packages}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob'); + $loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob'); + $loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob'); + } + + protected function configureRoutes(RouteCollectionBuilder $routes) + { + $confDir = $this->getProjectDir().'/config'; + + $routes->import($confDir.'/{routes}/*'.self::CONFIG_EXTS, '/', 'glob'); + $routes->import($confDir.'/{routes}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, '/', 'glob'); + $routes->import($confDir.'/{routes}'.self::CONFIG_EXTS, '/', 'glob'); + } +} diff --git a/tests/fixtures/www/app/templates/rest.php b/tests/fixtures/www/app/templates/rest.php new file mode 100644 index 00000000..367f72c9 --- /dev/null +++ b/tests/fixtures/www/app/templates/rest.php @@ -0,0 +1,32 @@ +You have sent a request. + + header(s) received. + $value): ?> +
: + + + +
No parameter received. + +
parameter(s) received. + $value): ?> +
: + + + + +
No files received. + +
file(s) received. + $value): ?> +
- name : +
- error : +
- size : + + + + +
No body received. + +
Body : + diff --git a/tests/fixtures/www/framework/config/bundles.php b/tests/fixtures/www/framework/config/bundles.php new file mode 100644 index 00000000..49d3fb6f --- /dev/null +++ b/tests/fixtures/www/framework/config/bundles.php @@ -0,0 +1,5 @@ + ['all' => true], +]; diff --git a/tests/fixtures/www/framework/config/packages/framework.yaml b/tests/fixtures/www/framework/config/packages/framework.yaml new file mode 100644 index 00000000..bea1ba1b --- /dev/null +++ b/tests/fixtures/www/framework/config/packages/framework.yaml @@ -0,0 +1,9 @@ +framework: + test: true + secret: 'xx-top-secret-yy' + + router: + strict_requirements: ~ + + templating: + engines: ['php'] diff --git a/tests/fixtures/www/framework/config/routes.yaml b/tests/fixtures/www/framework/config/routes.yaml new file mode 100644 index 00000000..6fbc211e --- /dev/null +++ b/tests/fixtures/www/framework/config/routes.yaml @@ -0,0 +1,3 @@ +rest: + path: /symfony/rest + controller: 'App\Controller\RestController:action' diff --git a/tests/fixtures/www/framework/config/services.yaml b/tests/fixtures/www/framework/config/services.yaml new file mode 100644 index 00000000..531448f3 --- /dev/null +++ b/tests/fixtures/www/framework/config/services.yaml @@ -0,0 +1,32 @@ +# This file is the entry point to configure your own services. +# Files in the packages/ subdirectory configure your dependencies. + +# Put parameters here that don't need to change on each machine where the app is deployed +# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration +parameters: + locale: 'en' + +services: + # default configuration for services in *this* file + _defaults: + autowire: true # Automatically injects dependencies in your services. + autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. + public: false # Allows optimizing the container by removing unused services; this also means + # fetching services directly from the container via $container->get() won't work. + # The best practice is to be explicit about your dependencies anyway. + + # makes classes in src/ available to be used as services + # this creates a service per class whose id is the fully-qualified class name +# App\: +# resource: '../../app/*' +# exclude: '../../app/Kernel.php}' +# public: true + + # controllers are imported separately to make sure services can be injected + # as action arguments even if you don't extend any base controller class + App\Controller\: + resource: '../../app/Controller' + tags: ['controller.service_arguments'] + + # add more service definitions when explicit configuration is needed + # please note that last definitions always *replace* previous ones From ea9ab631ef396b19fdf70f7884471726f47f338e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Terje=20Br=C3=A5ten?= Date: Wed, 27 Mar 2019 08:11:24 +0000 Subject: [PATCH 5/9] Update Kernel so we can make do without a MicroKernelTrait --- tests/fixtures/www/app/Kernel.php | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/tests/fixtures/www/app/Kernel.php b/tests/fixtures/www/app/Kernel.php index db099a13..1ca86c01 100644 --- a/tests/fixtures/www/app/Kernel.php +++ b/tests/fixtures/www/app/Kernel.php @@ -2,17 +2,15 @@ namespace App; -use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Kernel as BaseKernel; use Symfony\Component\Routing\RouteCollectionBuilder; class Kernel extends BaseKernel { - use MicroKernelTrait; - const CONFIG_EXTS = '.{php,xml,yaml,yml}'; private $projectDir; @@ -36,6 +34,29 @@ public function getLogDir() return $this->getProjectDir().'/var/log'; } + public function registerContainerConfiguration(LoaderInterface $loader) + { + $loader->load(function (ContainerBuilder $container) use ($loader) { + $container->loadFromExtension('framework', [ + 'router' => [ + 'resource' => 'kernel::loadRoutes', + 'type' => 'service', + ], + ]); + + if ($this instanceof EventSubscriberInterface) { + $container->register('kernel', static::class) + ->setSynthetic(true) + ->setPublic(true) + ->addTag('kernel.event_subscriber'); + } + + $this->configureContainer($container, $loader); + + $container->addObjectResource($this); + }); + } + public function registerBundles() { $contents = require $this->getProjectDir().'/config/bundles.php'; From 35056ea8197d052c19fd5ae29e75cb3c631e2c0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Terje=20Br=C3=A5ten?= Date: Wed, 27 Mar 2019 08:39:23 +0000 Subject: [PATCH 6/9] Simplify app/Kernel.php --- tests/fixtures/www/app/Kernel.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/fixtures/www/app/Kernel.php b/tests/fixtures/www/app/Kernel.php index 1ca86c01..f7fe8791 100644 --- a/tests/fixtures/www/app/Kernel.php +++ b/tests/fixtures/www/app/Kernel.php @@ -11,7 +11,7 @@ class Kernel extends BaseKernel { - const CONFIG_EXTS = '.{php,xml,yaml,yml}'; + const CONFIG_EXTS = '.yaml'; private $projectDir; @@ -57,6 +57,14 @@ public function registerContainerConfiguration(LoaderInterface $loader) }); } + public function loadRoutes(LoaderInterface $loader) + { + $routes = new RouteCollectionBuilder($loader); + $this->configureRoutes($routes); + + return $routes->build(); + } + public function registerBundles() { $contents = require $this->getProjectDir().'/config/bundles.php'; @@ -76,18 +84,14 @@ protected function configureContainer(ContainerBuilder $container, LoaderInterfa $container->setParameter('container.dumper.inline_class_loader', true); $confDir = $this->getProjectDir().'/config'; - $loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob'); - $loader->load($confDir.'/{packages}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob'); - $loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob'); - $loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob'); + $loader->load($confDir.'/packages/*'.self::CONFIG_EXTS, 'glob'); + $loader->load($confDir.'/services'.self::CONFIG_EXTS, 'glob'); } protected function configureRoutes(RouteCollectionBuilder $routes) { $confDir = $this->getProjectDir().'/config'; - $routes->import($confDir.'/{routes}/*'.self::CONFIG_EXTS, '/', 'glob'); - $routes->import($confDir.'/{routes}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, '/', 'glob'); - $routes->import($confDir.'/{routes}'.self::CONFIG_EXTS, '/', 'glob'); + $routes->import($confDir.'/routes'.self::CONFIG_EXTS, '/', 'glob'); } } From 7f981c571961b2f8d195c0ae42e7c5fd6b668296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Terje=20Br=C3=A5ten?= Date: Wed, 27 Mar 2019 09:10:28 +0000 Subject: [PATCH 7/9] Fix loading routes --- tests/fixtures/www/app/Kernel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fixtures/www/app/Kernel.php b/tests/fixtures/www/app/Kernel.php index f7fe8791..a39be6b7 100644 --- a/tests/fixtures/www/app/Kernel.php +++ b/tests/fixtures/www/app/Kernel.php @@ -92,6 +92,6 @@ protected function configureRoutes(RouteCollectionBuilder $routes) { $confDir = $this->getProjectDir().'/config'; - $routes->import($confDir.'/routes'.self::CONFIG_EXTS, '/', 'glob'); + $routes->import($confDir.'/routes'.self::CONFIG_EXTS, '/'); } } From 03484735071a322366660b6a8cd675a746bb5546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Terje=20Br=C3=A5ten?= Date: Wed, 27 Mar 2019 09:15:56 +0000 Subject: [PATCH 8/9] Remove globbing in Kernel --- tests/fixtures/www/app/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/fixtures/www/app/Kernel.php b/tests/fixtures/www/app/Kernel.php index a39be6b7..a89f00f0 100644 --- a/tests/fixtures/www/app/Kernel.php +++ b/tests/fixtures/www/app/Kernel.php @@ -84,8 +84,8 @@ protected function configureContainer(ContainerBuilder $container, LoaderInterfa $container->setParameter('container.dumper.inline_class_loader', true); $confDir = $this->getProjectDir().'/config'; - $loader->load($confDir.'/packages/*'.self::CONFIG_EXTS, 'glob'); - $loader->load($confDir.'/services'.self::CONFIG_EXTS, 'glob'); + $loader->load($confDir.'/packages/framework.yaml'. self::CONFIG_EXTS); + $loader->load($confDir.'/services'.self::CONFIG_EXTS); } protected function configureRoutes(RouteCollectionBuilder $routes) From cb682b64b26fd4eb537eb55b6b0cdd5efb7d9be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Terje=20Br=C3=A5ten?= Date: Wed, 27 Mar 2019 09:55:08 +0000 Subject: [PATCH 9/9] Change loading of framework.yaml --- tests/fixtures/www/app/Kernel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fixtures/www/app/Kernel.php b/tests/fixtures/www/app/Kernel.php index a89f00f0..cb8c64fa 100644 --- a/tests/fixtures/www/app/Kernel.php +++ b/tests/fixtures/www/app/Kernel.php @@ -84,7 +84,7 @@ protected function configureContainer(ContainerBuilder $container, LoaderInterfa $container->setParameter('container.dumper.inline_class_loader', true); $confDir = $this->getProjectDir().'/config'; - $loader->load($confDir.'/packages/framework.yaml'. self::CONFIG_EXTS); + $loader->load($confDir.'/packages/framework'. self::CONFIG_EXTS); $loader->load($confDir.'/services'.self::CONFIG_EXTS); }