diff --git node_access_example/node_access_example.info node_access_example/node_access_example.info
index cc6c04b..2fe3e64 100644
--- node_access_example/node_access_example.info
+++ node_access_example/node_access_example.info
@@ -1,8 +1,9 @@
 ; $Id$
 name = Node access example
-description = An example illustrating how to restrict access to nodes based on some criterion associated with the user.
+description = Demonstrates how a module can use Drupal's node access system
 package = Example modules
 version = VERSION
 core = 7.x
 files[] = node_access_example.module
 files[] = node_access_example.install
+files[] = node_access_example.test
diff --git node_access_example/node_access_example.module node_access_example/node_access_example.module
index 6905749..bda53d0 100755
--- node_access_example/node_access_example.module
+++ node_access_example/node_access_example.module
@@ -4,20 +4,37 @@
 /**
  * @file
  * This is an example illustrating how to restrict access to nodes based on
- * the node access system.
+ * the node access system. It implements an additional "private" marker for
+ * each node. The idea is that only the user (or specially permissioned users)
+ * can access a "private" node.
  *
- * This example module will simply set a single marker on a node: 'private'.
- * The marker is implemented by a custom table which has one row per node
- * simply indicating that the node is private. If the "private" marker is set,
- * other users are denied access.
+ * The node access system has three layers.
+ * - Overall override permissions. User 1 and any user with 'bypass node access'
+ *   permission are automatically granted access.
+ * - hook_node_access() gives each module the opportunity to approve or deny
+ *   access. Any module that returns NODE_ACCESS_DENY from hook_node_access()
+ *   will result in denial of access. If no module denies access and one or
+ *   more modules allow access, then access is granted.
+ * - If no resolution has yet been reached, then the node_access table is used
+ *   along with hook_node_grants().
+ *
+ * In order to demonstrate hook_node_access() (see
+ * node_example_module_node_access()) to deny delete access to users with an
+ * even-numbered uid.
+ *
+ * In addition, the traditional node rights system is employed to specify
+ * which users are allowed to view, edit, or delete "private" content.
+ *
+ * This puts a single marker on a node: 'private'. The marker is implemented
+ * by a custom table which has one row per node simply indicating that the node
+ * is private. If the "private" marker is set, other users are denied access.
  *
  * Additional standard permissions are defined which allow users with
  * 'access any private content' or 'edit any private content' to override
  * the node access restrictions.
  *
- * Additionally we will ensure that the node author can always view, edit,
- * and delete the node by providing an additional access realm that grants
- * privileges to the node's author.
+ * Additionally, the node author can always view, edit, and delete the node.
+ * A separate access realm grants privileges to each node's author.
  *
  * There are two basic building blocks in the node access system.
  * - hook_node_access_records() provides a list of "grants" for each node.
@@ -37,6 +54,11 @@
  * might have wanted not to grant access. So there's enormous (potential)
  * ambiguity if one tries to use more than one node access module.
  *
+ * The only page provided by this module gives a rundown of how many nodes
+ * are marked private, and how many of those are accessible to the current
+ * user. This demonstrates the use of the 'node_access' tag in node queries,
+ * preventing disclosure of information which should not be shown to a user.
+ *
  * See: @link node_access Node Access Rights @endlink and
  * @link http://drupal.org/node/270000 Handbook page on Node Access module @endlink
  */
@@ -48,25 +70,82 @@
 function node_access_example_menu() {
   $items['examples/node_access'] = array(
     'title' => 'Node Access Example',
-    'page callback' => 'node_access_example_description',
+    'page callback' => 'node_access_example_private_node_listing',
     'access callback' => TRUE,
   );
   return $items;
 }
 
 /**
- * Simple description page for user who is trying to interace with the module.
+ * Information for the user about what nodes are marked private on the system
+ * and which of those the user has access to.
+ *
+ * The queries showing what is accessible to the current user demonstrate the
+ * use of the 'node_access' tag to make sure that we don't show inappropriate
+ * information to unprivileged users.
  */
-function node_access_example_description() {
-  return t('This example shows how a module can use the Drupal node access system to allow access to specific nodes. You will need to look at the code and then experiment with it by creating nodes, marking them private, and accessing them as various users.');
+function node_access_example_private_node_listing() {
+  $content = '<div>' . t('This example shows how a module can use the Drupal node access system to allow access to specific nodes. You will need to look at the code and then experiment with it by creating nodes, marking them private, and accessing them as various users.') . '</div>';
+
+  // Find out how many nodes are marked private.
+  $query = db_select('node', 'n');
+  $query->addExpression('COUNT(n.nid)', 'private_count');
+  $query->join('node_access_example', 'nae', 'nae.nid = n.nid');
+  $num_private = $query
+  ->condition('nae.private', 1)->execute()->fetchField();
+
+  // Find out how many nodes owned by this user are marked private.
+  $query = db_select('node', 'n');
+  $query->addExpression('COUNT(n.nid)', 'private_count');
+  $query->join('node_access_example', 'nae', 'nae.nid = n.nid');
+  $num_personal = $query
+  ->condition('n.uid', $GLOBALS['user']->uid)
+  ->condition('nae.private', 1)
+  ->execute()->fetchfield();
+
+  $content .= '<div>' . t('There are currently @num private nodes in the system @num_personal are yours.', array('@num' => $num_private, '@num_personal' => $num_personal)) . '</div>';
+
+  // Use a 'node_access' tag with a query to find out how many this user has
+  // access to. This will be the standard way to make lists while respecting
+  // node access restrictions.
+  $query = db_select('node', 'n');
+  $query->addExpression('COUNT(n.nid)', 'private_count');
+  $query->addTag('node_access');
+  $query->join('node_access_example', 'nae', 'nae.nid = n.nid');
+  $num_private_accessible = $query->condition('nae.private', 1)->execute()->fetchField();
+  $content .= '<div>' . t('You have access to @num private nodes.', array('@num' => $num_private_accessible)) . '</div>';
+
+  // Use the key 'node_access' tag to get the key data from the nodes this
+  // has access to.
+  $query = db_select('node', 'n', array('fetch' => PDO::FETCH_ASSOC));
+  $query->addTag('node_access');
+  $query->join('node_access_example', 'nae', 'nae.nid = n.nid');
+  $query->join('users', 'u', 'u.uid = n.uid');
+  $result = $query->fields('n', array('nid', 'title', 'uid'))
+  ->fields('u', array('name'))
+  ->condition('nae.private', 1)->execute();
+
+  $rows = array();
+  foreach ($result as $node) {
+    $node['nid'] = l($node['nid'], 'node/' . $node['nid']);
+    $rows[] = array('data' => $node,  'class' => array('accessible'));
+  }
+  $content .= '<div>' . t('Accessible rows:') . theme('table', array('header' => array('nid', 'title', 'uid', 'username'), 'rows' => $rows)) . '</div>';
+
+  return $content;
 }
 
+
 /**
  * Implements hook_permission().
  *
  * Users with 'access any private content' have global access to content marked
  * private by other users. 'edit any private content' allows global edit
  * privileges, basically overriding the node access system.
+ *
+ * Note that the 'edit any * content' and 'delete any * content' permissions
+ * will allow edit or delete permissions to the holder, regardless of what
+ * this module does.
  */
 function node_access_example_permission() {
   return array(
@@ -82,6 +161,25 @@ function node_access_example_permission() {
 }
 
 /**
+ * Implements hook_node_access().
+ *
+ *  Allows view and edit access to private nodes where theacccount requesting
+ *  access has the username 'foobar'.
+ */
+function node_access_example_node_access($node, $op, $account) {
+  // If $node is a string, the node has not yet been created. We don't care
+  // about that case.
+  if (is_string($node)) {
+    return NODE_ACCESS_IGNORE;
+  }
+  if (($op == 'view' || $op == 'update') && $account->name == 'foobar' && !empty($node->private)) {
+    drupal_set_message(t('Access to node @nid allowed because requester name (@name) is specifically allowed', array('@name' => $node->name, '@uid' => $account->uid)));
+    return NODE_ACCESS_ALLOW;
+  }
+  return NODE_ACCESS_IGNORE;
+}
+
+/**
  * Implements hook_node_grants().
  *
  * Tell the node access system what grant IDs the account belongs to for each
@@ -102,11 +200,11 @@ function node_access_example_node_grants($account, $op) {
   // Then, if "access any private content" is allowed to the account,
   // grant view, update, or delete as necessary.
   if ($op == 'view' && user_access('access any private content', $account)) {
-    $grants['node_access_example'] = array(1);
+    $grants['node_access_example_view'] = array(1);
   }
 
   if (($op == 'update' || $op == 'delete') && user_access('edit any private content', $account)) {
-    $grants['node_access_example'] = array(1);
+    $grants['node_access_example_edit'] = array(1);
   }
 
   return $grants;
@@ -127,13 +225,21 @@ function node_access_example_node_access_records($node) {
   if (!empty($node->private)) {
     $grants = array();
     $grants[] = array(
-      'realm' => 'node_access_example',
+      'realm' => 'node_access_example_view',
       'gid' => 1,
       'grant_view' => 1,
       'grant_update' => 0,
       'grant_delete' => 0,
       'priority' => 0,
     );
+    $grants[] = array(
+      'realm' => 'node_access_example_edit',
+      'gid' => 1,
+      'grant_view' => 1,
+      'grant_update' => 1,
+      'grant_delete' => 1,
+      'priority' => 0,
+    );
 
     // For the example_author realm, the GID is equivalent to a UID, which
     // means there are many many groups of just 1 user.
@@ -205,6 +311,7 @@ function node_access_example_node_insert($node) {
   if (isset($node->private)) {
     db_insert('node_access_example')->fields(array('nid' => $node->nid, 'private' => (int)$node->private))->execute();
   }
+  drupal_set_message(t('New node @nid was created and private=@private', array('@nid' => $node->nid, '@private' => !empty($node->private) ? 1 : 0)));
 }
 
 /**
diff --git node_access_example/node_access_example.test node_access_example/node_access_example.test
new file mode 100644
index 0000000..ab01b57
--- /dev/null
+++ node_access_example/node_access_example.test
@@ -0,0 +1,197 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Tests for Node Access example module.
+ */
+class NodeAccessExampleTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Node Access Example functionality',
+      'description' => 'Checks behavior of Node Access Example.',
+      'group' => 'Examples',
+    );
+  }
+
+  /**
+   * Enable modules and create user with specific permissions.
+   */
+  public function setUp() {
+    parent::setUp('node_access_example', 'search');
+    node_access_rebuild();
+  }
+
+  /**
+   * Test the "private" node access.
+   *
+   * - Create 3 users with "access content" and "create article" permissions.
+   * - Each user creates one private and one not private article.
+   * - Run cron to update search index.
+   * - Test that each user can view the other user's non-private article.
+   * - Test that each user cannot view the other user's private article.
+   * - Test that each user finds only appropriate (non-private + own private)
+   *   in search results.
+   * - Create another user with 'view any private content'.
+   * - Test that user 4 can view all content created above.
+   * - Test that user 4 can search for all content created above.
+   * - Test that user 4 cannot edit private content above.
+   * - Create another user with 'edit any private content'
+   * - Test that user 5 can edit private content.
+   * - Test that user 5 can delete private content.
+   * - Test listings of nodes with 'node_access' tag on database search.
+   */
+  function testNodeAccessBasic() {
+    $num_simple_users = 3;
+    $simple_users = array();
+
+    // nodes keyed by uid and nid: $nodes[$uid][$nid] = $is_private;
+    $nodes_by_user = array();
+    $titles = array(); // Titles keyed by nid
+    $private_nodes = array(); // Array of nids marked private.
+    for($i = 0; $i < $num_simple_users; $i++) {
+      $simple_users[$i] = $this->drupalCreateUser(array('access content', 'create article content', 'search content'));
+    }
+    foreach ($simple_users as $web_user) {
+      $this->drupalLogin($web_user);
+      foreach(array(0 => 'Public', 1 => 'Private') as $is_private => $type) {
+        $edit = array(
+          'title' => t('@private_public Article created by @user', array('@private_public' => $type, '@user' => $web_user->name)),
+        );
+        if ($is_private) {
+          $edit['private'] = TRUE;
+          $edit['body[und][0][value]'] = 'private node';
+        }
+        else {
+          $edit['body[und][0][value]'] = 'public node';
+        }
+        $this->drupalPost('node/add/article', $edit, t('Save'));
+        debug(t('Created article with private=@private', array('@private' => $is_private)));
+        $this->assertText(t('Article @title has been created', array('@title' => $edit['title'])));
+        $nid = db_query('SELECT nid FROM {node} WHERE title = :title', array(':title' => $edit['title']))->fetchField();
+        $this->assertText(t('New node @nid was created and private=@private', array('@nid' => $nid, '@private' => $is_private)));
+        $private_status = db_query('SELECT private FROM {node_access_example} where nid = :nid', array(':nid' => $nid))->fetchField();
+        $this->assertTrue($is_private == $private_status, t('Node was properly set to private or not private in node_access_example table.'));
+        if ($is_private) {
+          $private_nodes[] = $nid;
+        }
+        $titles[$nid] = $edit['title'];
+        $nodes_by_user[$web_user->uid][$nid] = $is_private;
+      }
+    }
+    debug($nodes_by_user);
+    $this->cronRun();  // Build the search index.
+    foreach ($simple_users as $web_user) {
+      $this->drupalLogin($web_user);
+      // Check to see that we find the number of search results expected.
+      $this->checkSearchResults('Private node', 1);
+      // Check own nodes to see that all are readable.
+      foreach(array_keys($nodes_by_user) as $uid) {
+        // All of this user's nodes should be readable to same.
+        if ($uid == $web_user->uid) {
+          foreach($nodes_by_user[$uid] as $nid => $is_private) {
+            $this->drupalGet('node/'.$nid);
+            $this->assertResponse(200);
+            $this->assertTitle($titles[$nid] . ' | Drupal', t('Correct title for node found'));
+          }
+        }
+        else {
+          // Otherwise, for other users, private nodes should get a 403,
+          // but we should be able to read non-private nodes.
+          foreach($nodes_by_user[$uid] as $nid => $is_private) {
+            $this->drupalGet('node/'.$nid);
+            $this->assertResponse($is_private ? 403 : 200, t('Node @nid by user @uid should get a @response for this user (@web_user_uid)', array('@nid' => $nid, '@uid' => $uid, '@response' => $is_private ? 403 : 200, '@web_user_uid' => $web_user->uid)));
+            if (!$is_private) {
+              $this->assertTitle($titles[$nid] . ' | Drupal', t('Correct title for node was found'));
+            }
+          }
+        }
+      }
+
+      // Check to see that the correct nodes are shown on examples/node_access.
+      $this->drupalGet('examples/node_access');
+      $accessible = $this->xpath("//tr[contains(@class,'accessible')]");
+      $this->assertEqual(count($accessible), 1, t('One private item accessible'));
+      foreach ($accessible as $row) {
+        $this->assertEqual($row->td[2], $web_user->uid, t('Accessible row owned by this user'));
+      }
+    }
+
+    // Now test that a user with 'access any private content' can view content.
+    $access_user = $this->drupalCreateUser(array('access content', 'create article content', 'access any private content', 'search content'));
+    $this->drupalLogin($access_user);
+
+    // Check to see that we find the number of search results expected.
+    $this->checkSearchResults('Private node', 3);
+
+    foreach($nodes_by_user as $uid => $private_status) {
+      foreach ($private_status as $nid => $is_private) {
+        $this->drupalGet('node/' . $nid);
+        $this->assertResponse(200);
+      }
+    }
+
+    // Check to see that the correct nodes are shown on examples/node_access.
+    // This user should be able to see all 3 of them.
+    $this->drupalGet('examples/node_access');
+    $accessible = $this->xpath("//tr[contains(@class,'accessible')]");
+    $this->assertEqual(count($accessible), 3);
+
+
+    // Test that a user named 'foobar' can edit any private node due to
+    // node_access_example_node_access(). Note that this user will not be
+    // able to search for private nodes, and will not have available nodes
+    // shown on examples/node_access, because node_access() is not called
+    // for node listings, only for actual access to a node.
+    $edit_user = $this->drupalCreateUser(array('access comments', 'access content', 'post comments', 'post comments without approval', 'search content'));
+    // Update the name of the user to 'foobar'.
+    $num_updated = db_update('users')
+      ->fields(array(
+          'name' => 'foobar',
+      ))
+      ->condition('uid', $edit_user->uid)
+      ->execute();
+
+    $edit_user->name = 'foobar';
+    $this->drupalLogin($edit_user);
+
+    // Try to edit each of the private nodes.
+    foreach($private_nodes as $nid) {
+      $body = $this->randomName();
+      $edit = array('body[und][0][value]' => $body);
+      $this->drupalPost('node/' . $nid . '/edit', $edit, t('Save'));
+      $this->assertText(t('has been updated'), t('Node was updated by "foobar" user'));
+    }
+
+    // Test that a privileged user can edit and delete private content.
+    // This test should go last, as the nodes get deleted.
+    $edit_user = $this->drupalCreateUser(array('access content', 'access any private content', 'edit any private content'));
+    $this->drupalLogin($edit_user);
+    foreach($private_nodes as $nid) {
+      $body = $this->randomName();
+      $edit = array('body[und][0][value]' => $body);
+      $this->drupalPost('node/' . $nid . '/edit', $edit, t('Save'));
+      $this->assertText(t('has been updated'));
+      $this->drupalPost('node/' . $nid . '/edit', array(), t('Delete'));
+      $this->drupalPost(NULL, array(), t('Delete'));
+      $this->assertText(t('has been deleted'));
+    }
+
+
+  }
+
+  /**
+   * On the search page, search for a string and assert the expected number
+   * of results.
+   * @param $search_query
+   *   String to search for
+   * @param $expected_result_count
+   *   Expected result count
+   */
+  function checkSearchResults($search_query, $expected_result_count) {
+    $this->drupalPost('search/node', array('keys' => $search_query), t('Search'));
+    $search_results = $this->xpath("//ol[contains(@class, 'search-results')]/li");
+    $this->assertEqual(count($search_results), $expected_result_count, t('Found the expected number of search results'));
+  }
+}
