diff --git a/DEPS b/DEPS
index e165a0fb8f9aa6794c43b2c042e6fda41f5c0e1a..75080990b17af84df06052107745f50390d8cc95 100644
--- a/DEPS
+++ b/DEPS
@@ -57,18 +57,27 @@ deps = {
   "src/tools/page_cycler/acid3":
     "/trunk/deps/page_cycler/acid3@19546",
 
-  # TODO(jianli): Remove this once we do not need to run worker's layout tests
-  # in ui test.
-  "src/chrome/test/data/workers/LayoutTests/fast/events":
-    Var("webkit_trunk") + "/LayoutTests/fast/events@" + Var("webkit_revision"),
-  "src/chrome/test/data/workers/LayoutTests/fast/workers":
-    Var("webkit_trunk") + "/LayoutTests/fast/workers@" + Var("webkit_revision"),
-  "src/chrome/test/data/workers/LayoutTests/http/tests/resources":
-    Var("webkit_trunk") + "/LayoutTests/http/tests/resources@" + Var("webkit_revision"),
-  "src/chrome/test/data/workers/LayoutTests/http/tests/workers":
-    Var("webkit_trunk") + "/LayoutTests/http/tests/workers@" + Var("webkit_revision"),
-  "src/chrome/test/data/workers/LayoutTests/http/tests/xmlhttprequest":
-    Var("webkit_trunk") + "/LayoutTests/http/tests/xmlhttprequest@" + Var("webkit_revision"),
+  # We run these layout tests as UI tests.  Since many of the buildbots that
+  # run layout tests do NOT have access to the LayoutTest directory, we need
+  # to map them here.  In practice, these do not take up much space.
+  "src/chrome/test/data/layout_tests/LayoutTests/fast/events":
+    Var("webkit_trunk") + "/LayoutTests/fast/events@" +
+    Var("webkit_revision"),
+  "src/chrome/test/data/layout_tests/LayoutTests/fast/workers":
+    Var("webkit_trunk") + "/LayoutTests/fast/workers@" +
+    Var("webkit_revision"),
+  "src/chrome/test/data/layout_tests/LayoutTests/http/tests/resources":
+    Var("webkit_trunk") + "/LayoutTests/http/tests/resources@" +
+    Var("webkit_revision"),
+  "src/chrome/test/data/layout_tests/LayoutTests/http/tests/workers":
+    Var("webkit_trunk") + "/LayoutTests/http/tests/workers@" +
+    Var("webkit_revision"),
+  "src/chrome/test/data/layout_tests/LayoutTests/http/tests/xmlhttprequest":
+    Var("webkit_trunk") + "/LayoutTests/http/tests/xmlhttprequest@" +
+    Var("webkit_revision"),
+  "src/chrome/test/data/layout_tests/LayoutTests/storage/domstorage":
+    Var("webkit_trunk") + "/LayoutTests/storage/domstorage@" +
+    Var("webkit_revision"),
 }
 
 
