diff --git a/config/install/replication.replication_settings.article.yml b/config/install/replication.replication_settings.article.yml
new file mode 100644
index 0000000..14f5a13
--- /dev/null
+++ b/config/install/replication.replication_settings.article.yml
@@ -0,0 +1,9 @@
+langcode: en
+status: true
+dependencies: {  }
+id: article
+label: Replicate only article entities
+filter_id: entity_type
+parameters:
+  types:
+    - node.article
diff --git a/config/install/replication.replication_settings.page.yml b/config/install/replication.replication_settings.page.yml
new file mode 100644
index 0000000..3465383
--- /dev/null
+++ b/config/install/replication.replication_settings.page.yml
@@ -0,0 +1,9 @@
+langcode: en
+status: true
+dependencies: {  }
+id: page
+label: Replicate only page entities
+filter_id: entity_type
+parameters:
+  types:
+    - node.page
diff --git a/config/install/replication.replication_settings.published.yml b/config/install/replication.replication_settings.published.yml
new file mode 100644
index 0000000..72555bf
--- /dev/null
+++ b/config/install/replication.replication_settings.published.yml
@@ -0,0 +1,8 @@
+langcode: en
+status: true
+dependencies: {  }
+id: published
+label: Replicate published entities
+filter_id: published
+parameters:
+  include_unpublishable_entities: false
diff --git a/config/schema/replication.replication_settings.schema.yml b/config/schema/replication.replication_settings.schema.yml
new file mode 100644
index 0000000..caa01d4
--- /dev/null
+++ b/config/schema/replication.replication_settings.schema.yml
@@ -0,0 +1,16 @@
+replication.replication_settings.*:
+  type: config_entity
+  label: 'Replication settings config'
+  mapping:
+    id:
+      type: string
+      label: 'ID'
+    label:
+      type: label
+      label: 'Label'
+    filter_id:
+      type: string
+      label: 'Filter plugin ID'
+    parameters:
+      type: ignore
+      label: 'Filter parameters'
diff --git a/src/Changes/Changes.php b/src/Changes/Changes.php
index 2a0372b..b16a092 100644
--- a/src/Changes/Changes.php
+++ b/src/Changes/Changes.php
@@ -7,8 +7,6 @@ use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\multiversion\Entity\Index\SequenceIndexInterface;
 use Drupal\multiversion\Entity\WorkspaceInterface;
 use Drupal\replication\Plugin\ReplicationFilterManagerInterface;
-// @todo where is the ParameterBagInterface???
-use Symfony\Component\HttpFoundation\ParameterBag;
 use Symfony\Component\Serializer\SerializerInterface;
 
 /**
@@ -18,8 +16,9 @@ class Changes implements ChangesInterface {
   use DependencySerializationTrait;
 
   /**
+   * The workspace to generate the changeset from.
+   *
    * @var string
-   *   The workspace to generate the changeset from.
    */
   protected $workspaceId;
 
