Skip to content

Instantly share code, notes, and snippets.

@sameronline
Last active March 15, 2017 13:45
Show Gist options
  • Save sameronline/407c2fc115e9bbc0d53898d3a788398c to your computer and use it in GitHub Desktop.
Save sameronline/407c2fc115e9bbc0d53898d3a788398c to your computer and use it in GitHub Desktop.
drupal/relaxed 8.3 compatibility patch based on https://github.com/relaxedws/drupal-relaxed/pull/82
diff --git a/.travis.yml b/.travis.yml
index ae19cd2..e24bc8d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,9 +30,9 @@ env:
matrix:
allow_failures:
- - env: SCRIPT='modules/relaxed/tests/bin/drupal.sh' MAKE_FILE=drupal-8.3.x.make.yml
- - env: SCRIPT='modules/relaxed/tests/bin/pouchdb.sh' MAKE_FILE=drupal-8.3.x.make.yml
- - env: SCRIPT='modules/relaxed/tests/bin/replication.sh' MAKE_FILE=drupal-8.3.x.make.yml
+ - env: SCRIPT='modules/relaxed/tests/bin/drupal.sh' MAKE_FILE=drupal-8.2.x.make.yml
+ - env: SCRIPT='modules/relaxed/tests/bin/pouchdb.sh' MAKE_FILE=drupal-8.2.x.make.yml
+ - env: SCRIPT='modules/relaxed/tests/bin/replication.sh' MAKE_FILE=drupal-8.2.x.make.yml
fast_finish: true
notifications:
diff --git a/config/install/relaxed.settings.yml b/config/install/relaxed.settings.yml
index cc407cf..251ac58 100644
--- a/config/install/relaxed.settings.yml
+++ b/config/install/relaxed.settings.yml
@@ -1,171 +1 @@
api_root: "/relaxed"
-
-# Keep this just for compatibility with Drupal 8.1.x. Starting with Drupal 8.2.x
-# these settings are config entities.
-# @todo Remove when we decide to not support Drupal 8.1.x.
-resources:
- relaxed:db:
- HEAD:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- GET:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- POST:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- PUT:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- DELETE:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- relaxed:attachment:
- HEAD:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- GET:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- PUT:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- DELETE:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- relaxed:bulk_docs:
- POST:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- relaxed:changes:
- GET:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- relaxed:doc:
- HEAD:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- GET:
- supported_formats:
- - json
- - mixed
- supported_auth:
- - cookie
- - basic_auth
- PUT:
- supported_formats:
- - json
- - related
- supported_auth:
- - cookie
- - basic_auth
- DELETE:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- relaxed:revs_diff:
- POST:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- relaxed:local:doc:
- HEAD:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- GET:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- PUT:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- relaxed:root:
- GET:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- relaxed:session:
- GET:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- relaxed:ensure_full_commit:
- POST:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- relaxed:all_dbs:
- GET:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- relaxed:all_docs:
- GET:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
- relaxed:replicate:
- POST:
- supported_formats:
- - json
- supported_auth:
- - cookie
- - basic_auth
diff --git a/config/optional/rest.resource.relaxed.attachment.yml b/config/optional/rest.resource.relaxed.attachment.yml
index b3a2000..2e042ad 100644
--- a/config/optional/rest.resource.relaxed.attachment.yml
+++ b/config/optional/rest.resource.relaxed.attachment.yml
@@ -5,12 +5,16 @@ configuration:
HEAD:
supported_formats:
- json
+ - stream
+ - base64_stream
supported_auth:
- cookie
- basic_auth
GET:
supported_formats:
- json
+ - stream
+ - base64_stream
supported_auth:
- cookie
- basic_auth
diff --git a/config/schema/relaxed.schema.yml b/config/schema/relaxed.schema.yml
index 1e86e75..6568629 100644
--- a/config/schema/relaxed.schema.yml
+++ b/config/schema/relaxed.schema.yml
@@ -1,4 +1,3 @@
-# @todo Remove when we decide to not support Drupal 8.1.x.
relaxed.settings:
type: config_object
label: 'Relaxed API settings'
@@ -6,51 +5,6 @@ relaxed.settings:
api_root:
type: string
label: 'Absolute base path to the API root, without trailing slash.'
- resources:
- type: sequence
- label: 'Resources'
- sequence:
- type: relaxed_resource
- label: 'Resource'
-
-# @todo Remove when we decide to not support Drupal 8.1.x.
-relaxed_resource:
- type: mapping
- mapping:
- GET:
- type: rest_request
- label: 'GET method settings'
- POST:
- type: rest_request
- label: 'POST method settings'
- PATCH:
- type: rest_request
- label: 'PATCH method settings'
- DELETE:
- type: rest_request
- label: 'DELETE method settings'
- HEAD:
- type: rest_request
- label: 'HEAD method settings'
- PUT:
- type: rest_request
- label: 'PUT method settings'
-
-rest_request:
- type: mapping
- mapping:
- supported_formats:
- type: sequence
- label: 'Supported format'
- sequence:
- type: string
- label: 'Format'
- supported_auth:
- type: sequence
- label: 'Supported authentication'
- sequence:
- type: string
- label: 'Authentication'
relaxed.endpoint.*:
type: config_entity
diff --git a/relaxed.info.yml b/relaxed.info.yml
index a22d474..517b025 100644
--- a/relaxed.info.yml
+++ b/relaxed.info.yml
@@ -8,5 +8,6 @@ dependencies:
- basic_auth
- multiversion
- replication
+ - system (>=8.3.x)
test_dependencies:
- workspace
diff --git a/relaxed.install b/relaxed.install
index 9ffffb5..13de276 100644
--- a/relaxed.install
+++ b/relaxed.install
@@ -23,44 +23,4 @@ function relaxed_install() {
],
])->save();
}
-
- // Keep this just for compatibility with Drupal 8.1.x.
- // @todo Remove when we decide to not support Drupal 8.1.x.
- $module_handler = \Drupal::moduleHandler();
- // Merge 'resource' settings from relaxed module with 'resource' settings from rest module,
- // these settings are not loaded if added to /config/install/rest.settings.yml.
- // @todo {@link https://www.drupal.org/node/2599862 Figure out a better way to do this.}
- $relaxed_resource_config = \Drupal::config('relaxed.settings')->get('resources');
- $rest_config = \Drupal::configFactory()->getEditable('rest.settings');
- $rest_resource_config = $rest_config->get('resources');
- // The rest module define settings for the node entity type but doesn't
- // declare a dependency on node. This is causing trouble in some of our tests
- // for some reason. So we remove those settings if the node modules is not
- // enabled.
- if (!$module_handler->moduleExists('node')) {
- unset($rest_resource_config['entity:node']);
- }
- if (is_array($rest_resource_config)) {
- $rest_config->set('resources', array_merge($rest_resource_config, $relaxed_resource_config))->save();
- }
-}
-
-/**
- * Implements hook_uninstall().
- */
-function relaxed_uninstall() {
- // Keep this just for compatibility with Drupal 8.1.x.
- // @todo Remove when we decide to not support Drupal 8.1.x.
-
- // Remove 'resource' settings defined by RELAXed Web Services module from
- // 'resource' settings defined by RESTful Web Services module.
- $relaxed_resource_config = \Drupal::config('relaxed.settings')->get('resources');
- $rest_config = \Drupal::configFactory()->getEditable('rest.settings');
- $rest_resource_config = $rest_config->get('resources');
- foreach ($relaxed_resource_config as $key => $item) {
- if (isset($rest_resource_config[$key])) {
- unset($rest_resource_config[$key]);
- }
- }
- $rest_config->set('resources', $rest_resource_config)->save();
}
diff --git a/relaxed.services.yml b/relaxed.services.yml
index 191c185..3d01cf8 100644
--- a/relaxed.services.yml
+++ b/relaxed.services.yml
@@ -41,3 +41,8 @@ services:
tags:
- { name: normalizer, priority: 10 }
arguments: ['@relaxed.replicate']
+ relaxed.resource_response.subscriber:
+ class: Drupal\relaxed\EventSubscriber\ResourceResponseSubscriber
+ tags:
+ - { name: event_subscriber }
+ arguments: ['@serializer', '@renderer', '@current_route_match']
diff --git a/src/Controller/ResourceController.php b/src/Controller/ResourceController.php
index d54c843..d2ff433 100644
--- a/src/Controller/ResourceController.php
+++ b/src/Controller/ResourceController.php
@@ -4,12 +4,15 @@ namespace Drupal\relaxed\Controller;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Cache\CacheableResponseInterface;
+use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Render\RenderContext;
+use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\multiversion\Entity\WorkspaceInterface;
-use Drupal\relaxed\HttpMultipart\HttpFoundation\MultipartResponse;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
+use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
@@ -19,7 +22,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\PreconditionFailedHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
-class ResourceController implements ContainerAwareInterface {
+class ResourceController implements ContainerAwareInterface, ContainerInjectionInterface {
use ContainerAwareTrait;
@@ -34,6 +37,30 @@ class ResourceController implements ContainerAwareInterface {
protected $request;
/**
+ * The resource configuration storage.
+ *
+ * @var \Drupal\Core\Entity\EntityStorageInterface
+ */
+ protected $resourceStorage;
+
+ /**
+ * Creates a new RequestHandler instance.
+ *
+ * @param \Drupal\Core\Entity\EntityStorageInterface $entity_storage
+ * The resource configuration storage.
+ */
+ public function __construct(EntityStorageInterface $entity_storage) {
+ $this->resourceStorage = $entity_storage;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container) {
+ return new static($container->get('entity_type.manager')->getStorage('rest_resource_config'));
+ }
+
+ /**
* @return \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected function container() {
@@ -78,11 +105,13 @@ class ResourceController implements ContainerAwareInterface {
}
/**
+ * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+ *
* @return array
*/
- protected function getParameters() {
+ protected function getParameters(RouteMatchInterface $route_match) {
$parameters = array();
- foreach ($this->request->attributes->get('_route_params') as $key => $parameter) {
+ foreach ($route_match->getParameters() as $key => $parameter) {
// We don't want private parameters.
if ($key{0} !== '_') {
$parameters[] = $parameter;
@@ -133,11 +162,12 @@ class ResourceController implements ContainerAwareInterface {
}
/**
+ * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
* @param \Symfony\Component\HttpFoundation\Request $request
*
* @return \Symfony\Component\HttpFoundation\Response
*/
- public function handle(Request $request) {
+ public function handle(RouteMatchInterface $route_match, Request $request) {
$this->request = $request;
$method = $this->getMethod();
@@ -145,13 +175,13 @@ class ResourceController implements ContainerAwareInterface {
$resource = $this->getResource();
$content = $this->request->getContent();
- $parameters = $this->getParameters();
- $serializer = $this->serializer();
+ $parameters = $this->getParameters($route_match);
$render_contexts = [];
// @todo {@link https://www.drupal.org/node/2600500 Check if this is safe.}
$query = $this->request->query->all();
- $context = array('query' => $query, 'resource_id' => $resource->getPluginId());
+ $resource_config_id = $route_match->getRouteObject()->getDefault('_rest_resource_config');
+ $context = array('query' => $query, 'resource_id' => $resource_config_id);
$entity = NULL;
$definition = $resource->getPluginDefinition();
if (!empty($content)) {
@@ -192,32 +222,11 @@ class ResourceController implements ContainerAwareInterface {
return $this->errorResponse($e);
}
- $response_format = (in_array($request->getMethod(), array('GET', 'HEAD')) && $format == 'stream')
- ? 'stream'
- : 'json';
-
- $responses = ($response instanceof MultipartResponse) ? $response->getParts() : array($response);
-
- foreach ($responses as $response_part) {
- try {
- if ($response_data = $response_part->getResponseData()) {
- // Collect bubbleable metadata in a render context.
- $render_context = new RenderContext();
- $response_output = $this->container->get('renderer')->executeInRenderContext($render_context, function() use ($serializer, $response_data, $response_format, $context) {
- return $serializer->serialize($response_data, $response_format, $context);
- });
- if (!$render_context->isEmpty()) {
- $render_contexts[] = $render_context->pop();
- }
- $response_part->setContent($response_output);
- }
- }
- catch (\Exception $e) {
- return $this->errorResponse($e);
- }
- if (!$response_part->headers->get('Content-Type')) {
- $response_part->headers->set('Content-Type', $this->request->getMimeType($response_format));
- }
+ /** @var \Drupal\rest\RestResourceConfigInterface $resource_config */
+ $resource_config = $this->resourceStorage->load($resource_config_id);
+ if ($response instanceof CacheableResponseInterface) {
+ // Add rest config's cache tags.
+ $response->addCacheableDependency($resource_config);
}
$cacheable_dependencies = [];
@@ -232,13 +241,10 @@ class ResourceController implements ContainerAwareInterface {
$cacheable_dependencies[] = $parameter;
}
}
- $cacheable_dependencies[] = $this->container->get('config.factory')->get('rest.settings');
$cacheable_metadata = new CacheableMetadata();
$cacheable_dependencies[] = $cacheable_metadata->setCacheContexts(['url.query_args', 'request_format', 'headers:If-None-Match']);
$this->addCacheableDependency($response, $cacheable_dependencies);
- if ($request->getMethod() !== 'HEAD') {
- $response->headers->set('Content-Length', strlen($response->getContent()));
- }
+
return $response;
}
diff --git a/src/EventSubscriber/ResourceResponseSubscriber.php b/src/EventSubscriber/ResourceResponseSubscriber.php
new file mode 100644
index 0000000..4a090be
--- /dev/null
+++ b/src/EventSubscriber/ResourceResponseSubscriber.php
@@ -0,0 +1,104 @@
+<?php
+
+namespace Drupal\relaxed\EventSubscriber;
+
+use Drupal\relaxed\HttpMultipart\HttpFoundation\MultipartResponse;
+use Drupal\Core\Render\RenderContext;
+use Drupal\rest\ResourceResponseInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\Serializer\SerializerInterface;
+use Drupal\rest\EventSubscriber\ResourceResponseSubscriber as CoreResourceResponseSubscriber;
+
+class ResourceResponseSubscriber extends CoreResourceResponseSubscriber {
+
+ /**
+ * Serializes ResourceResponse relaxed responses' data.
+ *
+ * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
+ * The event to process.
+ */
+ public function onResponse(FilterResponseEvent $event) {
+ $response = $event->getResponse();
+ if (!$response instanceof ResourceResponseInterface) {
+ return;
+ }
+
+ $request = $event->getRequest();
+ if ($this->isRelaxedRoute()) {
+ // @todo Review/refactor format negotiation.
+ // @see \Drupal\rest\EventSubscriber\ResourceResponseSubscriber::getResponseFormat().
+ $format = (in_array($request->getMethod(), array('GET', 'HEAD')) && $this->isAttachment()) ? 'stream' : 'json';
+ $this->renderResponseBody($request, $response, $this->serializer, $format);
+ $event->setResponse($this->flattenResponse($response));
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function renderResponseBody(Request $request, ResourceResponseInterface $response, SerializerInterface $serializer, $format) {
+ $responses = ($response instanceof MultipartResponse) ? $response->getParts() : array($response);
+ // @todo {@link https://www.drupal.org/node/2600500 Check if this is safe.}
+ $query = $request->query->all();
+ $resource_config_id = $this->routeMatch->getRouteObject()->getDefault('_rest_resource_config');
+ $context = array('query' => $query, 'resource_id' => $resource_config_id);
+
+ $render_contexts = [];
+ foreach ($responses as $response_part) {
+ if ($response_data = $response_part->getResponseData()) {
+ // Collect bubbleable metadata in a render context.
+ $render_context = new RenderContext();
+ $response_output = $this->renderer->executeInRenderContext($render_context, function() use ($serializer, $response_data, $format, $context) {
+ return $serializer->serialize($response_data, $format, $context);
+ });
+ if (!$render_context->isEmpty()) {
+ $render_contexts[] = $render_context->pop();
+ }
+ $response_part->setContent($response_output);
+ }
+ if (!$response_part->headers->get('Content-Type')) {
+ $response_part->headers->set('Content-Type', $request->getMimeType($format));
+ }
+ }
+
+ if ($request->getMethod() !== 'HEAD') {
+ $response->headers->set('Content-Length', strlen($response->getContent()));
+ }
+ }
+
+ protected function isRelaxedRoute() {
+ return (substr($this->routeMatch->getRouteObject()->getDefault('_rest_resource_config'), 0, strlen('relaxed')) === 'relaxed');
+ }
+
+ protected function isAttachment() {
+ return (substr($this->routeMatch->getRouteObject()->getDefault('_rest_resource_config'), -strlen('attachment')) === 'attachment');
+ }
+
+ /**
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ *
+ * @return array
+ */
+ protected function getParameters(Request $request) {
+ $parameters = array();
+ foreach ($request->attributes->get('_route_params') as $key => $parameter) {
+ // We don't want private parameters.
+ if ($key{0} !== '_') {
+ $parameters[] = $parameter;
+ }
+ }
+ return $parameters;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getSubscribedEvents() {
+ // Run shortly before \Drupal\rest\EventSubscriber\ResourceResponseSubscriber.
+ $events[KernelEvents::RESPONSE][] = ['onResponse', 6];
+ return $events;
+ }
+
+}
diff --git a/src/Tests/RemoteConfigurationTest.php b/src/Tests/RemoteConfigurationTest.php
index 49aea68..9b83250 100644
--- a/src/Tests/RemoteConfigurationTest.php
+++ b/src/Tests/RemoteConfigurationTest.php
@@ -19,7 +19,6 @@ class RemoteConfigurationTest extends WebTestBase {
*/
public static $modules = array(
'file',
- 'entity_test',
'multiversion',
'rest',
'relaxed',
@@ -98,7 +97,8 @@ class RemoteConfigurationTest extends WebTestBase {
$this->assertResponse(200);
$this->assertNoText($new_label, "Make sure the Remote label does not appear on the overview page after we've deleted the Remote.");
- $remote = entity_load('remote', $aid);
+ $remote = \Drupal::entityTypeManager()->getStorage('remote')->load($aid);
$this->assertFalse($remote, 'Make sure the Remote is gone after being deleted.');
}
+
}
diff --git a/src/Tests/ResourceTestBase.php b/src/Tests/ResourceTestBase.php
index 19d8bf8..5436be0 100644
--- a/src/Tests/ResourceTestBase.php
+++ b/src/Tests/ResourceTestBase.php
@@ -121,7 +121,7 @@ abstract class ResourceTestBase extends RESTTestBase {
$mime_type = $this->defaultMimeType;
}
if ($mime_type === $this->defaultMimeType && !isset($query['_format'])) {
- $query[] = ['_format' => $this->defaultFormat];
+ $query['_format'] = $this->defaultFormat;
}
if (!in_array($method, array('GET', 'HEAD', 'OPTIONS', 'TRACE'))) {
// GET the CSRF token first for writing requests.
diff --git a/tests/bin/replication.sh b/tests/bin/replication.sh
index e8e3e17..19d0201 100644
--- a/tests/bin/replication.sh
+++ b/tests/bin/replication.sh
@@ -11,4 +11,9 @@ php ~/drush.phar --yes --uri=http://localhost:8081 site-install --sites-subdir=8
php ~/drush.phar --yes --uri=http://localhost:8080 pm-enable entity_test, relaxed_test || true
php ~/drush.phar --yes --uri=http://localhost:8081 pm-enable entity_test, relaxed_test || true
+composer update
+
+# Check if CouchDB is running.
+curl http://127.0.0.1:5984
+
vendor/phpunit/phpunit/phpunit --verbose --debug --configuration ~/www/phpunit.travis.xml --bootstrap ~/www/core/tests/bootstrap.php
diff --git a/tests/phpunit.travis.xml b/tests/phpunit.travis.xml
index 8543e96..4e7561f 100644
--- a/tests/phpunit.travis.xml
+++ b/tests/phpunit.travis.xml
@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- TODO set checkForUnintentionallyCoveredCode="true" once https://www.drupal.org/node/2626832 is resolved. -->
+<!-- PHPUnit expects functional tests to be run with either a privileged user
+ or your current system user. See core/tests/README.md and
+ https://www.drupal.org/node/2116263 for details.
+-->
<phpunit bootstrap="./core/tests/bootstrap.php" colors="true"
checkForUnintentionallyCoveredCode="false">
<php>
@@ -8,19 +12,14 @@
<ini name="error_reporting" value="32767"/>
<!-- Do not limit the amount of memory tests take to run. -->
<ini name="memory_limit" value="-1"/>
- <env name="SIMPLETEST_BASE_URL" value=""/>
<!-- Example SIMPLETEST_BASE_URL value: http://localhost -->
- <env name="SIMPLETEST_DB" value="mysql://root@localhost/drupal0"/>
+ <env name="SIMPLETEST_BASE_URL" value=""/>
<!-- Example SIMPLETEST_DB value: mysql://username:password@localhost/databasename#table_prefix -->
+ <env name="SIMPLETEST_DB" value="mysql://root@localhost/drupal0"/>
</php>
<testsuites>
<testsuite name="integration">
- <directory>./modules/*/tests/src/Integration</directory>
- <directory>./sites/*/modules/*/tests/src/Integration</directory>
- <!-- Exclude Composer's vendor directory so we don't run tests there. -->
- <exclude>./core/vendor</exclude>
- <!-- Exclude Drush tests. -->
- <exclude>./drush/tests</exclude>
+ <file>./modules/relaxed/tests/src/TestSuites/IntegrationTestSuite.php</file>
</testsuite>
</testsuites>
<listeners>
diff --git a/tests/src/Integration/CouchDBReplicatorTest.php b/tests/src/Integration/CouchDBReplicatorTest.php
index f5145b8..50a4055 100644
--- a/tests/src/Integration/CouchDBReplicatorTest.php
+++ b/tests/src/Integration/CouchDBReplicatorTest.php
@@ -2,6 +2,8 @@
namespace Drupal\Tests\relaxed\Integration;
+require_once __DIR__ . '/ReplicationTestBase.php';
+
/**
* @group relaxed
*/
diff --git a/tests/src/Integration/PhpReplicatorTest.php b/tests/src/Integration/PhpReplicatorTest.php
index 9c011ca..6edb6ec 100644
--- a/tests/src/Integration/PhpReplicatorTest.php
+++ b/tests/src/Integration/PhpReplicatorTest.php
@@ -2,6 +2,8 @@
namespace Drupal\Tests\relaxed\Integration;
+require_once __DIR__ . '/ReplicationTestBase.php';
+
/**
* @group relaxed
*/
diff --git a/tests/src/Integration/ReplicateEndpointTest.php b/tests/src/Integration/ReplicateEndpointTest.php
index af32590..91e88d4 100644
--- a/tests/src/Integration/ReplicateEndpointTest.php
+++ b/tests/src/Integration/ReplicateEndpointTest.php
@@ -2,6 +2,8 @@
namespace Drupal\Tests\relaxed\Integration;
+require_once __DIR__ . '/ReplicationTestBase.php';
+
/**
* @group relaxed
*/
diff --git a/tests/src/TestSuites/IntegrationTestSuite.php b/tests/src/TestSuites/IntegrationTestSuite.php
new file mode 100644
index 0000000..c3ef2a6
--- /dev/null
+++ b/tests/src/TestSuites/IntegrationTestSuite.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Drupal\Tests\relaxed\TestSuites;
+
+require_once __DIR__ . '/TestSuiteBase.php';
+
+/**
+ * Discovers tests for the integration test suite.
+ */
+class IntegrationTestSuite extends TestSuiteBase {
+
+ /**
+ * Factory method which loads up a suite with all integration tests.
+ *
+ * @return static
+ * The test suite.
+ */
+ public static function suite() {
+ $root = dirname(dirname(dirname(__DIR__)));
+
+ $suite = new static('integration');
+ $suite->addTestsBySuiteNamespace($root, 'Integration');
+
+ return $suite;
+ }
+
+}
diff --git a/tests/src/TestSuites/TestSuiteBase.php b/tests/src/TestSuites/TestSuiteBase.php
new file mode 100644
index 0000000..f33d457
--- /dev/null
+++ b/tests/src/TestSuites/TestSuiteBase.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Drupal\Tests\relaxed\TestSuites;
+
+//require_once __DIR__ . '/../../../../../core/tests/TestSuites/TestSuiteBase.php';
+// For TravisCI.
+require_once __DIR__ . '/../../../../../../www/core/tests/TestSuites/TestSuiteBase.php';
+
+use Drupal\simpletest\TestDiscovery;
+use Drupal\Tests\TestSuites\TestSuiteBase as CoreTestSuiteBase;
+
+/**
+ * Base class for Drupal test suites.
+ */
+abstract class TestSuiteBase extends CoreTestSuiteBase {
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function addTestsBySuiteNamespace($root, $suite_namespace) {
+ if ($suite_namespace == 'Integration') {
+ $this->addTestFiles(TestDiscovery::scanDirectory("Drupal\\Tests\\", "$root/tests/src/$suite_namespace"));
+
+ $test_path = "$root/tests/src/$suite_namespace";
+ if (is_dir($test_path)) {
+ $this->addTestFiles(TestDiscovery::scanDirectory("Drupal\\Tests\\relaxed\\$suite_namespace\\", $test_path));
+ }
+ }
+ }
+
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment