diff --git a/lib/Drupal/views/Tests/Plugin/RowTest.php b/lib/Drupal/views/Tests/Plugin/RowTest.php
new file mode 100644
index 0000000..46e3319
--- /dev/null
+++ b/lib/Drupal/views/Tests/Plugin/RowTest.php
@@ -0,0 +1,118 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\views\Tests\Plugin\RowTest.
+ */
+
+namespace Drupal\views\Tests\Plugin;
+
+/**
+ * Tests general row plugin functionality.
+ *
+ * @see Drupal\views\Plugin\views\row\RowPluginBase
+ */
+class RowTest extends PluginTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('views_ui');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Row: General',
+      'description' => 'Tests general row plugin functionality.',
+      'group' => 'Views Plugins',
+    );
+  }
+
+  protected function setUp() {
+    parent::setUp();
+
+    $this->enableViewsTestModule();
+  }
+
+  /**
+   * Test some basic UI of row plugins.
+   */
+  public function testRowPluginUI() {
+    $views_admin = $this->drupalCreateUser(array('administer views'));
+    $this->drupalLogin($views_admin);
+
+    // Make sure the link to the row options exists.
+    $row_options_path = 'admin/structure/views/nojs/display/test_row_plugin/default/row_options';
+    $view_edit_path = 'admin/structure/views/view/test_row_plugin/edit';
+    $this->drupalGet($view_edit_path);
+    $this->assertLinkByHref($row_options_path);
+
+    // The test view has a relationship to node_revision so the row option
+    // should show a relationship selection.
+
+    $this->drupalGet($row_options_path);
+    $relationship_name = 'row_options[relationship]';
+    $this->assertFieldByName($relationship_name);
+
+    // Check for available options.
+    $xpath = $this->constructFieldXpath('name', $relationship_name);
+    $fields = $this->xpath($xpath);
+    $options = array();
+    foreach ($fields as $field) {
+      $items = $this->getAllOptions($field);
+      foreach ($items as $item) {
+        $options[] = $item->attributes()->value;
+      }
+    }
+    $expected_options = array('none', 'vid');
+    $this->assertEqual($options, $expected_options);
+
+    // Remove the relationship and take sure no relationship option appears.
+    $this->drupalPost('admin/structure/views/nojs/config-item/test_row_plugin/default/relationship/vid', array(), t('Remove'));
+    $this->drupalGet($row_options_path);
+    $this->assertNoFieldByName($relationship_name, 'Make sure that no relationship option is available');
+
+    // Disable options for the row plugin and make sure no link exists.
+    $this->drupalPost($row_options_path, array('row_options[test_option]' => FALSE), t('Apply'));
+    $this->drupalGet($view_edit_path);
+    $this->assertNoLinkByHref($row_options_path);
+  }
+
+  /**
+   * Test query of the row plugin.
+   */
+  public function testRowQuery() {
+    $view = views_get_view('test_row_plugin');
+    $view->initDisplay();
+    $view->initStyle();
+    $this->executeView($view);
+
+    // Make sure the base field is added to the query.
+    $row_plugin = $view->style_plugin->row_plugin;
+
+    $this->assertTrue(isset($view->query->fields[$row_plugin->field_alias]));
+    $this->assertEqual($view->query->fields[$row_plugin->field_alias], array(
+      'field' => 'nid',
+      'table' => 'node',
+      'alias' => $row_plugin->field_alias
+    ));
+    $view->destroy();
+
+    // Choose a relationship and check whether the base field from the
+    // relationship is taken into account.
+    $view->initDisplay();
+    $view->initStyle();
+    $row_plugin = $view->style_plugin->row_plugin;
+    $view->style_plugin->row_plugin->options['relationship'] = 'vid';
+
+    $this->executeView($view);
+    $this->assertEqual($view->query->fields[$row_plugin->field_alias], array(
+      'field' => 'nid',
+      // Table is the key to the relationship table alias.
+      'table' => 'node_node_revision',
+      'alias' => $row_plugin->field_alias
+    ));
+  }
+
+}
diff --git a/tests/views_test_config/config/views.view.test_row_plugin.yml b/tests/views_test_config/config/views.view.test_row_plugin.yml
new file mode 100644
index 0000000..36aaa27
--- /dev/null
+++ b/tests/views_test_config/config/views.view.test_row_plugin.yml
@@ -0,0 +1,25 @@
+api_version: '3.0'
+base_table: node
+core: '8'
+description: ''
+disabled: '0'
+display:
+  default:
+    display_options:
+      access:
+        type: none
+      cache:
+        type: none
+      row_plugin: test_row
+      relationships:
+        vid:
+          id: vid
+          field: vid
+          table: node_revision
+    display_plugin: default
+    display_title: Master
+    id: default
+    position: '0'
+human_name: {  }
+name: test_row_plugin
+tag: ''
diff --git a/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/row/RowTest.php b/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/row/RowTest.php
new file mode 100644
index 0000000..c61a0b3
--- /dev/null
+++ b/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/row/RowTest.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\views_test_data\Plugin\views\row\RowTest.
+ */
+
+namespace Drupal\views_test_data\Plugin\views\row;
+
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+use Drupal\views\Plugin\views\row\RowPluginBase;
+
+/**
+ * @Plugin(
+ *   id = "test_row",
+ *   title = @Translation("Test row plugin"),
+ *   help = @Translation("Provides a generic row test plugin."),
+ *   base = {"node"},
+ *   type = "normal"
+ * )
+ */
+class RowTest extends RowPluginBase {
+
+  /**
+   * The table this row plugin is acting on.
+   *
+   * @var string
+   */
+  public $base_table = 'node';
+
+  /**
+   * The field of the base_table the row plugin is acting on.
+   *
+   * @var string
+   */
+  public $base_field = 'nid';
+
+  /**
+   * Overrides Drupal\views\Plugin\views\row\RowPluginBase::defineOptions().
+   *
+   * @return array
+   */
+  protected function defineOptions() {
+    $options = parent::defineOptions();
+
+    $options['test_option'] = array('default' => TRUE);
+    return $options;
+  }
+
+  /**
+   * Overrides Drupal\views\Plugin\views\row\RowPluginBase::buildOptionsForm().
+   *
+   * @return array
+   */
+  public function buildOptionsForm(&$form, &$form_state) {
+    parent::buildOptionsForm($form, $form_state);
+
+    $form['test_option'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Controls whether the row plugin has options.'),
+      '#default_value' => $this->options['test_option'],
+    );
+  }
+
+  /**
+   * Overrides Drupal\views\Plugin\views\row\RowPluginBase::usesOptions().
+   *
+   * The test checkbox controls whether this plugin has options.
+   */
+  public function usesOptions() {
+    return $this->options['test_option'];
+  }
+
+}