@@ -45,20 +44,23 @@ class Changes implements ChangesInterface {
   protected $filterName;
 
   /**
-   * @var ParameterBag
-   *   The parameters passed to the filter function.
+   * The parameters passed to the filter plugin.
+   *
+   * @var array
    */
   protected $parameters;
 
   /**
+   * Whether to include entities in the changeset.
+   *
    * @var boolean
-   *   Whether to include entities in the changeset.
    */
   protected $includeDocs = FALSE;
 
   /**
+   * The sequence ID to start including changes from. Result includes $lastSeq.
+   *
    * @var int
-   *   The sequence ID to start including changes from. Result includes $lastSeq.
    */
   protected $lastSeq = 0;
 
@@ -88,7 +90,7 @@ class Changes implements ChangesInterface {
   /**
    * {@inheritdoc}
    */
-  public function parameters(ParameterBag $parameters = NULL) {
+  public function parameters(array $parameters = NULL) {
     $this->parameters = $parameters;
     return $this;
   }
@@ -118,15 +120,15 @@ class Changes implements ChangesInterface {
       ->getRange($this->lastSeq, NULL);
 
     // Setup filter plugin.
-    $parameters = ($this->parameters instanceof ParameterBag) ? $this->parameters : new ParameterBag();
+    $parameters = is_array($this->parameters) ? $this->parameters : [];
     $filter = NULL;
     if (is_string($this->filterName) && $this->filterName) {
-      $filter = $this->filterManager->createInstance($this->filterName);
+      $filter = $this->filterManager->createInstance($this->filterName, $parameters);
     }
     // If UUIDs are sent as a parameter, but no filter is set, automatically
     // select the "uuid" filter.
-    elseif ($parameters->has('uuids')) {
-      $filter = $this->filterManager->createInstance('uuid');
+    elseif (isset($parameters['uuids'])) {
+      $filter = $this->filterManager->createInstance('uuid', $parameters);
     }
 
     // Format the result array.
@@ -146,7 +148,7 @@ class Changes implements ChangesInterface {
       }
 
       // Filter the document.
-      if ($filter !== NULL && !$filter->filter($revision, $parameters)) {
+      if ($filter !== NULL && !$filter->filter($revision)) {
         continue;
       }
 
diff --git a/src/Changes/ChangesInterface.php b/src/Changes/ChangesInterface.php
index 1b42b86..5cc2006 100644
--- a/src/Changes/ChangesInterface.php
+++ b/src/Changes/ChangesInterface.php
@@ -2,8 +2,6 @@
 
 namespace Drupal\replication\Changes;
 
-use Symfony\Component\HttpFoundation\ParameterBag;
-
 /**
  * Define and build a changeset for a Workspace.
  *
@@ -29,13 +27,13 @@ interface ChangesInterface {
   /**
    * Set the parameters for the filter plugin.
    *
-   * @param ParameterBag $parameters
-   *   The parameters passed to the filter function.
+   * @param array $parameters
+   *   The parameters passed to the filter plugin.
    *
    * @return \Drupal\replication\Changes\ChangesInterface
    *   Returns $this.
    */
-  public function parameters(ParameterBag $parameters = NULL);
+  public function parameters(array $parameters = NULL);
 
   /**
    * Set the flag for including entities in the changeset.
diff --git a/src/Entity/ReplicationSettings.php b/src/Entity/ReplicationSettings.php
new file mode 100644
index 0000000..4d4ff0f
--- /dev/null
+++ b/src/Entity/ReplicationSettings.php
@@ -0,0 +1,67 @@
+<?php
+
+namespace Drupal\replication\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\replication\Entity\ReplicationSettingsInterface;
+
+/**
+ * Defines the replication settings entity.
+ *
+ * The replication settings are attached to a Workspace to define how that
+ * Workspace should be replicated.
+ *
+ * @ConfigEntityType(
+ *   id = "replication_settings",
+ *   label = @Translation("Replication settings"),
+ *   config_prefix = "replication_settings",
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "label"
+ *   }
+ * )
+ */
+class ReplicationSettings extends ConfigEntityBase implements ReplicationSettingsInterface {
+
+  /**
+   * An identifier for these replication settings.
+   *
+   * @var string
+   */
+  protected $id;
+
+  /**
+   * The human readable name for these replication settings.
+   *
+   * @var string
+   */
+  protected $label;
+
+  /**
+   * The plugin ID of a replication filter.
+   *
+   * @var string
+   */
+  protected $filter_id;
+
+  /**
+   * The replication filter parameters.
+   *
+   * @var array
+   */
+  protected $parameters;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFilterId() {
+    return $this->filter_id;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getParameters() {
+    return $this->parameters;
+  }
+}
diff --git a/src/Entity/ReplicationSettingsInterface.php b/src/Entity/ReplicationSettingsInterface.php
new file mode 100644
index 0000000..86defa4
--- /dev/null
+++ b/src/Entity/ReplicationSettingsInterface.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Drupal\replication\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+
+/**
+ * Provides an interface for replication settings entities.
+ */
+interface ReplicationSettingsInterface extends ConfigEntityInterface {
+
+  /**
+   * Get the plugin ID of the replication filter to use.
+   *
+   * @return string
+   */
+  public function getFilterId();
+
+  /**
+   * Get the replication filter parameters.
+   *
+   * @return array
+   */
+  public function getParameters();
+
+}
diff --git a/src/Plugin/ReplicationFilter/EntityTypeFilter.php b/src/Plugin/ReplicationFilter/EntityTypeFilter.php
index 5ab7393..ea105a4 100644
--- a/src/Plugin/ReplicationFilter/EntityTypeFilter.php
+++ b/src/Plugin/ReplicationFilter/EntityTypeFilter.php
@@ -4,13 +4,12 @@ namespace Drupal\replication\Plugin\ReplicationFilter;
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\replication\Plugin\ReplicationFilter\ReplicationFilterBase;
-use Symfony\Component\HttpFoundation\ParameterBag;
 
 /**
  * Provides a filter based on entity type.
  *
- * Supported parameters:
- *   entity_type: a comma delimited list of entity type id's to include
+ * Use the configuration "types" which is an array of values in the format
+ * "{entity_type_id}.{bundle}".
  *
  * @ReplicationFilter(
  *   id = "entity_type",
@@ -23,16 +22,41 @@ class EntityTypeFilter extends ReplicationFilterBase {
   /**
    * {@inheritdoc}
    */
-  public function filter(EntityInterface $entity, ParameterBag $parameters) {
-    if ($parameters->has('entity_type')) {
-      $types = $parameters->get('entity_type');
-    }
-    else {
-      $types = '';
+  public function defaultConfiguration() {
+    return [
+      'types' => [],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function filter(EntityInterface $entity) {
+    $configuration = $this->getConfiguration();
+    $types = $configuration['types'];
+
+    foreach ($types as $type) {
+      // Handle cases like "node.".
+      $type = trim($type, '.');
+
+      $split = explode('.', $type);
+
+      $entity_type_id = $split[0];
+      $bundle = isset($split[1]) ? $split[1] : NULL;
+
+      // Filter for only the entity type id.
+      if ($bundle == NULL && $entity->getEntityTypeId() == $entity_type_id) {
+        return TRUE;
+      }
+
+      // Filter for both the entity type id and bundle.
+      if ($entity->getEntityTypeId() == $entity_type_id
+        && $entity->bundle() == $bundle) {
+        return TRUE;
+      }
     }
-    $types = explode(',', $types);
-    $types = array_filter(array_map('trim', $types));
-    return in_array($entity->bundle(), $types);
+
+    return FALSE;
   }
 
 }
diff --git a/src/Plugin/ReplicationFilter/PublishedFilter.php b/src/Plugin/ReplicationFilter/PublishedFilter.php
index d103c7c..a049fb1 100644
--- a/src/Plugin/ReplicationFilter/PublishedFilter.php
+++ b/src/Plugin/ReplicationFilter/PublishedFilter.php
@@ -3,14 +3,17 @@
 namespace Drupal\replication\Plugin\ReplicationFilter;
 
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\node\NodeInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\replication\Plugin\ReplicationFilter\ReplicationFilterBase;
-use Symfony\Component\HttpFoundation\ParameterBag;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Provides a filter for published entities.
  *
- * Note: this filter will only work with NodeTypes.
+ * Use the configuration "include_unpublishable_entities" to determine what
+ * happens to entities that do not have a "status" field, if set to TRUE they
+ * will be included by the filter, else excluded.
  *
  * @ReplicationFilter(
  *   id = "published",
@@ -18,16 +21,64 @@ use Symfony\Component\HttpFoundation\ParameterBag;
  *   description = @Translation("Replicate only nodes that are published.")
  * )
  */
-class PublishedFilter extends ReplicationFilterBase {
+class PublishedFilter extends ReplicationFilterBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The entity type manager to check for "status" entity key.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * Constructs a new PublishedFilter.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->entityTypeManager = $entity_type_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static($configuration, $plugin_id, $plugin_definition, $container->get('entity_type.manager'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultConfiguration() {
+    return [
+      'include_unpublishable_entities' => FALSE,
+    ];
+  }
 
   /**
    * {@inheritdoc}
    */
-  public function filter(EntityInterface $entity, ParameterBag $parameters) {
-    if (!$entity instanceof NodeInterface) {
-      return false;
+  public function filter(EntityInterface $entity) {
+    // @todo handle translations?
+    // @todo is there an easier way to tell if an entity is published?
+    $definition = $this->entityTypeManager->getDefinition($entity->getEntityTypeId());
+    if ($definition->hasKey('status')) {
+      $field_name = $definition->getKey('status');
+      $field_definition = $entity->getFieldDefinition($field_name);
+      $property = $field_definition->getFieldStorageDefinition()->getMainPropertyName();
+      return (bool) $entity->get($field_name)->$property;
     }
-    return $entity->isPublished();
+    // Determine what to do with entities without a 'status' field.
+    $configuration = $this->getConfiguration();
+    return $configuration['include_unpublishable_entities'];
   }
 
 }
diff --git a/src/Plugin/ReplicationFilter/ReplicationFilterBase.php b/src/Plugin/ReplicationFilter/ReplicationFilterBase.php
index 4fa7b92..329a8cc 100644
--- a/src/Plugin/ReplicationFilter/ReplicationFilterBase.php
+++ b/src/Plugin/ReplicationFilter/ReplicationFilterBase.php
@@ -14,11 +14,15 @@ use Drupal\replication\Plugin\ReplicationFilterInterface;
 abstract class ReplicationFilterBase extends PluginBase implements ReplicationFilterInterface {
 
   /**
+   * The human readable label for the replication filter.
+   *
    * @var string
    */
   protected $label;
 
   /**
+   * The description of what the replication filter does.
+   *
    * @var string
    */
   protected $description;
@@ -37,4 +41,31 @@ abstract class ReplicationFilterBase extends PluginBase implements ReplicationFi
     return $this->description;
   }
 
+  /**
+   * {@inheritdoc}
+   *
+   * For replication filters, the plugin configuration contains what would be
+   * passed as "query_params" to a CouchDB filter function.
+   */
+  public function getConfiguration() {
+    if (empty($this->configuration)) {
+      return $this->defaultConfiguration();
+    }
+    return $this->configuration;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setConfiguration(array $configuration) {
+    $this->configuration = $configuration;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function calculateDependencies() {
+    return array();
+  }
+
 }
diff --git a/src/Plugin/ReplicationFilter/UuidFilter.php b/src/Plugin/ReplicationFilter/UuidFilter.php
index 61fdfa0..c7bd4ae 100644
--- a/src/Plugin/ReplicationFilter/UuidFilter.php
+++ b/src/Plugin/ReplicationFilter/UuidFilter.php
@@ -4,11 +4,12 @@ namespace Drupal\replication\Plugin\ReplicationFilter;
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\replication\Plugin\ReplicationFilter\ReplicationFilterBase;
-use Symfony\Component\HttpFoundation\ParameterBag;
 
 /**
  * Provides filtering by UUID.
  *
+ * Use the configuration "uuids" which is an array of uuids, e.g. "101,102".
+ *
  * Note: if the entity a UUID refers to references another entity, that
  * referenced entity's UUID must also be included in order to maintain data
  * integrity.
@@ -24,11 +25,18 @@ class UuidFilter extends ReplicationFilterBase {
   /**
    * {@inheritdoc}
    */
-  public function filter(EntityInterface $entity, ParameterBag $parameters) {
-    $uuids = $parameters->get('uuids') ?: '';
-    $uuids = explode(',', $uuids);
-    $uuids = array_map('trim', $uuids);
-    return in_array($entity->uuid(), $uuids);
+  public function defaultConfiguration() {
+    return [
+      'uuids' => [],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function filter(EntityInterface $entity) {
+    $configuration = $this->getConfiguration();
+    return in_array($entity->uuid(), $configuration['uuids']);
   }
 
 }
diff --git a/src/Plugin/ReplicationFilterInterface.php b/src/Plugin/ReplicationFilterInterface.php
index dae6556..c041c30 100644
--- a/src/Plugin/ReplicationFilterInterface.php
+++ b/src/Plugin/ReplicationFilterInterface.php
@@ -2,9 +2,9 @@
 
 namespace Drupal\replication\Plugin;
 
+use Drupal\Component\Plugin\ConfigurablePluginInterface;
 use Drupal\Component\Plugin\PluginInspectionInterface;
 use Drupal\Core\Entity\EntityInterface;
-use Symfony\Component\HttpFoundation\ParameterBag;
 
 /**
  * Defines a replication filter.
@@ -12,7 +12,7 @@ use Symfony\Component\HttpFoundation\ParameterBag;
  * Replication filters are used to filter out entities from a changeset during
  * replication.
  */
-interface ReplicationFilterInterface extends PluginInspectionInterface {
+interface ReplicationFilterInterface extends PluginInspectionInterface, ConfigurablePluginInterface {
 
   /**
    * Get the label for the filter.
@@ -33,12 +33,10 @@ interface ReplicationFilterInterface extends PluginInspectionInterface {
    *
    * @param EntityInterface $entity
    *   The entity to filter.
-   * @param ParameterBag $parameters
-   *   The parameters passed to the filter function.
    *
    * @return bool
    *   Return TRUE if it should be included, else FALSE.
    */
-  public function filter(EntityInterface $entity, ParameterBag $parameters);
+  public function filter(EntityInterface $entity);
 
 }
diff --git a/src/ReplicationTask/ReplicationTask.php b/src/ReplicationTask/ReplicationTask.php
index bb39a21..8ec4cd8 100644
--- a/src/ReplicationTask/ReplicationTask.php
+++ b/src/ReplicationTask/ReplicationTask.php
@@ -3,7 +3,6 @@
 namespace Drupal\replication\ReplicationTask;
 
 use Drupal\replication\ReplicationTask\ReplicationTaskInterface;
-use Symfony\Component\HttpFoundation\ParameterBag;
 
 /**
  * {@inheritdoc}
@@ -11,25 +10,20 @@ use Symfony\Component\HttpFoundation\ParameterBag;
 class ReplicationTask implements ReplicationTaskInterface {
 
   /**
+   * The ID of the filter plugin to use during replication.
+   *
    * @var string
-   *   The id of the filter plugin to use during replication.
    */
   protected $filterName;
 
   /**
-   * @var ParameterBag
-   *   The parameters passed to the filter function.
+   * The parameters passed to the filter function.
+   *
+   * @var array
    */
   protected $parameters;
 
   /**
-   * ReplicationTask constructor.
-   */
-  public function __construct() {
-    $this->parameters = new ParameterBag();
-  }
-
-  /**
    * {@inheritdoc}
    */
   public function setFilter($filter_name = NULL) {
@@ -47,7 +41,10 @@ class ReplicationTask implements ReplicationTaskInterface {
   /**
    * {@inheritdoc}
    */
-  public function setParameters(ParameterBag $parameters) {
+  public function setParameters(array $parameters = NULL) {
+    if ($parameters == NULL) {
+      $parameters = [];
+    }
     $this->parameters = $parameters;
     return $this;
   }
@@ -55,20 +52,11 @@ class ReplicationTask implements ReplicationTaskInterface {
   /**
    * {@inheritdoc}
    */
-  public function setParametersByArray(array $parameters_array = array()) {
-    $parameters = new ParameterBag($parameters_array);
-    return $this->setParameters($parameters);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function setParameter($name, $value) {
-    if (!$this->parameters instanceof ParameterBag) {
-      $parameters = new ParameterBag();
-      $this->setParameters($parameters);
+    if (!is_array($this->parameters)) {
+      $this->setParameters([]);
     }
-    $this->parameters->set($name, $value);
+    $this->parameters[$name] = $value;
     return $this;
   }
 
diff --git a/src/ReplicationTask/ReplicationTaskInterface.php b/src/ReplicationTask/ReplicationTaskInterface.php
index 22f7a13..3280745 100644
--- a/src/ReplicationTask/ReplicationTaskInterface.php
+++ b/src/ReplicationTask/ReplicationTaskInterface.php
@@ -2,8 +2,6 @@
 
 namespace Drupal\replication\ReplicationTask;
 
-use Symfony\Component\HttpFoundation\ParameterBag;
-
 /**
  * The replication settings between source and target.
  *
@@ -16,10 +14,10 @@ use Symfony\Component\HttpFoundation\ParameterBag;
 interface ReplicationTaskInterface {
 
   /**
-   * Set the id of the filter plugin to use during replication.
+   * Set the ID of the filter plugin to use during replication.
    *
    * @param string $filter_name
-   *   The plugin id of a ReplicationFilterInterface.
+   *   The plugin ID of a ReplicationFilterInterface.
    *
    * @return ReplicationTaskInterface
    *   Returns $this.
@@ -27,37 +25,23 @@ interface ReplicationTaskInterface {
   public function setFilter($filter_name = NULL);
 
   /**
-   * Get the id of the filter plugin to use during replication.
+   * Get the ID of the filter plugin to use during replication.
    *
    * @return string
-   *   The plugin id of a ReplicationFilterInterface.
+   *   The plugin ID of a ReplicationFilterInterface.
    */
   public function getFilter();
 
   /**
    * Set the parameters for the filter plugin.
    *
-   * @param ParameterBag $parameters
-   *   The parameters passed to the filter function.
-   *
-   * @return ReplicationTaskInterface
-   *   Returns $this.
-   */
-  public function setParameters(ParameterBag $parameters);
-
-  /**
-   * Set the parameters for the filter plugin using an array.
-   *
-   * The array input is converted to a ParameterBag and then passed to
-   * setParameters.
-   *
-   * @param array $parameters_array
+   * @param array|NULL $parameters
    *   An associative array of name-value parameters.
    *
    * @return ReplicationTaskInterface
    *   Returns $this.
    */
-  public function setParametersByArray(array $parameters_array = array());
+  public function setParameters(array $parameters = NULL);
 
   /**
    * Set a parameter for the filter plugin.
@@ -77,7 +61,7 @@ interface ReplicationTaskInterface {
   /**
    * Get the parameters for the filter plugin.
    *
-   * @return ParameterBag
+   * @return array
    *   The parameters passed to the filter plugin.
    */
   public function getParameters();
diff --git a/tests/src/Functional/ReplicationFilterTest.php b/tests/src/Functional/ReplicationFilterTest.php
index de0b364..57c6213 100644
--- a/tests/src/Functional/ReplicationFilterTest.php
+++ b/tests/src/Functional/ReplicationFilterTest.php
@@ -5,7 +5,6 @@ namespace Drupal\Tests\replication\Functional;
 use Drupal\multiversion\Entity\Workspace;
 use Drupal\node\Entity\Node;
 use Drupal\simpletest\WebTestBase;
-use Symfony\Component\HttpFoundation\ParameterBag;
 
 /**
  * Tests replication filters.
@@ -14,8 +13,14 @@ use Symfony\Component\HttpFoundation\ParameterBag;
  */
 class ReplicationFilterTest extends WebTestBase {
 
+  /**
+   * {@inheritdoc}
+   */
   protected $strictConfigSchema = FALSE;
 
+  /**
+   * {@inheritdoc}
+   */
   public static $modules = [
     'multiversion',
     'node',
@@ -24,8 +29,9 @@ class ReplicationFilterTest extends WebTestBase {
   ];
 
   /**
+   * The logged in user.
+   *
    * @var \Drupal\user\Entity\User
-   *   The logged in user.
    */
   protected $user;
 
@@ -70,9 +76,9 @@ class ReplicationFilterTest extends WebTestBase {
     $entity2->workspace = $workspace;
     $entity2->save();
 
-    $parameters = new ParameterBag(['uuids' => $entity1->uuid()]);
+    $parameters = ['uuids' => [$entity1->uuid()]];
     $changes = $changes_factory->get($workspace)->filter('uuid')->parameters($parameters)->getNormal();
-    $this->assertEqual(1, count($changes), 'Expect there is 1 entity in the changeset.');
+    $this->assertCount(1, $changes, 'Expect there is 1 entity in the changeset for UUIDs filter.');
   }
 
   /**
@@ -104,7 +110,7 @@ class ReplicationFilterTest extends WebTestBase {
     $entity2->save();
 
     $changes = $changes_factory->get($workspace)->filter('published')->getNormal();
-    $this->assertEqual(1, count($changes), 'Expect there is 1 entity in the changeset.');
+    $this->assertCount(1, $changes, 'Expect there is 1 entity in the changeset for published filter.');
   }
 
   /**
@@ -137,9 +143,9 @@ class ReplicationFilterTest extends WebTestBase {
     $entity2->workspace = $workspace;
     $entity2->save();
 
-    $parameters = new ParameterBag(['entity_type' => 'article']);
+    $parameters = ['types' => ['node.article']];
     $changes = $changes_factory->get($workspace)->filter('entity_type')->parameters($parameters)->getNormal();
-    $this->assertEqual(1, count($changes), 'Expect there is 1 entity in the changeset.');
+    $this->assertCount(1, $changes, 'Expect there is 1 entity in the changeset for entity type filter.');
   }
 
 }
diff --git a/tests/src/Kernel/Plugin/ReplicationFilter/PublishedFilterTest.php b/tests/src/Kernel/Plugin/ReplicationFilter/PublishedFilterTest.php
new file mode 100644
index 0000000..9e6baf5
--- /dev/null
+++ b/tests/src/Kernel/Plugin/ReplicationFilter/PublishedFilterTest.php
@@ -0,0 +1,136 @@
+<?php
+
+namespace Drupal\Tests\replication\Kernel\Plugin\ReplicationFilter;
+
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\block_content\Entity\BlockContentType;
+use Drupal\node\Entity\NodeType;
+
+/**
+ * Tests that the published filter parses parameters correctly.
+ *
+ * @group replication
+ */
+class PublishedFilterTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $strictConfigSchema = FALSE;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'block',
+    'block_content',
+    'key_value',
+    'multiversion',
+    'node',
+    'replication',
+    'serialization',
+    'system',
+    'user',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    $node_type = NodeType::create([
+      'type' => 'test',
+      'label' => 'Test',
+    ]);
+    $node_type->save();
+
+    $bundle_type = BlockContentType::create([
+      'id' => 'test',
+      'label' => 'Test',
+    ]);
+    $bundle_type->save();
+  }
+
+  /**
+   * Test filtering published entities.
+   *
+   * @param bool $include_unpublishable_entities
+   *   The plugin configuration value for including unpublishable entities.
+   * @param string $entity_type_id
+   *   The entity type id of the entity to create for testing.
+   * @param array $entity_values
+   *   The values with which to create the entity.
+   * @param bool $expected
+   *   The expected return value from the filter function.
+   *
+   * @dataProvider filterTestProvider
+   */
+  public function testFilter($include_unpublishable_entities, $entity_type_id, $entity_values, $expected) {
+    /** @var \Drupal\replication\Plugin\ReplicationFilterManagerInterface $filter_manager */
+    $filter_manager = $this->container->get('plugin.manager.replication_filter');
+    $configuration = [
+      'include_unpublishable_entities' => $include_unpublishable_entities,
+    ];
+    $filter = $filter_manager->createInstance('published', $configuration);
+    $entity = $this->container
+        ->get('entity_type.manager')
+        ->getStorage($entity_type_id)
+        ->create($entity_values);
+
+    $value = $filter->filter($entity);
+
+    $this->assertSame($expected, $value);
+  }
+
+  /**
+   * Test default configuration for published filter.
+   */
+  public function testDefaultConfig() {
+    /** @var \Drupal\replication\Plugin\ReplicationFilterManagerInterface $filter_manager */
+    $filter_manager = $this->container->get('plugin.manager.replication_filter');
+    $filter = $filter_manager->createInstance('published');
+    $entity = $this->container
+        ->get('entity_type.manager')
+        ->getStorage('block_content')
+        ->create(['type' => 'test']);
+
+    $value = $filter->filter($entity);
+
+    // By default entities with no status entity key are filtered out.
+    $this->assertFalse($value);
+  }
+
+  /**
+   * Provide test cases for the "entity_type_id" and "bundle" parameters.
+   *
+   * Note: the only node bundle is 'test' and the only block content bundle is
+   * 'test'.
+   *
+   * @return array
+   *   An array of arrays, each array being the arguments to filterTest().
+   */
+  public function filterTestProvider() {
+    $published_node = [
+      'type' => 'test',
+      'status' => TRUE,
+    ];
+
+    $unpublished_node = [
+      'type' => 'test',
+      'status' => FALSE,
+    ];
+
+    $block = [
+      'type' => 'test',
+    ];
+
+    return [
+      [FALSE, 'node', $published_node, TRUE],
+      [FALSE, 'node', $unpublished_node, FALSE],
+      [TRUE, 'block_content', $block, TRUE],
+      [FALSE, 'block_content', $block, FALSE],
+    ];
+  }
+
+}
diff --git a/tests/src/Kernel/ReplicationSettingsTest.php b/tests/src/Kernel/ReplicationSettingsTest.php
new file mode 100644
index 0000000..b4c2632
--- /dev/null
+++ b/tests/src/Kernel/ReplicationSettingsTest.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace Drupal\Tests\replication\Kernel;
+
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Test operations on ReplicationSettings config entity.
+ *
+ * @group replication
+ */
+class ReplicationSettingsTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $strictConfigSchema = FALSE;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'user',
+    'serialization',
+    'key_value',
+    'multiversion',
+    'replication',
+  ];
+
+  /**
+   * Test creation of ReplicationSettings config entity.
+   */
+  public function testCreation() {
+    $this->installEntitySchema('replication_settings');
+    $entityTypeManager = $this->container->get('entity_type.manager');
+    $entity = $entityTypeManager->getStorage('replication_settings')->create([
+      'id' => 'test',
+      'label' => 'Replication settings test',
+      'filter_id' => 'entity_type',
+      'parameters' => ['entity_type_id' => 'node', 'bundle' => 'article'],
+    ]);
+    $entity->save();
+
+    $entity = $entityTypeManager->getStorage('replication_settings')->load('test');
+
+    $this->assertEquals($entity->id(), 'test', 'Test replication settings config entity successfully saved.');
+  }
+
+}
diff --git a/tests/src/Unit/Plugin/ReplicationFilter/EntityTypeFilterTest.php b/tests/src/Unit/Plugin/ReplicationFilter/EntityTypeFilterTest.php
index 4d97d94..6b5d8c8 100644
--- a/tests/src/Unit/Plugin/ReplicationFilter/EntityTypeFilterTest.php
+++ b/tests/src/Unit/Plugin/ReplicationFilter/EntityTypeFilterTest.php
@@ -4,7 +4,6 @@ namespace Drupal\Tests\replication\Unit\Plugin\ReplicationFilter;
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\replication\Plugin\ReplicationFilter\EntityTypeFilter;
-use Symfony\Component\HttpFoundation\ParameterBag;
 
 /**
  * Tests that the entity type filter parses parameters correctly.
@@ -16,44 +15,60 @@ class EntityTypeFilterTest extends \PHPUnit_Framework_TestCase {
   /**
    * Test filtering entity types.
    *
+   * @param string $types
+   *   The types filter parameter.
+   * @param string $expected
+   *   The expected return value from the filter method.
+   *
    * @dataProvider filterTestProvider
    */
-  public function testFilter($entity_type, $parameter_value, $expected) {
+  public function testFilter($types, $expected) {
     // Use a mock builder for the class under test to eliminate the need to
-    // mock all the dependencies. This is OK since the method under test is a
-    // pure function, i.e. does not use the state createdy by the constructor.
+    // mock all the dependencies. The method under test uses the $configuration
+    // set by the constructor, but is retrieved via a get method we can stub.
     $filter = $this->getMockBuilder(EntityTypeFilter::class)
       ->disableOriginalConstructor()
-      ->setMethods(NULL)
+      ->setMethods(['getConfiguration'])
       ->getMock();
+    $configuration = [
+      'types' => $types,
+    ];
+    $filter->method('getConfiguration')
+      ->willReturn($configuration);
     $entity = $this->getMock(EntityInterface::class);
+    $entity->method('getEntityTypeId')
+      ->willReturn('node');
     $entity->method('bundle')
       ->willReturn('article');
-    $parameters = new ParameterBag(['entity_type' => $parameter_value]);
 
-    $value = $filter->filter($entity, $parameters);
+    $value = $filter->filter($entity);
 
     $this->assertEquals($expected, $value);
   }
 
   /**
-   * Provide test cases for the "entity_type" parameter.
+   * Provide test cases for the "entity_type_id" and "bundle" parameters.
    */
   public function filterTestProvider() {
     return [
       // Test singular parameter values.
-      ['article', 'article', TRUE],
-      ['article', 'page', FALSE],
+      [['node'], TRUE],
+      [['node.article'], TRUE],
+      [['node.page'], FALSE],
       // Test multiple parameter values.
-      ['article', 'page,article', TRUE],
-      ['article', 'article,page', TRUE],
-      ['article', 'page,news', FALSE],
+      [['block', 'node'], TRUE],
+      [['node.article', 'node.page'], TRUE],
+      [['node.page', 'node.article'], TRUE],
+      [['node.test', 'node.page'], FALSE],
       // Test bad data that might be entered into the parameters:
-      ['article', '', FALSE],
-      ['article', NULL, FALSE],
-      ['article', FALSE, FALSE],
-      ['article', TRUE, FALSE],
-      ['article', 0, FALSE],
+      [[''], FALSE],
+      [[','], FALSE],
+      [[',node'], FALSE],
+      [['..'], FALSE],
+      [[NULL], FALSE],
+      [[FALSE], FALSE],
+      [[TRUE], FALSE],
+      [[0], FALSE],
     ];
   }
 
diff --git a/tests/src/Unit/Plugin/ReplicationFilter/UuidFilterTest.php b/tests/src/Unit/Plugin/ReplicationFilter/UuidFilterTest.php
index a16be60..0770074 100644
--- a/tests/src/Unit/Plugin/ReplicationFilter/UuidFilterTest.php
+++ b/tests/src/Unit/Plugin/ReplicationFilter/UuidFilterTest.php
@@ -4,7 +4,6 @@ namespace Drupal\Tests\replication\Unit\Plugin\ReplicationFilter;
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\replication\Plugin\ReplicationFilter\UuidFilter;
-use Symfony\Component\HttpFoundation\ParameterBag;
 
 /**
  * Tests that the uuid filter parses parameters correctly.
@@ -20,18 +19,22 @@ class UuidFilterTest extends \PHPUnit_Framework_TestCase {
    */
   public function testFilter($uuid, $parameter_value, $expected) {
     // Use a mock builder for the class under test to eliminate the need to
-    // mock all the dependencies. This is OK since the method under test is a
-    // pure function, i.e. does not use the state createdy by the constructor.
+    // mock all the dependencies. The method under test uses the $configuration
+    // set by the constructor, but is retrieved via a get method we can stub.
     $filter = $this->getMockBuilder(UuidFilter::class)
       ->disableOriginalConstructor()
-      ->setMethods(NULL)
+      ->setMethods(['getConfiguration'])
       ->getMock();
+    $configuration = [
+      'uuids' => $parameter_value,
+    ];
+    $filter->method('getConfiguration')
+      ->willReturn($configuration);
     $entity = $this->getMock(EntityInterface::class);
     $entity->method('uuid')
       ->willReturn($uuid);
-    $parameters = new ParameterBag(['uuids' => $parameter_value]);
 
-    $value = $filter->filter($entity, $parameters);
+    $value = $filter->filter($entity);
 
     $this->assertEquals($expected, $value);
   }
@@ -42,16 +45,15 @@ class UuidFilterTest extends \PHPUnit_Framework_TestCase {
   public function filterTestProvider() {
     return [
       // Test singular parameter values.
-      ['123', '123', TRUE],
-      ['123', '456', FALSE],
+      ['123', ['123'], TRUE],
+      ['123', ['456'], FALSE],
       // Test multiple parameter values.
-      ['123', '123,456', TRUE],
-      ['123', '456,789', FALSE],
+      ['123', ['123', '456'], TRUE],
+      ['123', ['456', '789'], FALSE],
       // Test bad data that might be entered into the parameters:
-      ['123', '123, 456', TRUE],
-      ['123', '123 , 456', TRUE],
-      ['123', '0', FALSE],
-      ['123', 'NULL', FALSE],
+      ['123', ['123 '], FALSE],
+      ['123', [0], FALSE],
+      ['123', [NULL], FALSE],
     ];
   }
 
@@ -69,9 +71,8 @@ class UuidFilterTest extends \PHPUnit_Framework_TestCase {
     $entity = $this->getMock(EntityInterface::class);
     $entity->method('uuid')
       ->willReturn('123');
-    $parameters = new ParameterBag();
 
-    $value = $filter->filter($entity, $parameters);
+    $value = $filter->filter($entity, []);
 
     $this->assertEquals(FALSE, $value);
   }
