diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index a9ea984..9b9d915 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -175,6 +175,15 @@
  * @see http://php.net/manual/reserved.variables.server.php
  * @see http://php.net/manual/function.time.php
  */
+
+// @todo: HACK: Use server request time for tests.
+if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/^(simpletest\d+);(.+);(.+);(.+)$/", $_SERVER['HTTP_USER_AGENT'], $matches)) {
+  list(, $prefix, $time, $salt, $hmac) = $matches;
+  if ($time < 1393632000) {
+    $_SERVER['REQUEST_TIME'] = (int) $time;
+    $_SERVER['REQUEST_TIME_FLOAT'] = (float) $time;
+  }
+}
 define('REQUEST_TIME', (int) $_SERVER['REQUEST_TIME']);
 
 /**
@@ -1721,9 +1730,13 @@ function drupal_valid_test_ua($new_prefix = NULL) {
 /**
  * Generates a user agent string with a HMAC and timestamp for simpletest.
  */
-function drupal_generate_test_ua($prefix) {
+function drupal_generate_test_ua($prefix, $time = NULL) {
   static $key, $last_prefix;
 
+  if (!isset($time)) {
+    $time = time();
+  }
+
   if (!isset($key) || $last_prefix != $prefix) {
     $last_prefix = $prefix;
     $key_file = DRUPAL_ROOT . '/sites/simpletest/' . substr($prefix, 10) . '/.htkey';
@@ -1750,7 +1763,7 @@ function drupal_generate_test_ua($prefix) {
   }
   // Generate a moderately secure HMAC based on the database credentials.
   $salt = uniqid('', TRUE);
-  $check_string = $prefix . ';' . time() . ';' . $salt;
+  $check_string = $prefix . ';' . $time . ';' . $salt;
   return $check_string . ';' . Crypt::hmacBase64($check_string, $key);
 }
 
diff --git a/core/lib/Drupal/Component/Utility/DeterministicRandom.php b/core/lib/Drupal/Component/Utility/DeterministicRandom.php
new file mode 100644
index 0000000..8f0b0ef
--- /dev/null
+++ b/core/lib/Drupal/Component/Utility/DeterministicRandom.php
@@ -0,0 +1,161 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\Utility\Random.
+ */
+
+namespace Drupal\Component\Utility;
+
+/**
+ * Defines a utility class for creating random data.
+ *
+ * @ingroup utility
+ */
+class DeterministicRandom {
+
+  /**
+   * The maximum number of times name() and string() can loop.
+   *
+   * This prevents infinite loops if the length of the random value is very
+   * small.
+   *
+   * @see \Drupal\Tests\Component\Utility\RandomTest
+   */
+  const MAXIMUM_TRIES = 100;
+
+  /**
+   * A list of unique strings generated by string().
+   *
+   * @var array
+   */
+  protected $strings = array();
+
+  /**
+   * A list of unique names generated by name().
+   *
+   * @var array
+   */
+  protected $names = array();
+
+  /**
+   * Generates a random string of ASCII characters of codes 32 to 126.
+   *
+   * The generated string includes alpha-numeric characters and common
+   * miscellaneous characters. Use this method when testing general input
+   * where the content is not restricted.
+   *
+   * @param int $length
+   *   Length of random string to generate.
+   * @param bool $unique
+   *   (optional) If TRUE ensures that the random string returned is unique.
+   *   Defaults to FALSE.
+   * @param callable $validator
+   *   (optional) A callable to validate the the string. Defaults to NULL.
+   *
+   * @return string
+   *   Randomly generated string.
+   *
+   * @see \Drupal\Component\Utility\DeterministicRandom::name()
+   */
+  public function string($length = 8, $unique = FALSE, $validator = NULL) {
+    $counter = 0;
+
+    // Continue to loop if $unique is TRUE and the generated string is not
+    // unique or if $validator is a callable that returns FALSE. To generate a
+    // random string this loop must be carried out at least once.
+    do {
+      if ($counter == static::MAXIMUM_TRIES) {
+        throw new \RuntimeException('Unable to generate a unique random name');
+      }
+      $str = '';
+      for ($i = 0; $i < $length; $i++) {
+        $str .= chr(rand(32, 126));
+      }
+      $counter++;
+
+      $continue = FALSE;
+      if ($unique) {
+        $continue = isset($this->strings[$str]);
+      }
+      if (!$continue && is_callable($validator)) {
+        // If the validator callback returns FALSE generate another random
+        // string.
+        $continue = !call_user_func($validator, $str);
+      }
+    } while ($continue);
+
+    if ($unique) {
+      $this->strings[$str] = TRUE;
+    }
+
+    return $str;
+  }
+
+  /**
+   * Generates a random string containing letters and numbers.
+   *
+   * The string will always start with a letter. The letters may be upper or
+   * lower case. This method is better for restricted inputs that do not
+   * accept certain characters. For example, when testing input fields that
+   * require machine readable values (i.e. without spaces and non-standard
+   * characters) this method is best.
+   *
+   * @param int $length
+   *   Length of random string to generate.
+   * @param bool $unique
+   *   (optional) If TRUE ensures that the random string returned is unique.
+   *   Defaults to FALSE.
+   *
+   * @return string
+   *   Randomly generated string.
+   *
+   * @see \Drupal\Component\Utility\DeterministicRandom::string()
+   */
+  public function name($length = 8, $unique = FALSE) {
+    $values = array_merge(range(65, 90), range(97, 122), range(48, 57));
+    $max = count($values) - 1;
+    $counter = 0;
+
+    do {
+      if ($counter == static::MAXIMUM_TRIES) {
+        throw new \RuntimeException('Unable to generate a unique random name');
+      }
+      $str = chr(rand(97, 122));
+      for ($i = 1; $i < $length; $i++) {
+        $str .= chr($values[rand(0, $max)]);
+      }
+      $counter++;
+    } while ($unique && isset($this->names[$str]));
+
+    if ($unique) {
+      $this->names[$str] = TRUE;
+    }
+
+    return $str;
+  }
+
+  /**
+   * Generates a random PHP object.
+   *
+   * @param int $size
+   *   The number of random keys to add to the object.
+   *
+   * @return \stdClass
+   *   The generated object, with the specified number of random keys. Each key
+   *   has a random string value.
+   */
+  public function object($size = 4) {
+    $object = new \stdClass();
+    for ($i = 0; $i < $size; $i++) {
+      $random_key = $this->name();
+      $random_value = $this->string();
+      $object->{$random_key} = $random_value;
+    }
+    return $object;
+  }
+
+  public function setSeed($int) {
+    srand($int);
+  }
+}
diff --git a/core/modules/rest/src/Tests/RESTTestBase.php b/core/modules/rest/src/Tests/RESTTestBase.php
index 1e19be2..52c0f6f 100644
--- a/core/modules/rest/src/Tests/RESTTestBase.php
+++ b/core/modules/rest/src/Tests/RESTTestBase.php
@@ -279,7 +279,7 @@ protected function assertHeader($header, $value, $message = '', $group = 'Browse
    * CURLOPT_CUSTOMREQUEST cannot be unset on the cURL handle, so we need to
    * override it every time it is omitted.
    */
-  protected function curlExec($curl_options, $redirect = FALSE) {
+  protected function curlExec($curl_options, $redirect = FALSE, $old_data = NULL) {
     if (!isset($curl_options[CURLOPT_CUSTOMREQUEST])) {
       if (!empty($curl_options[CURLOPT_HTTPGET])) {
         $curl_options[CURLOPT_CUSTOMREQUEST] = 'GET';
@@ -288,7 +288,7 @@ protected function curlExec($curl_options, $redirect = FALSE) {
         $curl_options[CURLOPT_CUSTOMREQUEST] = 'POST';
       }
     }
-    return parent::curlExec($curl_options, $redirect);
+    return parent::curlExec($curl_options, $redirect, $old_data);
   }
 
   /**
diff --git a/core/modules/simpletest/src/TestBase.php b/core/modules/simpletest/src/TestBase.php
index 0987d3d..5d3fa3b 100644
--- a/core/modules/simpletest/src/TestBase.php
+++ b/core/modules/simpletest/src/TestBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\simpletest;
 
 use Drupal\Component\Utility\Random;
+use Drupal\Component\Utility\DeterministicRandom;
 use Drupal\Core\Database\Database;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Config\ConfigImporter;
@@ -197,6 +198,16 @@
   protected $randomGenerator;
 
   /**
+   * The tests context.
+   */
+  protected $testContext;
+
+  /**
+   * The tests serverTime.
+   */
+  protected $serverTime = NULL;
+
+  /**
    * Constructor for Test.
    *
    * @param $test_id
@@ -739,6 +750,112 @@ protected function error($message = '', $group = 'Other', array $caller = NULL)
     return $this->assert('exception', $message, $group, $caller);
   }
 
+  protected function getServerTime() {
+    return $this->serverTime;
+  }
+
+  protected function incrementServerTime($inc) {
+    if (isset($this->serverTime)) {
+//      $this->setServerTime($this->serverTime + $inc);
+    }
+  }
+
+  protected function setServerTime($ts = NULL) {
+    $this->serverTime = $ts;
+  }
+
+  protected function enterTestContext($context) {
+    $this->testContext = $context;
+
+    // Set a deterministic random generator.
+    if (!($this->randomGenerator instanceof DeterministicRandom)) {
+      $this->randomGenerator = new DeterministicRandom();
+    }
+
+    // Seed it, so its random, but deterministic.
+    $this->randomGenerator->setSeed(crc32($context['class'] . '-' . $context['method']));
+  }
+
+  protected function leaveTestContext() {
+    $this->testContext = array();
+  }
+
+  protected function getTestContext() {
+    return $this->testContext;
+  }
+
+  protected function getLineNo() {
+    $line_no = '0000';
+
+    $context = $this->getTestContext();
+    if (empty($context)) {
+      return $line_no;
+    }
+
+    // Find line number via debug_backtrace().
+
+    $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
+    foreach ($backtrace as $key => $trace) {
+      if ($trace['function'] == $context['method'] &&
+          $trace['class'] == $context['class']) {
+        $line_no = $backtrace[$key-1]['line'];
+        break;
+      }
+    }
+    return $line_no;
+  }
+
+  protected function recordRequest($url, $output, $meta_data) {
+    $context = $this->getTestContext();
+    if (empty($context)) {
+      return;
+    }
+
+    // Increment serverTime by 1s.
+    $this->incrementServerTime(1);
+
+    $line_no = $this->getLineNo();
+
+    // Only use $path from URLs, so we get a nice hierarchical overview.
+    // @todo: Convert to route?
+    $uri = parse_url($url);
+
+    // Strip namespace
+    $class = explode('\\', $context['class']);
+
+    $filename = 'vtd/' . $uri['path'] . '/' . end($class) . '-' . $context['method'] . '-' . $line_no;
+
+    // Create directory if it does not exist, yet.
+    if (!file_exists(dirname($filename))) {
+      //mkdir(dirname($filename), 0775, TRUE);
+    }
+
+    // Prepare nice overall meta_data.
+    $meta_data = array(
+      'test' => $context,
+      'request' => $meta_data,
+    );
+
+    // Normalize HTML output a little.
+
+    // Remove form_build_id's and form_token.
+    $output = preg_replace('/name="form_build_id" value="[\w\-]*"/', 'name="form_build_id" value="[FORM-BUILD-ID-REPLACED]"', $output);
+    $output = preg_replace('/name="form_token" value="[\w\-]*"/', 'name="form_token" value="[FORM-TOKEN-REPLACED]"', $output);
+
+    // Remove href and src.
+    $output = preg_replace('/href="([^\?]*)\?[\w]*"/', 'href="\1"', $output);
+    $output = preg_replace('/src="([^\?]*)\?[\w\=\.]*"/', 'src="\1"', $output);
+
+    // And the theme_token and hashes.
+    $output = preg_replace('/,"theme_token":"[\w\-]*",/', ',"theme_token":"[THEME-TOKEN-REPLACED]",', $output);
+    $output = preg_replace('/,"permissionsHash":"[\w\-]*"},/', ',"permissionsHash":"[PERMISSION-HASH-REPLACED]"},', $output);
+
+    //file_put_contents($filename . '.html', $output);
+    //file_put_contents($filename . '.meta', print_r($meta_data, TRUE));
+    //file_put_contents($filename . '.url', $url);
+  }
+
+
   /**
    * Logs verbose message in a text file.
    *
@@ -781,6 +898,12 @@ protected function verbose($message) {
    *   methods during debugging.
    */
   public function run(array $methods = array()) {
+    $class_blacklist = array(
+    );
+    $method_blacklist = array(
+      'Drupal\system\Tests\System\CronRunTest->testAutomaticCron()',
+    );
+
     $class = get_class($this);
 
     if ($missing_requirements = $this->checkRequirements()) {
@@ -834,6 +957,9 @@ public function run(array $methods = array()) {
     if ($methods) {
       $test_methods = array_intersect($test_methods, $methods);
     }
+    $context = array(
+      'class' => $class,
+    );
     foreach ($test_methods as $method) {
       // Insert a fail record. This will be deleted on completion to ensure
       // that testing completed.
@@ -845,6 +971,16 @@ public function run(array $methods = array()) {
       );
       $test_completion_check_id = TestBase::insertAssert($this->testId, $class, FALSE, 'The test did not complete due to a fatal error.', 'Completion check', $caller);
 
+      // Reset server time to original time.
+/*
+      if (in_array($class, $class_blacklist) || in_array($caller['function'], $method_blacklist)) {
+        $this->setServerTime(NULL);
+      }
+      else {
+        $this->setServerTime(REQUEST_TIME);
+      }
+*/
+
       try {
         $this->prepareEnvironment();
       }
@@ -871,12 +1007,17 @@ public function run(array $methods = array()) {
         $this->restoreEnvironment();
         break;
       }
+
+      $this->enterTestContext($context + $caller + array('method' => $method));
       try {
         $this->$method();
       }
       catch (\Exception $e) {
+        $this->leaveTestContext();
         $this->exceptionHandler($e);
       }
+      $this->leaveTestContext();
+
       try {
         $this->tearDown();
       }
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index 6aa9767..2070b7e 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -1248,7 +1248,7 @@ protected function curlInitialize() {
     // We set the user agent header on each request so as to use the current
     // time and a new uniqid.
     if (preg_match('/simpletest\d+/', $this->databasePrefix, $matches)) {
-      curl_setopt($this->curlHandle, CURLOPT_USERAGENT, drupal_generate_test_ua($matches[0]));
+      curl_setopt($this->curlHandle, CURLOPT_USERAGENT, drupal_generate_test_ua($matches[0], $this->getServerTime()));
     }
   }
 
@@ -1268,7 +1268,7 @@ protected function curlInitialize() {
    *
    * @see curlInitialize()
    */
-  protected function curlExec($curl_options, $redirect = FALSE) {
+  protected function curlExec($curl_options, $redirect = FALSE, $old_data = NULL) {
     $this->curlInitialize();
 
     if (!empty($curl_options[CURLOPT_URL])) {
@@ -1348,6 +1348,14 @@ protected function curlExec($curl_options, $redirect = FALSE) {
     $content = curl_exec($this->curlHandle);
     $status = curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE);
 
+    $recorded = array(
+      'method' => !empty($curl_options[CURLOPT_NOBODY]) ? 'HEAD' : (empty($curl_options[CURLOPT_POSTFIELDS]) ? 'GET' : 'POST'),
+      'status' => $status,
+      'length' => strlen($content),
+      'curlOptions' => $this->additionalCurlOptions + $curl_options,
+      'oldData' => $old_data,
+    );
+
     // cURL incorrectly handles URLs with fragments, so instead of
     // letting cURL handle redirects we take of them ourselves to
     // to prevent fragments being sent to the web server as part
@@ -1359,7 +1367,7 @@ protected function curlExec($curl_options, $redirect = FALSE) {
         $curl_options = array();
         $curl_options[CURLOPT_URL] = $this->drupalGetHeader('location');
         $curl_options[CURLOPT_HTTPGET] = TRUE;
-        return $this->curlExec($curl_options, TRUE);
+        return $this->curlExec($curl_options, TRUE, $recorded);
       }
     }
 
@@ -1370,6 +1378,8 @@ protected function curlExec($curl_options, $redirect = FALSE) {
       '@status' => $status,
       '!length' => format_size(strlen($this->drupalGetContent()))
     );
+    $this->recordRequest($message_vars['@url'], $this->drupalGetContent(), $recorded);
+
     $message = String::format('!method @url returned @status (!length).', $message_vars);
     $this->assertTrue($this->drupalGetContent() !== FALSE, $message, 'Browser');
     return $this->drupalGetContent();
diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh
index 8eff2a2..5edc0a7 100755
--- a/core/scripts/run-tests.sh
+++ b/core/scripts/run-tests.sh
@@ -344,6 +344,9 @@ function simpletest_script_init() {
   $_SERVER['SCRIPT_FILENAME'] = $path .'/index.php';
   $_SERVER['PHP_SELF'] = $path .'/index.php';
   $_SERVER['HTTP_USER_AGENT'] = 'Drupal command line';
+//  $_SERVER['REQUEST_TIME'] = (int) 1388534400;
+//  $_SERVER['REQUEST_TIME_FLOAT'] = (int) 1388534400;
+
 
   if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
     // Ensure that any and all environment variables are changed to https://.
