diff --git a/core/modules/migrate/config/schema/migrate.data_types.schema.yml b/core/modules/migrate/config/schema/migrate.data_types.schema.yml
index edb628a..d887785 100644
--- a/core/modules/migrate/config/schema/migrate.data_types.schema.yml
+++ b/core/modules/migrate/config/schema/migrate.data_types.schema.yml
@@ -14,6 +14,10 @@ migrate_destination:
 migrate_source:
   type: migrate_plugin
   label: 'Source'
+  mapping:
+    constants:
+      type: ignore
+      label: 'Constants'
 
 # Base schema for migrate source plugins that extend
 # \Drupal\migrate\Plugin\migrate\source\SqlBase.
diff --git a/core/modules/migrate_drupal/config/optional/migrate.migration.d7_user.yml b/core/modules/migrate_drupal/config/optional/migrate.migration.d7_user.yml
new file mode 100755
index 0000000..8973802
--- /dev/null
+++ b/core/modules/migrate_drupal/config/optional/migrate.migration.d7_user.yml
@@ -0,0 +1,41 @@
+id: d7_user
+migration_tags:
+  - Drupal 7
+source:
+  plugin: d7_user
+destination:
+  plugin: entity:user
+process:
+  uid: uid
+  name: name
+  pass: pass
+  mail: mail
+  status: status
+  signature: signature
+  # TODO: whe the d7 text format migration is written, uncomment the following.
+#  signature_format:
+#    plugin: migration
+#    migration: d6_filter_format
+#    source: signature_format
+#    no_stub: 1
+  created: created
+  changed: changed
+  access: access
+  login: login
+  timezone: timezone
+  langcode: language
+  preferred_langcode: language
+  preferred_admin_langcode: language
+  init: init
+  roles:
+    plugin: migration
+    migration: d7_user_role
+    source: roles
+migration_dependencies:
+  required:
+    - d7_user_role
+dependencies:
+  module:
+    - user
+  config:
+    - migrate.migration.d7_user_role
diff --git a/core/modules/migrate_drupal/config/optional/migrate.migration.d7_user_flood.yml b/core/modules/migrate_drupal/config/optional/migrate.migration.d7_user_flood.yml
new file mode 100755
index 0000000..b568949
--- /dev/null
+++ b/core/modules/migrate_drupal/config/optional/migrate.migration.d7_user_flood.yml
@@ -0,0 +1,23 @@
+id: d7_user_flood
+migration_tags:
+  - Drupal 7
+source:
+  plugin: variable
+  variables:
+    - user_failed_login_identifier_uid_only
+    - user_failed_login_ip_limit
+    - user_failed_login_ip_window
+    - user_failed_login_user_window
+    - user_failed_login_user_limit
+process:
+  uid_only: user_failed_login_identifier_uid_only
+  ip_limit: user_failed_login_ip_limit
+  ip_window: user_failed_login_ip_window
+  user_limit: user_failed_login_user_limit
+  user_window: user_failed_login_user_window
+destination:
+  plugin: config
+  config_name: user.flood
+dependencies:
+  module:
+    - user
diff --git a/core/modules/migrate_drupal/config/optional/migrate.migration.d7_user_mail.yml b/core/modules/migrate_drupal/config/optional/migrate.migration.d7_user_mail.yml
new file mode 100644
index 0000000..8111e59
--- /dev/null
+++ b/core/modules/migrate_drupal/config/optional/migrate.migration.d7_user_mail.yml
@@ -0,0 +1,42 @@
+id: d7_user_mail
+label: Drupal 7 user mail configuration
+migration_tags:
+  - Drupal 7
+source:
+  plugin: variable
+  variables:
+    - user_mail_status_activated_subject
+    - user_mail_status_activated_body
+    - user_mail_password_reset_subject
+    - user_mail_password_reset_body
+    - user_mail_status_deleted_subject
+    - user_mail_status_deleted_body
+    - user_mail_register_admin_created_subject
+    - user_mail_register_admin_created_body
+    - user_mail_register_no_approval_required_subject
+    - user_mail_register_no_approval_required_body
+    - user_mail_user_mail_register_pending_approval_subject
+    - user_mail_user_mail_register_pending_approval_body
+    - user_mail_status_blocked_subject
+    - user_mail_status_blocked_body
+process:
+  'status_activated/subject': user_mail_status_activated_subject
+  'status_activated/body': user_mail_status_activated_body
+  'password_reset/subject': user_mail_password_reset_subject
+  'password_reset/body': user_mail_password_reset_body
+  'cancel_confirm/subject': user_mail_status_deleted_subject
+  'cancel_confirm/body': user_mail_status_deleted_body
+  'register_admin_created/subject': user_mail_register_admin_created_subject
+  'register_admin_created/body': user_mail_register_admin_created_body
+  'register_no_approval_required/subject': user_mail_register_no_approval_required_subject
+  'register_no_approval_required/body': user_mail_register_no_approval_required_body
+  'register_pending_approval/subject': user_mail_user_mail_register_pending_approval_subject
+  'register_pending_approval/body': user_mail_user_mail_register_pending_approval_body
+  'status_blocked/subject': user_mail_status_blocked_subject
+  'status_blocked/body': user_mail_status_blocked_body
+destination:
+  plugin: config
+  config_name: user.mail
+dependencies:
+  module:
+    - user
diff --git a/core/modules/migrate_drupal/config/optional/migrate.migration.d7_user_role.yml b/core/modules/migrate_drupal/config/optional/migrate.migration.d7_user_role.yml
new file mode 100755
index 0000000..01eeb85
--- /dev/null
+++ b/core/modules/migrate_drupal/config/optional/migrate.migration.d7_user_role.yml
@@ -0,0 +1,46 @@
+id: d7_user_role
+label: Drupal 7 user roles
+migration_tags:
+  - Drupal 7
+source:
+  plugin: d7_user_role
+process:
+  id:
+    -
+      plugin: machine_name
+      source: name
+    -
+      plugin: dedupe_entity
+      entity_type: user_role
+      field: id
+      length: 32
+  label: name
+  permissions:
+    -
+      plugin: static_map
+      source: permissions
+      bypass: true
+      map:
+        'use PHP for block visibility': 'use PHP for settings'
+        'administer site-wide contact form': 'administer contact forms'
+        'post comments without approval': 'skip comment approval'
+        'edit own blog entries' : 'edit own blog content'
+        'edit any blog entry' : 'edit any blog content'
+        'delete own blog entries' : 'delete own blog content'
+        'delete any blog entry' : 'delete any blog content'
+        'create forum topics' : 'create forum content'
+        'delete any forum topic' : 'delete any forum content'
+        'delete own forum topics' : 'delete own forum content'
+        'edit any forum topic' : 'edit any forum content'
+        'edit own forum topics' : 'edit own forum content'
+    # - plugin: system_update_7000
+    # - plugin: node_update_7008
+    - plugin: flatten
+destination:
+  plugin: entity:user_role
+migration_dependencies:
+  optional:
+    - d7_filter_format
+dependencies:
+  module:
+    - user
diff --git a/core/modules/migrate_drupal/src/Plugin/migrate/source/d7/Role.php b/core/modules/migrate_drupal/src/Plugin/migrate/source/d7/Role.php
new file mode 100755
index 0000000..f150954
--- /dev/null
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/source/d7/Role.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal\Plugin\migrate\source\d7\Role.
+ */
+
+namespace Drupal\migrate_drupal\Plugin\migrate\source\d7;
+
+use Drupal\migrate\Row;
+use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
+
+
+/**
+ * Drupal 7 role source from database.
+ *
+ * @MigrateSource(
+ *   id = "d7_user_role"
+ * )
+ */
+class Role extends DrupalSqlBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    return $this->select('role', 'r')
+      ->fields('r', array('rid', 'name'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    return array(
+      'rid' => $this->t('Role ID.'),
+      'name' => $this->t('The name of the user role.'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function prepareRow(Row $row) {
+    $permissions = $this->select('role_permission', 'rp')
+      ->fields('rp', ['permission'])
+      ->condition('rid', $row->getSourceProperty('rid'))
+      ->execute()
+      ->fetchCol();
+    $row->setSourceProperty('permissions', $permissions);
+
+    return parent::prepareRow($row);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    return ['rid' => ['type' => 'integer']];
+  }
+
+}
diff --git a/core/modules/migrate_drupal/src/Plugin/migrate/source/d7/User.php b/core/modules/migrate_drupal/src/Plugin/migrate/source/d7/User.php
new file mode 100755
index 0000000..a1ea43d
--- /dev/null
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/source/d7/User.php
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal\Plugin\migrate\source\d7\User.
+ */
+
+namespace Drupal\migrate_drupal\Plugin\migrate\source\d7;
+
+use Drupal\migrate\Plugin\SourceEntityInterface;
+use Drupal\migrate\Row;
+use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
+
+/**
+ * Extract users from Drupal 7 database.
+ *
+ * @MigrateSource(
+ *   id = "d7_user"
+ * )
+ */
+class User extends DrupalSqlBase implements SourceEntityInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    return $this->select('users', 'u')
+      ->fields('u', array_keys($this->fields()))
+      ->condition('uid', 0, '>');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function prepareRow(Row $row) {
+    $roles = $this->select('role', 'r')
+      ->fields('r', ['rid', 'name']);
+    $roles->join('users_roles', 'ur', 'ur.rid = r.rid');
+    // These extra fields are not needed once #2499835 lands.
+    $roles->fields('ur', ['uid', 'rid']);
+    $roles->condition('ur.uid', $row->getSourceProperty('uid'));
+    $row->setSourceProperty('roles', $roles->execute()->fetchAllKeyed(2, 3));
+  }
+
+  /**
+  * {@inheritdoc}
+  */
+  public function fields() {
+    return array(
+      'uid' => $this->t('User ID'),
+      'name' => $this->t('Username'),
+      'pass' => $this->t('Password'),
+      'mail' => $this->t('Email address'),
+      'signature' => $this->t('Signature'),
+      'signature_format' => $this->t('Signature format'),
+      'created' => $this->t('Registered timestamp'),
+      'access' => $this->t('Last access timestamp'),
+      'login' => $this->t('Last login timestamp'),
+      'status' => $this->t('Status'),
+      'timezone' => $this->t('Timezone'),
+      'language' => $this->t('Language'),
+      'picture' => $this->t('Picture'),
+      'init' => $this->t('Init'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    return array(
+      'uid' => array(
+        'type' => 'integer',
+        'alias' => 'u',
+      ),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function bundleMigrationRequired() {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function entityTypeId() {
+    return 'user';
+  }
+
+}
\ No newline at end of file
diff --git a/core/modules/migrate_drupal/src/Tests/Table/d7/Users.php b/core/modules/migrate_drupal/src/Tests/Table/d7/Users.php
index 33d7f59..e5d9f1d 100644
--- a/core/modules/migrate_drupal/src/Tests/Table/d7/Users.php
+++ b/core/modules/migrate_drupal/src/Tests/Table/d7/Users.php
@@ -88,7 +88,7 @@ public function load() {
         'status' => array(
           'type' => 'int',
           'not null' => TRUE,
-          'length' => '4',
+          'length' => '11',
           'default' => '0',
         ),
         'timezone' => array(
@@ -139,8 +139,25 @@ public function load() {
       'init',
       'data',
     ))
-    ->execute();
+    ->values(array(
+      'uid' => '2',
+      'name' => 'Odo',
+      'pass' => '$S$DVpvPItXvnsmF3giVEe7Jy2lG.SCoEs8uKwpHsyPvdeNAaNZYxZ8',
+      'mail' => 'odo@local.host',
+      'theme' => '',
+      'signature' => '',
+      'signature_format' => 'filtered_html',
+      'created' => '1432750741',
+      'access' => '0',
+      'login' => '0',
+      'status' => '1',
+      'timezone' => 'America/Chicago',
+      'language' => '',
+      'picture' => '0',
+      'init' => 'odo@local.host',
+      'data' => 'a:1:{s:7:"contact";i:1;}',
+    ))->execute();
   }
 
 }
-#bb60d488e9420b75be9bb507fc35df8b
+#e53c042361fbbccb2bbc9918c072e19f
diff --git a/core/modules/migrate_drupal/src/Tests/Table/d7/Variable.php b/core/modules/migrate_drupal/src/Tests/Table/d7/Variable.php
index c66d152..423be1c 100644
--- a/core/modules/migrate_drupal/src/Tests/Table/d7/Variable.php
+++ b/core/modules/migrate_drupal/src/Tests/Table/d7/Variable.php
@@ -101,7 +101,7 @@ public function load() {
       'value' => 's:43:"_vWFj-dRR2rNoHDwl7N__J9uZNutDcLz3w4tlPJzRAM";',
     ))->values(array(
       'name' => 'cron_last',
-      'value' => 'i:1432653550;',
+      'value' => 'i:1432750697;',
     ))->values(array(
       'name' => 'css_js_query_string',
       'value' => 's:6:"nihmmw";',
@@ -304,6 +304,12 @@ public function load() {
       'name' => 'suppress_itok_output',
       'value' => 'b:1;',
     ))->values(array(
+      'name' => 'taxonomy_override_selector',
+      'value' => 'b:1;',
+    ))->values(array(
+      'name' => 'taxonomy_terms_per_page_admin',
+      'value' => 'i:84;',
+    ))->values(array(
       'name' => 'theme_default',
       'value' => 's:6:"bartik";',
     ))->values(array(
@@ -418,4 +424,4 @@ public function load() {
   }
 
 }
-#d17f3e6a80f5f51c105acf809f1b4851
+#59776f583c1268ef59315caaef4996e5
diff --git a/core/modules/migrate_drupal/src/Tests/d7/MigrateUserFloodTest.php b/core/modules/migrate_drupal/src/Tests/d7/MigrateUserFloodTest.php
new file mode 100644
index 0000000..afdb7ba
--- /dev/null
+++ b/core/modules/migrate_drupal/src/Tests/d7/MigrateUserFloodTest.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal\Tests\d7\MigrateUserFloodTest.
+ */
+
+namespace Drupal\migrate_drupal\Tests\d7;
+
+use Drupal\migrate\MigrateExecutable;
+
+/**
+ * Migrates user flood control configuration.
+ *
+ * @group migrate_drupal 7.x
+ * @dumpFile d7/Variable.php
+ * @migration d7_user_flood
+ */
+class MigrateUserFloodTest extends MigrateDrupal7TestBase {
+
+  /**
+   * The modules to be enabled during the test.
+   *
+   * @var array
+   */
+  static $modules = array('system');
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installConfig(['user']);
+
+    // Load database dumps to provide source data.
+    $dumps = array(
+      $this->getDumpDirectory() . '/Variable.php',
+    );
+    $this->loadDumps($dumps);
+
+    // Migrate users.
+    $migration = entity_load('migration', 'd7_user_flood');
+    $executable = new MigrateExecutable($migration, $this);
+    $executable->import();
+  }
+
+  /**
+   * Tests the migration.
+   */
+  public function testMigration() {
+    $expected = [
+      'uid_only' => TRUE,
+      'ip_limit' => 30,
+      'ip_window' => 7200,
+      'user_limit' => 22,
+      'user_window' => 86400,
+    ];
+    $this->assertIdentical($expected, \Drupal::config('user.flood')->get());
+  }
+
+}
diff --git a/core/modules/migrate_drupal/src/Tests/d7/MigrateUserMailTest.php b/core/modules/migrate_drupal/src/Tests/d7/MigrateUserMailTest.php
new file mode 100644
index 0000000..878a40f
--- /dev/null
+++ b/core/modules/migrate_drupal/src/Tests/d7/MigrateUserMailTest.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal\Tests\d7\MigrateUserMailTest.
+ */
+
+namespace Drupal\migrate_drupal\Tests\d7;
+
+use Drupal\migrate\MigrateExecutable;
+
+/**
+ * Migrates user mail configuration.
+ *
+ * @group migrate_drupal 7.x
+ * @dumpFile d7/Variable.php
+ * @migration d7_user_mail
+ */
+class MigrateUserMailTest extends MigrateDrupal7TestBase {
+
+  /**
+   * The modules to be enabled during the test.
+   *
+   * @var array
+   */
+  static $modules = ['system', 'user'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installConfig(['user']);
+
+    // Load database dumps to provide source data.
+    $dumps = [
+      $this->getDumpDirectory() . '/Variable.php',
+    ];
+    $this->loadDumps($dumps);
+
+    // Migrate users.
+    $migration = entity_load('migration', 'd7_user_mail');
+    $executable = new MigrateExecutable($migration, $this);
+    $executable->import();
+  }
+
+  /**
+   * Tests the migration.
+   */
+  public function testMigration() {
+    $config = \Drupal::config('user.mail');
+  }
+
+}
diff --git a/core/modules/migrate_drupal/src/Tests/d7/MigrateUserRoleTest.php b/core/modules/migrate_drupal/src/Tests/d7/MigrateUserRoleTest.php
new file mode 100644
index 0000000..7786804
--- /dev/null
+++ b/core/modules/migrate_drupal/src/Tests/d7/MigrateUserRoleTest.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal\Tests\d7\MigrateUserRoleTest.
+ */
+
+namespace Drupal\migrate_drupal\Tests\d7;
+
+use Drupal\Core\Database\Database;
+use Drupal\migrate\MigrateExecutable;
+use Drupal\user\Entity\Role;
+use Drupal\user\RoleInterface;
+
+/**
+ * Upgrade user roles to user.role.*.yml.
+ *
+ * @group migrate_drupal 7.x
+ * @dumpFile d7/Role.php
+ * @dumpFile d7/RolePermission.php
+ * @dumpFile d7/Variable.php
+ * @migration d7_user_role
+ */
+class MigrateUserRoleTest extends MigrateDrupal7TestBase {
+
+  /**
+   * The modules to be enabled during the test.
+   *
+   * @var array
+   */
+  static $modules = array('user');
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    /** @var \Drupal\migrate\entity\Migration $migration */
+    $migration = entity_load('migration', 'd7_user_role');
+    $dumps = array(
+      $this->getDumpDirectory() . '/Role.php',
+      $this->getDumpDirectory() . '/RolePermission.php',
+      $this->getDumpDirectory() . '/Variable.php',
+    );
+    $this->prepare($migration, $dumps);
+    $executable = new MigrateExecutable($migration, $this);
+    $executable->import();
+  }
+
+  protected function assertEntity($id, $label, $original_rid = NULL) {
+    /** @var \Drupal\user\RoleInterface $entity */
+    $entity = Role::load($id);
+    $this->assertTrue($entity instanceof RoleInterface);
+    $this->assertIdentical($label, $entity->label());
+    if (isset($original_rid)) {
+      $permissions = Database::getConnection('default', 'migrate')
+        ->select('role_permission', 'rp')
+        ->fields('rp', ['permission'])
+        ->condition('rid', $original_rid)
+        ->execute()
+        ->fetchCol();
+      $this->assertIdentical($permissions, $entity->getPermissions());
+    }
+  }
+
+  /**
+   * Tests user role migration.
+   */
+  public function testUserRole() {
+    $this->assertEntity('anonymous_user', 'anonymous user', 1);
+    $this->assertEntity('authenticated_user', 'authenticated user', 2);
+    $this->assertEntity('administrator', 'administrator', 3);
+  }
+
+}
diff --git a/core/modules/migrate_drupal/src/Tests/d7/MigrateUserTest.php b/core/modules/migrate_drupal/src/Tests/d7/MigrateUserTest.php
new file mode 100644
index 0000000..368ae28
--- /dev/null
+++ b/core/modules/migrate_drupal/src/Tests/d7/MigrateUserTest.php
@@ -0,0 +1,88 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate_drupal\Tests\d7\MigrateUserTest.
+ */
+
+namespace Drupal\migrate_drupal\Tests\d7;
+
+use Drupal\user\Entity\User;
+use Drupal\file\Entity\File;
+use Drupal\Core\Database\Database;
+use Drupal\migrate\MigrateExecutable;
+use Drupal\user\RoleInterface;
+use Drupal\user\UserInterface;
+
+/**
+ * Users migration.
+ *
+ * @group migrate_drupal 7.x
+ * @dumpFile d7/Role.php
+ * @dumpFile d7/RolePermission.php
+ * @dumpFile d7/Users.php
+ * @dumpFile d7/UsersRoles.php
+ * @migration d7_user_role
+ * @migration d7_user
+ */
+class MigrateUserTest extends MigrateDrupal7TestBase {
+
+  /**
+   * The modules to be enabled during the test.
+   *
+   * @var array
+   */
+  static $modules = array('user');
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // Load database dumps to provide source data.
+    $dumps = array(
+      $this->getDumpDirectory() . '/Role.php',
+      $this->getDumpDirectory() . '/RolePermission.php',
+      $this->getDumpDirectory() . '/Users.php',
+      $this->getDumpDirectory() . '/UsersRoles.php',
+    );
+    $this->loadDumps($dumps);
+
+    $migration = entity_load('migration', 'd7_user_role');
+    $executable = new MigrateExecutable($migration, $this);
+    $executable->import();
+
+    $migration = entity_load('migration', 'd7_user');
+    $executable = new MigrateExecutable($migration, $this);
+    $executable->import();
+  }
+
+  protected function assertEntity($id, $label, $mail, $created, $access, $login, $blocked, $langcode, $init, array $roles = [RoleInterface::AUTHENTICATED_ID]) {
+    /** @var \Drupal\user\UserInterface $user */
+    $user = User::load($id);
+    $this->assertTrue($user instanceof UserInterface);
+    $this->assertIdentical($label, $user->label());
+    $this->assertIdentical($mail, $user->getEmail());
+    $this->assertIdentical($created, $user->getCreatedTime());
+    $this->assertIdentical($access, $user->getLastAccessedTime());
+    $this->assertIdentical($login, $user->getLastLoginTime());
+    $this->assertIdentical($blocked, $user->isBlocked());
+    // $user->getPreferredLangcode() might fallback to default language if the
+    // user preferred language is not configured on the site. We just want to
+    // test if the value was imported correctly.
+    $this->assertIdentical($langcode, $user->langcode->value);
+    $this->assertIdentical($langcode, $user->preferred_langcode->value);
+    $this->assertIdentical($langcode, $user->preferred_admin_langcode->value);
+    $this->assertIdentical($init, $user->getInitialEmail());
+    $this->assertIdentical($roles, $user->getRoles());
+  }
+
+  /**
+   * Tests the Drupal 7 user to Drupal 8 migration.
+   */
+  public function testUser() {
+    $this->assertEntity(2, 'Odo', 'odo@local.host', '1432750741', '0', '0', FALSE, '', 'odo@local.host');
+  }
+
+}
diff --git a/core/modules/migrate_drupal/tests/src/Unit/source/d6/UserTest.php b/core/modules/migrate_drupal/tests/src/Unit/source/d6/UserTest.php
index 805e1be..7adb352 100644
--- a/core/modules/migrate_drupal/tests/src/Unit/source/d6/UserTest.php
+++ b/core/modules/migrate_drupal/tests/src/Unit/source/d6/UserTest.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Contains \Drupal\Tests\migrate_drupal\Unit\source\d6\CommentTest.
+ * Contains \Drupal\Tests\migrate_drupal\Unit\source\d6\UserTest.
  */
 
 namespace Drupal\Tests\migrate_drupal\Unit\source\d6;
diff --git a/core/modules/migrate_drupal/tests/src/Unit/source/d7/RoleTest.php b/core/modules/migrate_drupal/tests/src/Unit/source/d7/RoleTest.php
new file mode 100644
index 0000000..6a3aa9c
--- /dev/null
+++ b/core/modules/migrate_drupal/tests/src/Unit/source/d7/RoleTest.php
@@ -0,0 +1,106 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\migrate_drupal\Unit\source\d7\RoleTest.
+ */
+
+namespace Drupal\Tests\migrate_drupal\Unit\source\d7 {
+
+  use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
+
+  /**
+   * Tests D7 role source plugin.
+   *
+   * @group migrate_drupal
+   */
+  class RoleTest extends MigrateSqlSourceTestCase {
+
+    // The plugin system is not working during unit testing so the source plugin
+    // class needs to be manually specified.
+    const PLUGIN_CLASS = 'Drupal\migrate_drupal\Plugin\migrate\source\d7\Role';
+
+    // The fake Migration configuration entity.
+    protected $migrationConfiguration = array(
+      // The ID of the entity, can be any string.
+      'id' => 'test',
+      // Leave it empty for now.
+      'idlist' => array(),
+      // This needs to be the identifier of the actual key: cid for comment, nid
+      // for node and so on.
+      'source' => array(
+        'plugin' => 'd7_user_role',
+      ),
+    );
+
+    protected $expectedResults = array(
+      array(
+        'rid' => 1,
+        'name' => 'anonymous user',
+        'permissions' => array(
+          'access content',
+        ),
+      ),
+      array(
+        'rid' => 2,
+        'name' => 'authenticated user',
+        'permissions' => array(
+          'access comments',
+          'access content',
+          'post comments',
+          'post comments without approval',
+        ),
+      ),
+      array(
+        'rid' => 3,
+        'name' => 'administrator',
+        'permissions' => array(
+          'access comments',
+          'administer comments',
+          'post comments',
+          'post comments without approval',
+          'access content',
+          'administer content types',
+          'administer nodes',
+        ),
+      ),
+    );
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function setUp() {
+      foreach ($this->expectedResults as $row) {
+        foreach ($row['permissions'] as $permission) {
+          $this->databaseContents['role_permission'][] = array(
+            'permission' => $permission,
+            'rid' => $row['rid'],
+          );
+        }
+        unset($row['permissions']);
+        $this->databaseContents['role'][] = $row;
+      }
+      parent::setUp();
+    }
+
+  }
+
+}
+
+namespace Drupal\Tests\migrate_drupal\Unit\source\d7 {
+
+  use Drupal\Core\Database\Connection;
+  use Drupal\Core\Extension\ModuleHandlerInterface;
+  use Drupal\migrate_drupal\Plugin\migrate\source\d7\Role;
+
+  class TestRole extends Role {
+    public function setDatabase(Connection $database) {
+      $this->database = $database;
+    }
+
+    public function setModuleHandler(ModuleHandlerInterface $module_handler) {
+      $this->moduleHandler = $module_handler;
+    }
+  }
+
+}
diff --git a/core/modules/migrate_drupal/tests/src/Unit/source/d7/UserTest.php b/core/modules/migrate_drupal/tests/src/Unit/source/d7/UserTest.php
new file mode 100644
index 0000000..6b4afdb
--- /dev/null
+++ b/core/modules/migrate_drupal/tests/src/Unit/source/d7/UserTest.php
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\migrate_drupal\Unit\source\d7\UserTest.
+ */
+
+namespace Drupal\Tests\migrate_drupal\Unit\source\d7;
+
+use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
+
+/**
+ * Tests D7 user source plugin.
+ *
+ * @group migrate_drupal
+ */
+class UserTest extends MigrateSqlSourceTestCase {
+
+  const PLUGIN_CLASS = 'Drupal\migrate_drupal\Plugin\migrate\source\d7\User';
+
+  protected $migrationConfiguration = [
+    'id' => 'test',
+    'idlist' => [],
+    'source' => [
+      'plugin' => 'd7_user',
+    ],
+  ];
+
+  protected $expectedResults = [
+    [
+      'uid' => '2',
+      'name' => 'Odo',
+      'pass' => '$S$DVpvPItXvnsmF3giVEe7Jy2lG.SCoEs8uKwpHsyPvdeNAaNZYxZ8',
+      'mail' => 'odo@local.host',
+      'signature' => '',
+      'signature_format' => 'filtered_html',
+      'created' => '1432750741',
+      'access' => '0',
+      'login' => '0',
+      'status' => '1',
+      'timezone' => 'America/Chicago',
+      'language' => '',
+      'picture' => '0',
+      'init' => 'odo@local.host',
+      'roles' => [
+        2 => 'authenticated user',
+      ],
+    ],
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    $this->databaseContents['users'][] = [
+      'uid' => '2',
+      'name' => 'Odo',
+      'pass' => '$S$DVpvPItXvnsmF3giVEe7Jy2lG.SCoEs8uKwpHsyPvdeNAaNZYxZ8',
+      'mail' => 'odo@local.host',
+      'theme' => '',
+      'signature' => '',
+      'signature_format' => 'filtered_html',
+      'created' => '1432750741',
+      'access' => '0',
+      'login' => '0',
+      'status' => '1',
+      'timezone' => 'America/Chicago',
+      'language' => '',
+      'picture' => '0',
+      'init' => 'odo@local.host',
+      'data' => 'a:1:{s:7:"contact";i:1;}',
+    ];
+    $this->databaseContents['users_roles'][] = [
+      'uid' => 2,
+      'rid' => 2,
+    ];
+    $this->databaseContents['role'][] = [
+      'rid' => 2,
+      'name' => 'authenticated user',
+      'weight' => 0,
+    ];
+    parent::setUp();
+  }
+
+}
+
+namespace Drupal\Tests\migrate_drupal\Unit\source\d7;
+
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\migrate_drupal\Plugin\migrate\source\d7\User;
+
+class TestUser extends User {
+  public function setDatabase(Connection $database) {
+    $this->database = $database;
+  }
+  public function setModuleHandler(ModuleHandlerInterface $module_handler) {
+    $this->moduleHandler = $module_handler;
+  }
+}
