From b14ffbda2c2244b5261597d9fbbe5e7bfa91f667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20R?= Date: Mon, 20 Feb 2017 20:40:28 +0100 Subject: [PATCH 1/4] Enable EzSystemsPlatformHttpCacheBundle by default --- app/AppCache.php | 4 ++-- app/AppKernel.php | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/AppCache.php b/app/AppCache.php index a1b1285c88..e8f90fa587 100644 --- a/app/AppCache.php +++ b/app/AppCache.php @@ -6,7 +6,7 @@ * @license For full copyright and license information view LICENSE file distributed with this source code. * @version //autogentag// */ -use eZ\Bundle\EzPublishCoreBundle\HttpCache; +use EzSystems\PlatformHttpCacheBundle\AppCache as PlatformHttpCacheBundleAppCache; /** * Class AppCache. @@ -14,6 +14,6 @@ * For easier upgrade do not change this file, as of 2015.01 possible to extend * cleanly via SYMFONY_HTTP_CACHE_CLASS & SYMFONY_CLASSLOADER_FILE env variables! */ -class AppCache extends HttpCache +class AppCache extends PlatformHttpCacheBundleAppCache { } diff --git a/app/AppKernel.php b/app/AppKernel.php index 3171b4cf7a..f59561b990 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php @@ -33,6 +33,7 @@ public function registerBundles() new Hautelook\TemplatedUriBundle\HautelookTemplatedUriBundle(), new Liip\ImagineBundle\LiipImagineBundle(), new FOS\HttpCacheBundle\FOSHttpCacheBundle(), + new EzSystems\PlatformHttpCacheBundle\EzSystemsPlatformHttpCacheBundle(), new eZ\Bundle\EzPublishCoreBundle\EzPublishCoreBundle(), new eZ\Bundle\EzPublishLegacySearchEngineBundle\EzPublishLegacySearchEngineBundle(), new eZ\Bundle\EzPublishIOBundle\EzPublishIOBundle(), From 3ec5f2130eb2097dfd25e6f4943f75306ab4be5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20R?= Date: Sat, 29 Oct 2016 01:06:27 +0200 Subject: [PATCH 2/4] [Docker] Add docker support for using varnish with xkey --- .env | 5 + .travis.yml | 4 +- app/config/default_parameters.yml | 4 + app/config/env/docker.php | 6 + app/config/ezplatform.yml | 7 + doc/docker-compose/Dockerfile-varnish | 15 ++ doc/docker-compose/README.md | 1 + doc/docker-compose/redis.yml | 4 + doc/docker-compose/selenium.yml | 8 +- doc/docker-compose/solr.yml | 4 + doc/docker-compose/varnish.yml | 39 +++ doc/varnish/{varnish.md => README.md} | 8 +- doc/varnish/vcl/varnish3.vcl | 224 ------------------ .../vcl/{varnish4.vcl => varnish_ban.vcl} | 4 + doc/varnish/vcl/varnish_xkey.vcl | 4 + 15 files changed, 104 insertions(+), 233 deletions(-) create mode 100644 doc/docker-compose/Dockerfile-varnish create mode 100644 doc/docker-compose/varnish.yml rename doc/varnish/{varnish.md => README.md} (52%) delete mode 100644 doc/varnish/vcl/varnish3.vcl rename doc/varnish/vcl/{varnish4.vcl => varnish_ban.vcl} (98%) create mode 100644 doc/varnish/vcl/varnish_xkey.vcl diff --git a/.env b/.env index 51579a907c..688906c060 100644 --- a/.env +++ b/.env @@ -23,3 +23,8 @@ APP_DOCKER_FILE=Dockerfile # Install config, used by .platform.app.yaml among others INSTALL_EZ_INSTALL_TYPE=clean + +# Behat / Selenium config +EZP_TEST_REST_HOST=web +BEHAT_SELENIUM_HOST=selenium +BEHAT_WEB_HOST=web diff --git a/.travis.yml b/.travis.yml index 4eb5ba3901..a0b9b3c7b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,8 +16,8 @@ env: - SYMFONY_DEBUG=1 # list of behat arguments to test matrix: - # Disabled until failures on BDD tests with redis is solved / figured out - #- TEST_CMD="bin/behat -vv --profile=rest --suite=fullJson --tags=~@broken" COMPOSE_FILE="doc/docker-compose/base-prod.yml:doc/docker-compose/redis.yml:doc/docker-compose/selenium.yml" + # Disabled until failures on BDD tests with redis, and travis segfault with varnish is solved / figured out + #- TEST_CMD="bin/behat -vv --profile=rest --suite=fullJson --tags=~@broken" COMPOSE_FILE="doc/docker-compose/base-prod.yml:doc/docker-compose/redis.yml:doc/docker-compose/varnish.yml:doc/docker-compose/selenium.yml" BEHAT_WEB_HOST="varnish" - TEST_CMD="bin/behat -vv --profile=rest --suite=fullJson --tags=~@broken" COMPOSE_FILE="doc/docker-compose/base-prod.yml:doc/docker-compose/selenium.yml" - TEST_CMD="bin/behat -vv --profile=rest --suite=fullXml --tags=~@broken" - TEST_CMD="bin/behat -vv --profile=core --tags=~@broken" diff --git a/app/config/default_parameters.yml b/app/config/default_parameters.yml index 6710401616..85bfeb1d90 100644 --- a/app/config/default_parameters.yml +++ b/app/config/default_parameters.yml @@ -28,3 +28,7 @@ parameters: cache_memcached_port: 11211 cache_redis_port: 6379 + + # Settings for HttpCache + purge_type: "local" + purge_server: "http://my.varnish.server:80" diff --git a/app/config/env/docker.php b/app/config/env/docker.php index 79ca6d6cb5..6eb6833f86 100644 --- a/app/config/env/docker.php +++ b/app/config/env/docker.php @@ -94,3 +94,9 @@ $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../cache_pool')); $loader->load($pool . '.yml'); } + +// HttpCache setting (for configuring Varnish purging) +if ($purgeServer = getenv('HTTPCACHE_PURGE_SERVER')) { + $container->setParameter('purge_type', 'http'); + $container->setParameter('purge_server', $purgeServer); +} diff --git a/app/config/ezplatform.yml b/app/config/ezplatform.yml index c656538996..a8ce4e53e2 100644 --- a/app/config/ezplatform.yml +++ b/app/config/ezplatform.yml @@ -1,4 +1,8 @@ ezpublish: + # HttpCache settings, By default 'local' (Symfony HttpCache Proxy), by setting it to 'http' you can point it to Varnish + http_cache: + purge_type: %purge_type% + # Repositories configuration, setup default repository to support solr if enabled repositories: default: @@ -29,3 +33,6 @@ ezpublish: # so removing eng-GB from this list may lead to errors or content not being shown, unless you change # all eng-GB data to other locales first. languages: [eng-GB] + # HttpCache purge server(s) setting, eg Varnish, for when ezpublish.http_cache.purge_type is set to 'http'. + http_cache: + purge_servers: ["%purge_server%"] diff --git a/doc/docker-compose/Dockerfile-varnish b/doc/docker-compose/Dockerfile-varnish new file mode 100644 index 0000000000..f31b31c230 --- /dev/null +++ b/doc/docker-compose/Dockerfile-varnish @@ -0,0 +1,15 @@ +FROM debian:stretch +# Stretch is used in order to install varnish-modules withouth having to compile from source +# links: +# - https://github.com/varnish/varnish-modules/blob/master/docs/vmod_xkey.rst +# - https://wikitech.wikimedia.org/wiki/XKey + +ENV DEBIAN_FRONTEND noninteractive + +RUN \ + apt-get update -q -y && \ + apt-get install -q -y --force-yes --no-install-recommends ca-certificates varnish-modules varnish + +EXPOSE 80 6082 + +CMD ["varnishd", "-F", "-a", ":80", "-T", ":6082", "-f", "/etc/varnish/default.vcl", "-s", "malloc,256M"] diff --git a/doc/docker-compose/README.md b/doc/docker-compose/README.md index 242160ec1a..0e8e7763ff 100644 --- a/doc/docker-compose/README.md +++ b/doc/docker-compose/README.md @@ -32,6 +32,7 @@ The current Docker Compose files are made to be mixed and matched togtehr as you In addition the following exists but are work in progress, thus not tested yet and are known to be somewhat broken: - redis.yml _(optional, adds redis service and appends config to app)_ +- varnish.yml _(optional, adds varnish service and appends config to app)_ - solr.yml _(optional, add solr service and configure app for it)_ diff --git a/doc/docker-compose/redis.yml b/doc/docker-compose/redis.yml index a069d61797..c7276a54d0 100644 --- a/doc/docker-compose/redis.yml +++ b/doc/docker-compose/redis.yml @@ -1,6 +1,10 @@ version: '2.1' # Redis config, to be appended after base-prod or base-dev, ..., but before selenium.yml +## WARNING: +# This service is currently work in progress, is not tested by CI, and thus not guaranteed to work. +# You are however more then welcome to try it out and help make it stable. + services: app: depends_on: diff --git a/doc/docker-compose/selenium.yml b/doc/docker-compose/selenium.yml index cd11971dbb..5f2b9b1b25 100644 --- a/doc/docker-compose/selenium.yml +++ b/doc/docker-compose/selenium.yml @@ -1,5 +1,5 @@ version: '2.1' -# Appends services to prod.yml, prod+dev, prod+redis, ..., always latests +# Appends services to prod.yml, prod+dev, prod+redis, ..., always latest services: selenium: @@ -16,6 +16,6 @@ services: depends_on: - selenium environment: - - EZP_TEST_REST_HOST=web - - BEHAT_SELENIUM_HOST=selenium - - BEHAT_WEB_HOST=web + - EZP_TEST_REST_HOST + - BEHAT_SELENIUM_HOST + - BEHAT_WEB_HOST diff --git a/doc/docker-compose/solr.yml b/doc/docker-compose/solr.yml index 4c45f3710c..b4669e232a 100644 --- a/doc/docker-compose/solr.yml +++ b/doc/docker-compose/solr.yml @@ -4,6 +4,10 @@ version: '2.1' # NOTE: You'll need to manually reindex the solr index when booting this as we don't have entrypoint for solr yet. # (Unless you use ezplatform:install command which indexes for you) +## WARNING! +# This service is currently work in progress, is not tested by CI, and thus not guaranteed to work. +# You are however more then welcome to try it out and help make it stable. + services: app: depends_on: diff --git a/doc/docker-compose/varnish.yml b/doc/docker-compose/varnish.yml new file mode 100644 index 0000000000..dd0e07fdd5 --- /dev/null +++ b/doc/docker-compose/varnish.yml @@ -0,0 +1,39 @@ +version: '2.1' +# Simple single server setup for prod + +## WARNING! +# This service is currently work in progress, is not tested by CI, and thus not guaranteed to work. +# You are however more then welcome to try it out and help make it stable. + +services: + app: + environment: + - SYMFONY_HTTP_CACHE=0 + - SYMFONY_TRUSTED_PROXIES=varnish + - HTTPCACHE_PURGE_SERVER=http://varnish + + varnish: + build: + context: . + dockerfile: Dockerfile-varnish + image: my_varnish + mem_limit: 384M + memswap_limit: 512M + ports: + - "8081:80" + depends_on: + - web + volumes: + - ${COMPOSE_DIR}/../vendor/ezsystems/ezplatform-http-cache/docs/varnish/vcl/varnish4.vcl:/etc/varnish/default.vcl:ro + + +## DEBUG?? +# In need of debugging all request going to Varnish, use varnishlog, example: +# docker-compose exec varnish varnishlog -c -i ReqURL,ReqMethod -I ReqHeader:xkey +# Or more relevant only PURGE's with all info: +# docker-compose exec varnish varnishlog -g request -q "ReqMethod eq 'PURGE'" +# +# But before doing that check that http and not local purge client is set: +# docker-compose exec app app/console --env=dev debug:container ezplatform.http_cache.purge_client +# +# And if in prod make sure you have rebuilt app container on code changes ;) diff --git a/doc/varnish/varnish.md b/doc/varnish/README.md similarity index 52% rename from doc/varnish/varnish.md rename to doc/varnish/README.md index c08ac986c7..590ca9f4f8 100644 --- a/doc/varnish/varnish.md +++ b/doc/varnish/README.md @@ -3,14 +3,16 @@ eZ Platform Varnish configuration Prerequisites ------------- -* A working Varnish 3 or Varnish 4 setup. +* A working Varnish 4.1 and higher setup with xkey module installed. Recommended VCL base files -------------------------- For Varnish to work properly with eZ, you'll need to use one of the provided files as a basis: -* [eZ 5.4+ / 2014.09+ with Varnish 3](vcl/varnish3.vcl) -* [eZ 5.4+ / 2014.09+ with Varnish 4](vcl/varnish4.vcl) +* [eZ Platform optimized Varnish VCL using xkey](https://github.com/ezsystems/ezplatform-http-cache/blob/master/docs/varnish/vcl/varnish4.vcl) + * Further documentation on this option can be found in [ezplatform-http-cache package](https://github.com/ezsystems/ezplatform-http-cache/tree/master/docs) +* [(Deprecated) eZ Platform optimized Varnish VCL using BAN](vcl/varnish_ban.vcl) + * To use this one you'll need to disable `EzSystemsPlatformHttpCacheBundle`. > **Note:** Http cache management is done with the help of [FOSHttpCacheBundle](http://foshttpcachebundle.readthedocs.org/). One may need to tweak their VCL further on according to [FOSHttpCache documentation](http://foshttpcache.readthedocs.org/en/latest/varnish-configuration.html) diff --git a/doc/varnish/vcl/varnish3.vcl b/doc/varnish/vcl/varnish3.vcl deleted file mode 100644 index 718c26ea75..0000000000 --- a/doc/varnish/vcl/varnish3.vcl +++ /dev/null @@ -1,224 +0,0 @@ -// Varnish 3 style - eZ 5.4+ / 2014.09+ -// Complete VCL example - -// Our Backend - Assuming that web server is listening on port 80 -// Replace the host to fit your setup -backend ezplatform { - .host = "127.0.0.1"; - .port = "80"; -} - -// ACL for invalidators IP -acl invalidators { - "127.0.0.1"; - "192.168.0.0"/16; -} - -// ACL for debuggers IP -acl debuggers { - "127.0.0.1"; - "192.168.0.0"/16; -} - -// Called at the beginning of a request, after the complete request has been received -sub vcl_recv { - - // Set the backend - set req.backend = ezplatform; - - // Advertise Symfony for ESI support - set req.http.Surrogate-Capability = "abc=ESI/1.0"; - - // Add a unique header containing the client address (only for master request) - // Please note that /_fragment URI can change in Symfony configuration - if (!req.url ~ "^/_fragment") { - if (req.http.x-forwarded-for) { - set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip; - } else { - set req.http.X-Forwarded-For = client.ip; - } - } - - // Trigger cache purge if needed - call ez_purge; - - // Don't cache requests other than GET and HEAD. - if (req.request != "GET" && req.request != "HEAD") { - return (pass); - } - - // Normalize the Accept-Encoding headers - if (req.http.Accept-Encoding) { - if (req.http.Accept-Encoding ~ "gzip") { - set req.http.Accept-Encoding = "gzip"; - } elsif (req.http.Accept-Encoding ~ "deflate") { - set req.http.Accept-Encoding = "deflate"; - } else { - unset req.http.Accept-Encoding; - } - } - - // Don't cache Authenticate & Authorization - // You may remove this when using REST API with basic auth. - if (req.http.Authenticate || req.http.Authorization) { - if (client.ip ~ debuggers) { - set req.http.X-Debug = "Not Cached according to configuration (Authorization)"; - } - return(pass); - } - - // Do a standard lookup on assets - // Note that file extension list below is not extensive, so consider completing it to fit your needs. - if (req.url ~ "\.(css|js|gif|jpe?g|bmp|png|tiff?|ico|img|tga|wmf|svg|swf|ico|mp3|mp4|m4a|ogg|mov|avi|wmv|zip|gz|pdf|ttf|eot|wof)$") { - return (lookup); - } - - // Retrieve client user hash and add it to the forwarded request. - call ez_user_hash; - - // If it passes all these tests, do a lookup anyway. - return (lookup); -} - -// Called when the requested object has been retrieved from the backend -sub vcl_fetch { - - if (req.restarts == 0 - && req.http.accept ~ "application/vnd.fos.user-context-hash" - && beresp.status >= 500 - ) { - error 503 "Hash error"; - } - - // Optimize to only parse the Response contents from Symfony - if (beresp.http.Surrogate-Control ~ "ESI/1.0") { - unset beresp.http.Surrogate-Control; - set beresp.do_esi = true; - } - - // Respect the Cache-Control=private header from the backend - if (beresp.http.Cache-Control ~ "no-cache|no-store|private") { - set beresp.ttl = 120s; - return (hit_for_pass); - } - - return (deliver); -} - -// Handle purge -// You may add FOSHttpCacheBundle tagging rules -// See http://foshttpcache.readthedocs.org/en/latest/varnish-configuration.html#id4 -sub ez_purge { - - if (req.request == "BAN") { - if (!client.ip ~ invalidators) { - error 405 "Method not allowed"; - } - - if (req.http.X-Location-Id) { - ban( "obj.http.X-Location-Id ~ " + req.http.X-Location-Id); - if (client.ip ~ debuggers) { - set req.http.X-Debug = "Ban done for content connected to LocationId " + req.http.X-Location-Id; - } - error 200 "Banned"; - } - } -} - -// Sub-routine to get client user hash, for context-aware HTTP cache. -sub ez_user_hash { - - // Prevent tampering attacks on the hash mechanism - if (req.restarts == 0 - && (req.http.accept ~ "application/vnd.fos.user-context-hash" - || req.http.x-user-hash - ) - ) { - error 400; - } - - if (req.restarts == 0 && (req.request == "GET" || req.request == "HEAD")) { - // Get User (Context) hash, for varying cache by what user has access to. - // https://doc.ez.no/display/EZP/Context+aware+HTTP+cache - - // Anonymous user w/o session => Use hardcoded anonymous hash to avoid backend lookup for hash - if (req.http.Cookie !~ "eZSESSID" && !req.http.authorization) { - // You may update this hash with the actual one for anonymous user - // to get a better cache hit ratio across anonymous users. - // Note: You should then update it every time anonymous user rights change. - set req.http.X-User-Hash = "38015b703d82206ebc01d17a39c727e5"; - } - // Pre-authenticate request to get shared cache, even when authenticated - else { - set req.http.x-fos-original-url = req.url; - set req.http.x-fos-original-accept = req.http.accept; - set req.http.x-fos-original-cookie = req.http.cookie; - // Clean up cookie for the hash request to only keep session cookie, as hash cache will vary on cookie. - set req.http.cookie = ";" + req.http.cookie; - set req.http.cookie = regsuball(req.http.cookie, "; +", ";"); - set req.http.cookie = regsuball(req.http.cookie, ";(eZSESSID[^=]*)=", "; \1="); - set req.http.cookie = regsuball(req.http.cookie, ";[^ ][^;]*", ""); - set req.http.cookie = regsuball(req.http.cookie, "^[; ]+|[; ]+$", ""); - - set req.http.accept = "application/vnd.fos.user-context-hash"; - set req.url = "/_fos_user_context_hash"; - - // Force the lookup, the backend must tell how to cache/vary response containing the user hash - - return (lookup); - } - } - - // Rebuild the original request which now has the hash. - if (req.restarts > 0 - && req.http.accept == "application/vnd.fos.user-context-hash" - ) { - set req.url = req.http.x-fos-original-url; - set req.http.accept = req.http.x-fos-original-accept; - set req.http.cookie = req.http.x-fos-original-cookie; - - unset req.http.x-fos-original-url; - unset req.http.x-fos-original-accept; - unset req.http.x-fos-original-cookie; - - // Force the lookup, the backend must tell not to cache or vary on the - // user hash to properly separate cached data. - - return (lookup); - } -} - -sub vcl_deliver { - // On receiving the hash response, copy the hash header to the original - // request and restart. - if (req.restarts == 0 - && resp.http.content-type ~ "application/vnd.fos.user-context-hash" - && resp.status == 200 - ) { - set req.http.x-user-hash = resp.http.x-user-hash; - - return (restart); - } - - // If we get here, this is a real response that gets sent to the client. - - // Remove the vary on context user hash, this is nothing public. Keep all - // other vary headers. - set resp.http.Vary = regsub(resp.http.Vary, "(?i),? *x-user-hash *", ""); - set resp.http.Vary = regsub(resp.http.Vary, "^, *", ""); - if (resp.http.Vary == "") { - unset resp.http.Vary; - } - - // Sanity check to prevent ever exposing the hash to a client. - unset resp.http.x-user-hash; - - if (client.ip ~ debuggers) { - if (obj.hits > 0) { - set resp.http.X-Cache = "HIT"; - set resp.http.X-Cache-Hits = obj.hits; - } else { - set resp.http.X-Cache = "MISS"; - } - } -} diff --git a/doc/varnish/vcl/varnish4.vcl b/doc/varnish/vcl/varnish_ban.vcl similarity index 98% rename from doc/varnish/vcl/varnish4.vcl rename to doc/varnish/vcl/varnish_ban.vcl index 8d743b6563..adbf3b88aa 100644 --- a/doc/varnish/vcl/varnish4.vcl +++ b/doc/varnish/vcl/varnish_ban.vcl @@ -1,5 +1,9 @@ // Varnish 4 style - eZ 5.4+ / 2014.09+ // Complete VCL example +// +// DEPRECATED: This approach for invalidation is deprecated and default has changed to xkey. +// See doc/varnish/README.md + vcl 4.0; diff --git a/doc/varnish/vcl/varnish_xkey.vcl b/doc/varnish/vcl/varnish_xkey.vcl new file mode 100644 index 0000000000..a2a4aad14f --- /dev/null +++ b/doc/varnish/vcl/varnish_xkey.vcl @@ -0,0 +1,4 @@ +// +// This VCL can be found in: +// vendor/ezsystems/ezplatform-http-cache/docs/varnish/vcl/varnish4.vcl +// From 57e6b347f64b28ae2f4df61fafa7903a952a33a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20R?= Date: Mon, 14 Nov 2016 11:01:05 +0100 Subject: [PATCH 3/4] Increase TTL to 900 and add some more info --- app/config/ezplatform.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/config/ezplatform.yml b/app/config/ezplatform.yml index a8ce4e53e2..9396a035ec 100644 --- a/app/config/ezplatform.yml +++ b/app/config/ezplatform.yml @@ -36,3 +36,7 @@ ezpublish: # HttpCache purge server(s) setting, eg Varnish, for when ezpublish.http_cache.purge_type is set to 'http'. http_cache: purge_servers: ["%purge_server%"] + # Given we use ezplatform-http-cache package we increase the default TTL as the package aims to correctly + # invalidate all cache when they update, and hence longer TTL should be supported. + content: + default_ttl: 900 From 98fc8e26a3ecad633d3232bd9918d63a0377fe80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20R?= Date: Wed, 21 Jun 2017 17:31:49 +0200 Subject: [PATCH 4/4] [Travis] Run tests with varnish --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a0b9b3c7b8..65fcaf1551 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ env: matrix: # Disabled until failures on BDD tests with redis, and travis segfault with varnish is solved / figured out #- TEST_CMD="bin/behat -vv --profile=rest --suite=fullJson --tags=~@broken" COMPOSE_FILE="doc/docker-compose/base-prod.yml:doc/docker-compose/redis.yml:doc/docker-compose/varnish.yml:doc/docker-compose/selenium.yml" BEHAT_WEB_HOST="varnish" - - TEST_CMD="bin/behat -vv --profile=rest --suite=fullJson --tags=~@broken" COMPOSE_FILE="doc/docker-compose/base-prod.yml:doc/docker-compose/selenium.yml" + - TEST_CMD="bin/behat -vv --profile=rest --suite=fullJson --tags=~@broken" COMPOSE_FILE="doc/docker-compose/base-prod.yml:doc/docker-compose/varnish.yml:doc/docker-compose/selenium.yml" - TEST_CMD="bin/behat -vv --profile=rest --suite=fullXml --tags=~@broken" - TEST_CMD="bin/behat -vv --profile=core --tags=~@broken" - TEST_CMD="bin/phpunit -v vendor/ezsystems/ezpublish-kernel/eZ/Bundle/EzPublishRestBundle/Tests/Functional"