diff --git a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc
index 0bc4df0870f312972128a763c76622769971cf8e..5a7c169db252f35f9a05f0a079812bd92f1c48a9 100644
--- a/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc
+++ b/chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc
@@ -37,8 +37,9 @@ DOMStorageDispatcherHost::DOMStorageDispatcherHost(
 }
 
 DOMStorageDispatcherHost::~DOMStorageDispatcherHost() {
-  DCHECK(!ever_used_ || ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
   DCHECK(shutdown_);
+  // TODO(jorlow): This sometimes fails on the bots.  Why??
+  //DCHECK(!ever_used_ || ChromeThread::CurrentlyOn(ChromeThread::WEBKIT));
 }
 
 void DOMStorageDispatcherHost::Shutdown() {
diff --git a/chrome/browser/in_process_webkit/dom_storage_uitest.cc b/chrome/browser/in_process_webkit/dom_storage_uitest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..139640f996562fdeba46737cf0a9280d61de7f28
--- /dev/null
+++ b/chrome/browser/in_process_webkit/dom_storage_uitest.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/ui/ui_layout_test.h"
+
+// TODO(jorlow): Enable these tests when we remove them from the
+//               test_exceptions.txt file.
+//static const char* kTopLevelFiles[] = {
+  //"window-attributes-exist.html"
+//};
+
+// TODO(jorlow): Enable these tests when we remove them from the
+//               test_exceptions.txt file.
+static const char* kSubDirFiles[] = {
+  "clear.html",
+  "delete-removal.html",
+  "enumerate-storage.html",
+  "enumerate-with-length-and-key.html",
+  //"iframe-events.html",
+  //"index-get-and-set.html",
+  //"onstorage-attribute-markup.html",
+  //"onstorage-attribute-setattribute.html",
+  //"localstorage/onstorage-attribute-setwindow.html",
+  //"simple-events.html",
+  "simple-usage.html",
+  //"string-conversion.html",
+//  "window-open.html"
+};
+
+class DOMStorageTest : public UILayoutTest {
+ protected:
+  DOMStorageTest()
+      : UILayoutTest(),
+        test_dir_(FilePath().AppendASCII("LayoutTests").
+                  AppendASCII("storage").AppendASCII("domstorage"))
+  {
+  }
+
+  virtual ~DOMStorageTest() { }
+
+  virtual void SetUp() {
+    launch_arguments_.AppendSwitch(switches::kDisablePopupBlocking);
+    launch_arguments_.AppendSwitch(switches::kEnableLocalStorage);
+    launch_arguments_.AppendSwitch(switches::kEnableSessionStorage);
+    UILayoutTest::SetUp();
+  }
+
+  FilePath test_dir_;
+};
+
+TEST_F(DOMStorageTest, DOMStorageLayoutTests) {
+  // TODO(jorlow): Enable these tests when we remove them from the
+  //               test_exceptions.txt file.
+  //InitializeForLayoutTest(test_dir_, FilePath(), false);
+  //for (size_t i=0; i<arraysize(kTopLevelFiles); ++i)
+  //  RunLayoutTest(kTopLevelFiles[i], false, true);
+}
+
+TEST_F(DOMStorageTest, LocalStorageLayoutTests) {
+  InitializeForLayoutTest(test_dir_, FilePath().AppendASCII("localstorage"),
+                          false);
+  for (size_t i=0; i<arraysize(kSubDirFiles); ++i)
+    RunLayoutTest(kSubDirFiles[i], false);
+}
+
+TEST_F(DOMStorageTest, SessionStorageLayoutTests) {
+  InitializeForLayoutTest(test_dir_, FilePath().AppendASCII("sessionstorage"),
+                          false);
+  for (size_t i=0; i<arraysize(kSubDirFiles); ++i)
+    RunLayoutTest(kSubDirFiles[i], false);
+}
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 422bfda256e2e15d2fa42c8b91fff200b11ab6cd..6a2132b382c061d3d67ad4e33e6c1dc50a23b4a2 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -3503,6 +3503,8 @@
         'test/ui/npapi_test_helper.cc',
         'test/ui/npapi_test_helper.h',
         'test/ui/run_all_unittests.cc',
+        'test/ui/ui_layout_test.cc',
+        'test/ui/ui_layout_test.h',
         'test/ui/ui_test.cc',
         'test/ui/ui_test.h',
         'test/ui/ui_test_suite.cc',
@@ -3583,6 +3585,7 @@
         'browser/history/redirect_uitest.cc',
         'browser/iframe_uitest.cc',
         'browser/images_uitest.cc',
+        'browser/in_process_webkit/dom_storage_uitest.cc',
         'browser/locale_tests_uitest.cc',
         'browser/login_prompt_uitest.cc',
         'browser/media_uitest.cc',
diff --git a/chrome/test/data/layout_tests/layout_test_controller.html b/chrome/test/data/layout_tests/layout_test_controller.html
new file mode 100644
index 0000000000000000000000000000000000000000..5e14a39c81ea7e5e7558ad07f07c8c6ca46c6cda
--- /dev/null
+++ b/chrome/test/data/layout_tests/layout_test_controller.html
@@ -0,0 +1,26 @@
+<script>
+function LayoutTestController() {
+  this.wait_until_done_ = false;
+  this.dumpAsText = function () { };
+  this.waitUntilDone = function () {
+    this.wait_until_done_ = true;
+  };
+  this.notifyDone = function () {
+    var cookie = "%COOKIE%=" + encodeURIComponent(document.firstChild.innerText);
+    document.cookie = cookie;
+  };
+  this.OnTimerEvent = function () {
+    // Some layout tests do not call waitUntilDone.  If this is true, we should
+    // assume the test is done when it's finished loading.
+    if (!this.wait_until_done_)
+      layoutTestController.notifyDone();
+  };
+  this.OnLoadEvent = function (event) {
+    // Do a timeout to ensure that we run after all other onload handlers have
+    // finished.
+    setTimeout(layoutTestController.OnTimerEvent, 0);
+  };
+}
+window.layoutTestController = new LayoutTestController();
+window.addEventListener('load', layoutTestController.OnLoadEvent, false);
+</script>
diff --git a/chrome/test/data/workers/layout_test_controller.html b/chrome/test/data/workers/layout_test_controller.html
deleted file mode 100644
index cb97db2af5c86682543ddefe2a12f10ff03cb25e..0000000000000000000000000000000000000000
--- a/chrome/test/data/workers/layout_test_controller.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<script>
-function LayoutTestController() {
-  this.dumpAsText = function () { };
-  this.waitUntilDone = function () { };
-  this.notifyDone = function () {
-    var cookie = "%COOKIE%=" + encodeURIComponent(document.firstChild.innerText);
-    document.cookie = cookie;
-  };
-}
-var layoutTestController = new LayoutTestController();
-window.layoutTestController = layoutTestController;
-</script>
diff --git a/chrome/test/ui/ui_layout_test.cc b/chrome/test/ui/ui_layout_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..dc0a4a2c883dc594defee6eb62c08e8d79f5c4f6
--- /dev/null
+++ b/chrome/test/ui/ui_layout_test.cc
@@ -0,0 +1,234 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/test/ui/ui_layout_test.h"
+
+#include "base/file_util.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/automation/tab_proxy.h"
+#include "net/base/escape.h"
+#include "net/base/net_util.h"
+
+#if defined(OS_WIN)
+static const char kPlatformName[] = "chromium-win";
+#elif defined(OS_MACOSX)
+static const char kPlatformName[] = "chromium-mac";
+#elif defined(OS_LINUX)
+static const char kPlatformName[] = "chromium-linux";
+#else
+#error No known OS defined
+#endif
+
+static const char kTestCompleteCookie[] = "status";
+
+UILayoutTest::UILayoutTest()
+    : UITest(), initialized_for_layout_test_(false), test_count_(0) {
+}
+
+UILayoutTest::~UILayoutTest() {
+  // The deletion might fail because HTTP server process might not been
+  // completely shut down yet and is still holding certain handle to it.
+  // To work around this problem, we try to repeat the deletion several
+  // times.
+  if (!temp_test_dir_.empty()) {
+    static const int kRetryNum = 10;
+    static const int kRetryDelayTimeMs = 500;
+
+    int retry_time = 0;
+    for (int i = 0; i < kRetryNum; ++i) {
+      file_util::Delete(temp_test_dir_, true);
+      if (!file_util::DirectoryExists(temp_test_dir_))
+        break;
+
+      PlatformThread::Sleep(kRetryDelayTimeMs);
+      retry_time += kRetryDelayTimeMs;
+    }
+
+    if (retry_time) {
+      printf("Retrying %d ms to delete temp layout test directory.\n",
+             retry_time);
+    }
+  }
+}
+
+void UILayoutTest::InitializeForLayoutTest(const FilePath& test_parent_dir,
+                                           const FilePath& test_case_dir,
+                                           bool is_http_test) {
+  FilePath src_dir;
+  PathService::Get(base::DIR_SOURCE_ROOT, &src_dir);
+
+  // Gets the file path to WebKit ui layout tests, that is,
+  //   chrome/test/data/ui_tests/LayoutTests/...
+  // Note that we have to use our own copy of WebKit layout tests because our
+  // build machines do not have WebKit layout tests added.
+  layout_test_dir_ = src_dir.AppendASCII("chrome");
+  layout_test_dir_ = layout_test_dir_.AppendASCII("test");
+  layout_test_dir_ = layout_test_dir_.AppendASCII("data");
+  layout_test_dir_ = layout_test_dir_.AppendASCII("layout_tests");
+  layout_test_dir_ = layout_test_dir_.Append(test_parent_dir);
+  layout_test_dir_ = layout_test_dir_.Append(test_case_dir);
+  ASSERT_TRUE(file_util::DirectoryExists(layout_test_dir_));
+
+  // Gets the file path to rebased expected result directory for the current
+  // platform.
+  //   webkit/data/layout_tests/platform/chromium_***/LayoutTests/...
+  rebase_result_dir_ = src_dir.AppendASCII("webkit");
+  rebase_result_dir_ = rebase_result_dir_.AppendASCII("data");
+  rebase_result_dir_ = rebase_result_dir_.AppendASCII("layout_tests");
+  rebase_result_dir_ = rebase_result_dir_.AppendASCII("platform");
+  rebase_result_dir_ = rebase_result_dir_.AppendASCII(kPlatformName);
+  rebase_result_dir_ = rebase_result_dir_.Append(test_parent_dir);
+  rebase_result_dir_ = rebase_result_dir_.Append(test_case_dir);
+
+  // Gets the file path to rebased expected result directory under the
+  // win32 platform. This is used by other non-win32 platform to use the same
+  // rebased expected results.
+#if !defined(OS_WIN)
+  rebase_result_win_dir_ = src_dir.AppendASCII("webkit");
+  rebase_result_win_dir_ = rebase_result_win_dir_.AppendASCII("data");
+  rebase_result_win_dir_ = rebase_result_win_dir_.AppendASCII("layout_tests");
+  rebase_result_win_dir_ = rebase_result_win_dir_.AppendASCII("platform");
+  rebase_result_win_dir_ = rebase_result_win_dir_.AppendASCII("chromium-win");
+  rebase_result_win_dir_ = rebase_result_win_dir_.Append(test_parent_dir);
+  rebase_result_win_dir_ = rebase_result_win_dir_.Append(test_case_dir);
+#endif
+
+  // Creates the temporary directory.
+  ASSERT_TRUE(file_util::CreateNewTempDirectory(
+      FILE_PATH_LITERAL("chrome_ui_layout_tests_"), &temp_test_dir_));
+
+  // Creates the new layout test subdirectory under the temp directory.
+  // Note that we have to mimic the same layout test directory structure,
+  // like .../LayoutTests/fast/workers/.... Otherwise those layout tests
+  // dealing with location property, like worker-location.html, could fail.
+  new_layout_test_dir_ = temp_test_dir_;
+  new_layout_test_dir_ = new_layout_test_dir_.Append(test_parent_dir);
+  if (is_http_test) {
+    new_http_root_dir_ = new_layout_test_dir_;
+    test_case_dir_ = test_case_dir;
+  }
+  new_layout_test_dir_ = new_layout_test_dir_.Append(test_case_dir);
+  ASSERT_TRUE(file_util::CreateDirectory(new_layout_test_dir_));
+
+  // Copies the resource subdirectory.
+  FilePath layout_test_resource_path(layout_test_dir_);
+  layout_test_resource_path =
+      layout_test_resource_path.AppendASCII("resources");
+  FilePath new_layout_test_resource_path(new_layout_test_dir_);
+  new_layout_test_resource_path =
+      new_layout_test_resource_path.AppendASCII("resources");
+  ASSERT_TRUE(file_util::CopyDirectory(
+      layout_test_resource_path, new_layout_test_resource_path, true));
+
+  // Copies the parent resource subdirectory. This is needed in order to run
+  // http layout tests.
+  if (is_http_test) {
+    FilePath parent_resource_path(layout_test_dir_.DirName());
+    parent_resource_path = parent_resource_path.AppendASCII("resources");
+    FilePath new_parent_resource_path(new_layout_test_dir_.DirName());
+    new_parent_resource_path =
+        new_parent_resource_path.AppendASCII("resources");
+    ASSERT_TRUE(file_util::CopyDirectory(
+        parent_resource_path, new_parent_resource_path, true));
+  }
+
+  // Reads the layout test controller simulation script.
+  FilePath path;
+  PathService::Get(chrome::DIR_TEST_DATA, &path);
+  path = path.AppendASCII("layout_tests");
+  path = path.AppendASCII("layout_test_controller.html");
+  ASSERT_TRUE(file_util::ReadFileToString(path, &layout_test_controller_));
+}
+
+void UILayoutTest::RunLayoutTest(const std::string& test_case_file_name,
+                                 bool is_http_test) {
+  SCOPED_TRACE(test_case_file_name.c_str());
+
+  ASSERT_TRUE(!layout_test_controller_.empty());
+
+  // Creates a new cookie name. We will have to use a new cookie because
+  // this function could be called multiple times.
+  std::string status_cookie(kTestCompleteCookie);
+  status_cookie += IntToString(test_count_);
+  test_count_++;
+
+  // Reads the layout test HTML file.
+  FilePath test_file_path(layout_test_dir_);
+  test_file_path = test_file_path.AppendASCII(test_case_file_name);
+  std::string test_html;
+  ASSERT_TRUE(file_util::ReadFileToString(test_file_path, &test_html));
+
+  // Injects the layout test controller into the test HTML.
+  test_html.insert(0, layout_test_controller_);
+  ReplaceSubstringsAfterOffset(
+      &test_html, 0, "%COOKIE%", status_cookie.c_str());
+
+  // Creates the new layout test HTML file.
+  FilePath new_test_file_path(new_layout_test_dir_);
+  new_test_file_path = new_test_file_path.AppendASCII(test_case_file_name);
+  ASSERT_TRUE(file_util::WriteFile(new_test_file_path,
+                                   &test_html.at(0),
+                                   static_cast<int>(test_html.size())));
+
+  scoped_ptr<GURL> new_test_url;
+  if (is_http_test)
+    new_test_url.reset(new GURL(
+        std::string("http://localhost:8080/") +
+        WideToUTF8(test_case_dir_.ToWStringHack()) +
+        "/" +
+        test_case_file_name));
+  else
+    new_test_url.reset(new GURL(net::FilePathToFileURL(new_test_file_path)));
+
+  // Runs the new layout test.
+  scoped_refptr<TabProxy> tab(GetActiveTab());
+  ASSERT_TRUE(tab.get());
+  ASSERT_TRUE(tab->NavigateToURL(*new_test_url.get()));
+  std::string escaped_value =
+      WaitUntilCookieNonEmpty(tab.get(), *new_test_url.get(),
+          status_cookie.c_str(), kTestIntervalMs, kTestWaitTimeoutMs);
+
+  // Unescapes and normalizes the actual result.
+  std::string value = UnescapeURLComponent(escaped_value,
+      UnescapeRule::NORMAL | UnescapeRule::SPACES |
+          UnescapeRule::URL_SPECIAL_CHARS | UnescapeRule::CONTROL_CHARS);
+  value += "\n";
+  ReplaceSubstringsAfterOffset(&value, 0, "\r", "");
+
+  // Reads the expected result. First try to read from rebase directory.
+  // If failed, read from original directory.
+  std::string expected_result_value;
+  if (!ReadExpectedResult(rebase_result_dir_,
+                          test_case_file_name,
+                          &expected_result_value)) {
+    if (rebase_result_win_dir_.empty() ||
+        !ReadExpectedResult(rebase_result_win_dir_,
+                            test_case_file_name,
+                            &expected_result_value))
+      ReadExpectedResult(layout_test_dir_,
+                         test_case_file_name,
+                         &expected_result_value);
+  }
+  ASSERT_TRUE(!expected_result_value.empty());
+
+  // Normalizes the expected result.
+  ReplaceSubstringsAfterOffset(&expected_result_value, 0, "\r", "");
+
+  // Compares the results.
+  EXPECT_STREQ(expected_result_value.c_str(), value.c_str());
+}
+
+bool UILayoutTest::ReadExpectedResult(const FilePath& result_dir_path,
+                                      const std::string test_case_file_name,
+                                      std::string* expected_result_value) {
+  FilePath expected_result_path(result_dir_path);
+  expected_result_path = expected_result_path.AppendASCII(test_case_file_name);
+  expected_result_path = expected_result_path.InsertBeforeExtension(
+      FILE_PATH_LITERAL("-expected"));
+  expected_result_path =
+      expected_result_path.ReplaceExtension(FILE_PATH_LITERAL("txt"));
+  return file_util::ReadFileToString(expected_result_path,
+                                     expected_result_value);
+}
diff --git a/chrome/test/ui/ui_layout_test.h b/chrome/test/ui/ui_layout_test.h
new file mode 100644
index 0000000000000000000000000000000000000000..49d6a63df6b6ba30671d72e4cf52c3d4a0a48396
--- /dev/null
+++ b/chrome/test/ui/ui_layout_test.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_TEST_UI_UI_LAYOUT_TEST_H_
+#define CHROME_TEST_UI_UI_LAYOUT_TEST_H_
+
+#include "base/file_path.h"
+#include "chrome/test/ui/ui_test.h"
+
+class UILayoutTest : public UITest {
+ protected:
+  UILayoutTest();
+  virtual ~UILayoutTest();
+
+  void InitializeForLayoutTest(const FilePath& test_parent_dir,
+                               const FilePath& test_case_dir,
+                               bool is_http_test);
+  void RunLayoutTest(const std::string& test_case_file_name,
+                     bool is_http_test);
+
+  bool ReadExpectedResult(const FilePath& result_dir_path,
+                          const std::string test_case_file_name,
+                          std::string* expected_result_value);
+
+  bool initialized_for_layout_test_;
+  int test_count_;
+  FilePath temp_test_dir_;
+  FilePath layout_test_dir_;
+  FilePath test_case_dir_;
+  FilePath new_http_root_dir_;
+  FilePath new_layout_test_dir_;
+  FilePath rebase_result_dir_;
+  FilePath rebase_result_win_dir_;
+  std::string layout_test_controller_;
+
+  static const int kTestIntervalMs = 250;
+  static const int kTestWaitTimeoutMs = 60 * 1000;
+};
+
+#endif  // CHROME_TEST_UI_UI_LAYOUT_TEST_H_
diff --git a/chrome/worker/worker_uitest.cc b/chrome/worker/worker_uitest.cc
index 567306ce34a73cf099a2833a16980031fab663ef..3421dbdabcf4b0494a39bc45aa2d05faaf55941f 100644
--- a/chrome/worker/worker_uitest.cc
+++ b/chrome/worker/worker_uitest.cc
@@ -2,291 +2,30 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/file_path.h"
-#include "base/file_util.h"
-#include "base/path_service.h"
-#include "base/platform_thread.h"
-#include "base/string_util.h"
 #include "chrome/browser/worker_host/worker_service.h"
-#include "chrome/common/chrome_paths.h"
 #include "chrome/test/automation/browser_proxy.h"
 #include "chrome/test/automation/tab_proxy.h"
-#include "chrome/test/ui/ui_test.h"
-#include "net/base/escape.h"
-#include "net/base/net_util.h"
-
-#if defined(OS_WIN)
-const char kPlatformName[] = "chromium-win";
-#elif defined(OS_MACOSX)
-const char kPlatformName[] = "chromium-mac";
-#elif defined(OS_LINUX)
-const char kPlatformName[] = "chromium-linux";
-#else
-#error No known OS defined
-#endif
-
-const char kTestCompleteCookie[] = "status";
-const char kTestCompleteSuccess[] = "OK";
-const int kTestIntervalMs = 250;
-const int kTestWaitTimeoutMs = 60 * 1000;
-
-class WorkerTest : public UITest {
- protected:
-  WorkerTest();
-  virtual ~WorkerTest();
-
-  void RunTest(const std::wstring& test_case);
+#include "chrome/test/ui/ui_layout_test.h"
 
-  void InitializeForLayoutTest(const FilePath& test_parent_dir,
-                               const FilePath& test_case_dir,
-                               bool is_http_test);
-  void RunLayoutTest(const std::string& test_case_file_name, bool is_http_test);
+static const char kTestCompleteCookie[] = "status";
+static const char kTestCompleteSuccess[] = "OK";
 
+class WorkerTest : public UILayoutTest {
  protected:
-  bool ReadExpectedResult(const FilePath& result_dir_path,
-                          const std::string test_case_file_name,
-                          std::string* expected_result_value);
-
-  bool initialized_for_layout_test_;
-  int test_count_;
-  FilePath temp_test_dir_;
-  FilePath layout_test_dir_;
-  FilePath test_case_dir_;
-  FilePath new_http_root_dir_;
-  FilePath new_layout_test_dir_;
-  FilePath rebase_result_dir_;
-  FilePath rebase_result_win_dir_;
-  std::string layout_test_controller_;
-};
-
-WorkerTest::WorkerTest()
-    : UITest(), initialized_for_layout_test_(false), test_count_(0) {
-}
-
-WorkerTest::~WorkerTest() {
-  // The deletion might fail because HTTP server process might not been
-  // completely shut down yet and is still holding certain handle to it.
-  // To work around this problem, we try to repeat the deletion several
-  // times.
-  if (!temp_test_dir_.empty()) {
-    static const int kRetryNum = 10;
-    static const int kRetryDelayTimeMs = 500;
-
-    int retry_time = 0;
-    for (int i = 0; i < kRetryNum; ++i) {
-      file_util::Delete(temp_test_dir_, true);
-      if (!file_util::DirectoryExists(temp_test_dir_))
-        break;
-
-      PlatformThread::Sleep(kRetryDelayTimeMs);
-      retry_time += kRetryDelayTimeMs;
-    }
-
-    if (retry_time)
-      printf("Retrying %d ms to delete temp worker directory.\n", retry_time);
-  }
-}
-
-void WorkerTest::RunTest(const std::wstring& test_case) {
-  scoped_refptr<TabProxy> tab(GetActiveTab());
-  ASSERT_TRUE(tab.get());
-
-  GURL url = GetTestUrl(L"workers", test_case);
-  ASSERT_TRUE(tab->NavigateToURL(url));
-
-  std::string value = WaitUntilCookieNonEmpty(tab.get(), url,
-      kTestCompleteCookie, kTestIntervalMs, kTestWaitTimeoutMs);
-  ASSERT_STREQ(kTestCompleteSuccess, value.c_str());
-}
+  virtual ~WorkerTest() { }
 
-void WorkerTest::InitializeForLayoutTest(const FilePath& test_parent_dir,
-                                         const FilePath& test_case_dir,
-                                         bool is_http_test) {
-  FilePath src_dir;
-  PathService::Get(base::DIR_SOURCE_ROOT, &src_dir);
-
-  // Gets the file path to WebKit layout tests for workers, that is,
-  //   chrome/test/data/workers/LayoutTests/.../workers
-  // Note that we have to use our copy of WebKit layout tests for workers.
-  // This is because our build machines do not have WebKit layout tests added.
-  layout_test_dir_ = src_dir.AppendASCII("chrome");
-  layout_test_dir_ = layout_test_dir_.AppendASCII("test");
-  layout_test_dir_ = layout_test_dir_.AppendASCII("data");
-  layout_test_dir_ = layout_test_dir_.AppendASCII("workers");
-  layout_test_dir_ = layout_test_dir_.Append(test_parent_dir);
-  layout_test_dir_ = layout_test_dir_.Append(test_case_dir);
-
-  // If not found, try to use the original copy of WebKit layout tests for
-  // workers. For testing only in local machine only.
-  //   third_party/LayoutTests/.../workers
-  if (!file_util::DirectoryExists(layout_test_dir_)) {
-    layout_test_dir_ = src_dir.AppendASCII("third_party");
-    layout_test_dir_ = layout_test_dir_.Append(test_parent_dir);
-    layout_test_dir_ = layout_test_dir_.Append(test_case_dir);
-    ASSERT_TRUE(file_util::DirectoryExists(layout_test_dir_));
-  }
+  void RunTest(const std::wstring& test_case) {
+    scoped_refptr<TabProxy> tab(GetActiveTab());
+    ASSERT_TRUE(tab.get());
 
-  // Gets the file path to rebased expected result directory for workers for
-  // current platform.
-  //   webkit/data/layout_tests/platform/chromium_***/LayoutTests/.../workers
-  rebase_result_dir_ = src_dir.AppendASCII("webkit");
-  rebase_result_dir_ = rebase_result_dir_.AppendASCII("data");
-  rebase_result_dir_ = rebase_result_dir_.AppendASCII("layout_tests");
-  rebase_result_dir_ = rebase_result_dir_.AppendASCII("platform");
-  rebase_result_dir_ = rebase_result_dir_.AppendASCII(kPlatformName);
-  rebase_result_dir_ = rebase_result_dir_.Append(test_parent_dir);
-  rebase_result_dir_ = rebase_result_dir_.Append(test_case_dir);
-
-  // Gets the file path to rebased expected result directory for workers under
-  // win32 platform. This is used by other non-win32 platform to use the same
-  // rebased expected results.
-#if !defined(OS_WIN)
-  rebase_result_win_dir_ = src_dir.AppendASCII("webkit");
-  rebase_result_win_dir_ = rebase_result_win_dir_.AppendASCII("data");
-  rebase_result_win_dir_ = rebase_result_win_dir_.AppendASCII("layout_tests");
-  rebase_result_win_dir_ = rebase_result_win_dir_.AppendASCII("platform");
-  rebase_result_win_dir_ = rebase_result_win_dir_.AppendASCII("chromium-win");
-  rebase_result_win_dir_ = rebase_result_win_dir_.Append(test_parent_dir);
-  rebase_result_win_dir_ = rebase_result_win_dir_.Append(test_case_dir);
-#endif
-
-  // Creates the temporary directory.
-  ASSERT_TRUE(file_util::CreateNewTempDirectory(
-      FILE_PATH_LITERAL("chrome_worker_test_"), &temp_test_dir_));
-
-  // Creates the new layout test subdirectory under the temp directory.
-  // Note that we have to mimic the same layout test directory structure,
-  // like .../LayoutTests/fast/workers/.... Otherwise those layout tests
-  // dealing with location property, like worker-location.html, could fail.
-  new_layout_test_dir_ = temp_test_dir_;
-  new_layout_test_dir_ = new_layout_test_dir_.Append(test_parent_dir);
-  if (is_http_test) {
-    new_http_root_dir_ = new_layout_test_dir_;
-    test_case_dir_ = test_case_dir;
-  }
-  new_layout_test_dir_ = new_layout_test_dir_.Append(test_case_dir);
-  ASSERT_TRUE(file_util::CreateDirectory(new_layout_test_dir_));
-
-  // Copies the resource subdirectory.
-  FilePath layout_test_resource_path(layout_test_dir_);
-  layout_test_resource_path =
-      layout_test_resource_path.AppendASCII("resources");
-  FilePath new_layout_test_resource_path(new_layout_test_dir_);
-  new_layout_test_resource_path =
-      new_layout_test_resource_path.AppendASCII("resources");
-  ASSERT_TRUE(file_util::CopyDirectory(
-      layout_test_resource_path, new_layout_test_resource_path, true));
-
-  // Copies the parent resource subdirectory. This is needed in order to run
-  // http layout tests.
-  if (is_http_test) {
-    FilePath parent_resource_path(layout_test_dir_.DirName());
-    parent_resource_path = parent_resource_path.AppendASCII("resources");
-    FilePath new_parent_resource_path(new_layout_test_dir_.DirName());
-    new_parent_resource_path =
-        new_parent_resource_path.AppendASCII("resources");
-    ASSERT_TRUE(file_util::CopyDirectory(
-        parent_resource_path, new_parent_resource_path, true));
-  }
+    GURL url = GetTestUrl(L"workers", test_case);
+    ASSERT_TRUE(tab->NavigateToURL(url));
 
-  // Reads the layout test controller simulation script.
-  FilePath path;
-  PathService::Get(chrome::DIR_TEST_DATA, &path);
-  path = path.AppendASCII("workers");
-  path = path.AppendASCII("layout_test_controller.html");
-  ASSERT_TRUE(file_util::ReadFileToString(path, &layout_test_controller_));
-}
-
-void WorkerTest::RunLayoutTest(const std::string& test_case_file_name,
-                               bool is_http_test) {
-  SCOPED_TRACE(test_case_file_name.c_str());
-
-  ASSERT_TRUE(!layout_test_controller_.empty());
-
-  // Creates a new cookie name. We will have to use a new cookie because
-  // this function could be called multiple times.
-  std::string status_cookie(kTestCompleteCookie);
-  status_cookie += IntToString(test_count_);
-  test_count_++;
-
-  // Reads the layout test HTML file.
-  FilePath test_file_path(layout_test_dir_);
-  test_file_path = test_file_path.AppendASCII(test_case_file_name);
-  std::string test_html;
-  ASSERT_TRUE(file_util::ReadFileToString(test_file_path, &test_html));
-
-  // Injects the layout test controller into the test HTML.
-  test_html.insert(0, layout_test_controller_);
-  ReplaceSubstringsAfterOffset(
-      &test_html, 0, "%COOKIE%", status_cookie.c_str());
-
-  // Creates the new layout test HTML file.
-  FilePath new_test_file_path(new_layout_test_dir_);
-  new_test_file_path = new_test_file_path.AppendASCII(test_case_file_name);
-  ASSERT_TRUE(file_util::WriteFile(new_test_file_path,
-                                   &test_html.at(0),
-                                   static_cast<int>(test_html.size())));
-
-  scoped_ptr<GURL> new_test_url;
-  if (is_http_test)
-    new_test_url.reset(new GURL(
-        std::string("http://localhost:8080/") +
-        WideToUTF8(test_case_dir_.ToWStringHack()) +
-        "/" +
-        test_case_file_name));
-  else
-    new_test_url.reset(new GURL(net::FilePathToFileURL(new_test_file_path)));
-
-  // Runs the new layout test.
-  scoped_refptr<TabProxy> tab(GetActiveTab());
-  ASSERT_TRUE(tab.get());
-  ASSERT_TRUE(tab->NavigateToURL(*new_test_url.get()));
-  std::string escaped_value =
-      WaitUntilCookieNonEmpty(tab.get(), *new_test_url.get(),
-          status_cookie.c_str(), kTestIntervalMs, kTestWaitTimeoutMs);
-
-  // Unescapes and normalizes the actual result.
-  std::string value = UnescapeURLComponent(escaped_value,
-      UnescapeRule::NORMAL | UnescapeRule::SPACES |
-          UnescapeRule::URL_SPECIAL_CHARS | UnescapeRule::CONTROL_CHARS);
-  value += "\n";
-  ReplaceSubstringsAfterOffset(&value, 0, "\r", "");
-
-  // Reads the expected result. First try to read from rebase directory.
-  // If failed, read from original directory.
-  std::string expected_result_value;
-  if (!ReadExpectedResult(rebase_result_dir_,
-                          test_case_file_name,
-                          &expected_result_value)) {
-    if (rebase_result_win_dir_.empty() ||
-        !ReadExpectedResult(rebase_result_win_dir_,
-                            test_case_file_name,
-                            &expected_result_value))
-      ReadExpectedResult(layout_test_dir_,
-                         test_case_file_name,
-                         &expected_result_value);
+    std::string value = WaitUntilCookieNonEmpty(tab.get(), url,
+        kTestCompleteCookie, kTestIntervalMs, kTestWaitTimeoutMs);
+    ASSERT_STREQ(kTestCompleteSuccess, value.c_str());
   }
-  ASSERT_TRUE(!expected_result_value.empty());
-
-  // Normalizes the expected result.
-  ReplaceSubstringsAfterOffset(&expected_result_value, 0, "\r", "");
-
-  // Compares the results.
-  EXPECT_STREQ(expected_result_value.c_str(), value.c_str());
-}
-
-bool WorkerTest::ReadExpectedResult(const FilePath& result_dir_path,
-                                    const std::string test_case_file_name,
-                                    std::string* expected_result_value) {
-  FilePath expected_result_path(result_dir_path);
-  expected_result_path = expected_result_path.AppendASCII(test_case_file_name);
-  expected_result_path = expected_result_path.InsertBeforeExtension(
-      FILE_PATH_LITERAL("-expected"));
-  expected_result_path =
-      expected_result_path.ReplaceExtension(FILE_PATH_LITERAL("txt"));
-  return file_util::ReadFileToString(expected_result_path,
-                                     expected_result_value);
-}
+};
 
 TEST_F(WorkerTest, DISABLED_SingleWorker) {
   RunTest(L"single_worker.html");