summaryrefslogtreecommitdiff
path: root/chrome/test
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2013-10-22 16:41:35 +0100
committerTorne (Richard Coles) <torne@google.com>2013-10-22 16:41:35 +0100
commit8bcbed890bc3ce4d7a057a8f32cab53fa534672e (patch)
tree1390b6675d21328859f01f50203d9bde09105298 /chrome/test
parent116fa16b45c9efe30e785b9fc32f09780ca23bec (diff)
downloadchromium_org-8bcbed890bc3ce4d7a057a8f32cab53fa534672e.tar.gz
Merge from Chromium at DEPS revision 230120
This commit was generated by merge_to_master.py. Change-Id: I54bc06b7ee8a07092e74ce3b68c6893508349042
Diffstat (limited to 'chrome/test')
-rw-r--r--chrome/test/android/OWNERS2
-rw-r--r--chrome/test/android/javatests/src/org/chromium/chrome/test/util/InfoBarTestAnimationListener.java98
-rw-r--r--chrome/test/android/javatests/src/org/chromium/chrome/test/util/InfoBarUtil.java76
-rw-r--r--chrome/test/android/javatests/src/org/chromium/chrome/test/util/TranslateUtil.java78
-rw-r--r--chrome/test/base/in_process_browser_test_browsertest.cc1
-rw-r--r--chrome/test/base/test_browser_window.h3
-rw-r--r--chrome/test/base/test_launcher_utils.cc6
-rw-r--r--chrome/test/base/testing_profile.cc16
-rw-r--r--chrome/test/base/testing_profile.h8
-rw-r--r--chrome/test/base/testing_profile_manager.cc2
-rwxr-xr-xchrome/test/chromedriver/test/run_py_tests.py24
-rw-r--r--chrome/test/functional/ispy/common/ispy_utils.py136
-rw-r--r--chrome/test/functional/ispy/common/ispy_utils_unittest.py121
-rw-r--r--chrome/test/functional/ispy/server/debug_view_handler.py10
-rw-r--r--chrome/test/functional/ispy/server/main_view_handler.py26
-rw-r--r--chrome/test/functional/ispy/server/update_mask_handler.py18
-rw-r--r--chrome/test/functional/ispy/server/views/debug_view.html4
-rw-r--r--chrome/test/functional/ispy/server/views/diff_view.html62
-rw-r--r--chrome/test/functional/ispy/server/views/main_view.html6
-rw-r--r--chrome/test/gpu/gpu_feature_browsertest.cc3
-rw-r--r--chrome/test/ppapi/ppapi_browsertest.cc21
-rw-r--r--chrome/test/remoting/page_load_notification_observer.cc29
-rw-r--r--chrome/test/remoting/page_load_notification_observer.h34
-rw-r--r--chrome/test/remoting/remote_desktop_browsertest.cc310
-rw-r--r--chrome/test/remoting/remote_desktop_browsertest.h140
25 files changed, 775 insertions, 459 deletions
diff --git a/chrome/test/android/OWNERS b/chrome/test/android/OWNERS
index a223621c02..df798f4460 100644
--- a/chrome/test/android/OWNERS
+++ b/chrome/test/android/OWNERS
@@ -1,6 +1,8 @@
aruslan@chromium.org
bulach@chromium.org
+dfalcantara@chromium.org
dtrainor@chromium.org
+miguelg@chromium.org
nyquist@chromium.org
tedchoc@chromium.org
yfriedman@chromium.org
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/InfoBarTestAnimationListener.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/InfoBarTestAnimationListener.java
new file mode 100644
index 0000000000..97b39a3800
--- /dev/null
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/InfoBarTestAnimationListener.java
@@ -0,0 +1,98 @@
+// Copyright 2013 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.
+package org.chromium.chrome.test.util;
+
+import android.os.SystemClock;
+
+import java.util.concurrent.TimeUnit;
+
+import org.chromium.chrome.browser.infobar.AnimationHelper;
+import org.chromium.chrome.browser.infobar.InfoBarContainer;
+
+/**
+ * Allow tests to register for animation finished notifications.
+ */
+public class InfoBarTestAnimationListener implements InfoBarContainer.InfoBarAnimationListener {
+
+ private static long WAIT_MILLIS = TimeUnit.SECONDS.toMillis(5);
+
+ private static class ConditionalWait {
+ private volatile Boolean mCondition;
+ private Object mLock;
+
+ ConditionalWait() {
+ mCondition = false;
+ mLock = new Object();
+ }
+
+ /**
+ * Waits for {@code millis} or until the value of the condition becomes true
+ * if it does it resets it to false before returning so it can be reused.
+ *
+ * @return true if the condition becomes true before the specified {@code millis}.
+ */
+ public boolean waitAndExpire(long millis) throws InterruptedException {
+ synchronized(mLock) {
+ while (!mCondition && millis > 0) {
+ long start = SystemClock.elapsedRealtime();
+ mLock.wait(millis);
+ millis -= (SystemClock.elapsedRealtime() - start);
+ }
+ boolean result = mCondition;
+ mCondition = false;
+ return result;
+ }
+ }
+
+ public void set(boolean value) {
+ synchronized(mLock) {
+ mCondition = value;
+ if (value) {
+ mLock.notify();
+ }
+ }
+ }
+ }
+
+ private ConditionalWait mAddAnimationFinished;
+ private ConditionalWait mSwapAnimationFinished;
+ private ConditionalWait mRemoveAnimationFinished;
+
+
+ public InfoBarTestAnimationListener() {
+ mAddAnimationFinished = new ConditionalWait();
+ mSwapAnimationFinished = new ConditionalWait();
+ mRemoveAnimationFinished = new ConditionalWait();
+ }
+
+ @Override
+ public void notifyAnimationFinished(int animationType) {
+ switch(animationType) {
+ case AnimationHelper.ANIMATION_TYPE_SHOW:
+ mAddAnimationFinished.set(true);
+ break;
+ case AnimationHelper.ANIMATION_TYPE_SWAP:
+ mSwapAnimationFinished.set(true);
+ break;
+ case AnimationHelper.ANIMATION_TYPE_HIDE:
+ mRemoveAnimationFinished.set(true);
+ break;
+ default:
+ throw new UnsupportedOperationException(
+ "Animation finished for unknown type " + animationType);
+ }
+ }
+
+ public boolean addInfoBarAnimationFinished() throws InterruptedException {
+ return mAddAnimationFinished.waitAndExpire(WAIT_MILLIS);
+ }
+
+ public boolean swapInfoBarAnimationFinished() throws InterruptedException {
+ return mSwapAnimationFinished.waitAndExpire(WAIT_MILLIS);
+ }
+
+ public boolean removeInfoBarAnimationFinished() throws InterruptedException {
+ return mRemoveAnimationFinished.waitAndExpire(WAIT_MILLIS);
+ }
+}
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/InfoBarUtil.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/InfoBarUtil.java
new file mode 100644
index 0000000000..70a9f740dc
--- /dev/null
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/InfoBarUtil.java
@@ -0,0 +1,76 @@
+// Copyright 2013 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.
+
+package org.chromium.chrome.test.util;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.TouchUtils;
+import android.view.View;
+
+import org.chromium.chrome.R;
+
+import org.chromium.chrome.browser.infobar.InfoBar;
+import org.chromium.content.browser.test.util.TestTouchUtils;
+
+/**
+ * Utility functions for dealing with InfoBars.
+ */
+public class InfoBarUtil {
+ /**
+ * Finds, and optionally clicks, the button with the specified ID in the given InfoBar.
+ * @return True if the View was found.
+ */
+ private static boolean findButton(ActivityInstrumentationTestCase2<?> test,
+ InfoBar infoBar, int buttonId, boolean click) {
+ View button = infoBar.getContentWrapper().findViewById(buttonId);
+ if (button == null) return false;
+ if (click) TestTouchUtils.singleClickView(test.getInstrumentation(), button);
+ return true;
+ }
+
+ /**
+ * Checks if the primary button exists on the InfoBar.
+ * @return True if the View was found.
+ */
+ public static boolean hasPrimaryButton(ActivityInstrumentationTestCase2<?> test,
+ InfoBar infoBar) {
+ return findButton(test, infoBar, R.id.button_primary, false);
+ }
+
+ /**
+ * Checks if the secondary button exists on the InfoBar.
+ * @return True if the View was found.
+ */
+ public static boolean hasSecondaryButton(ActivityInstrumentationTestCase2<?> test,
+ InfoBar infoBar) {
+ return findButton(test, infoBar, R.id.button_secondary, false);
+ }
+
+ /**
+ * Simulates clicking the Close button in the specified infobar.
+ * @return True if the View was found.
+ */
+ public static boolean clickCloseButton(ActivityInstrumentationTestCase2<?> test,
+ InfoBar infoBar) {
+ return findButton(test, infoBar, R.id.infobar_close_button, true);
+ }
+
+ /**
+ * Simulates clicking the primary button in the specified infobar.
+ * @return True if the View was found.
+ */
+ public static boolean clickPrimaryButton(ActivityInstrumentationTestCase2<?> test,
+ InfoBar infoBar) {
+ return findButton(test, infoBar, R.id.button_primary, true);
+ }
+
+ /**
+ * Simulates clicking the secondary button in the specified infobar.
+ * @return True if the View was found.
+ */
+ public static boolean clickSecondaryButton(ActivityInstrumentationTestCase2<?> test,
+ InfoBar infoBar) {
+ return findButton(test, infoBar, R.id.button_secondary, true);
+ }
+}
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/TranslateUtil.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/TranslateUtil.java
new file mode 100644
index 0000000000..7abc29f9eb
--- /dev/null
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/TranslateUtil.java
@@ -0,0 +1,78 @@
+// Copyright 2013 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.
+
+package org.chromium.chrome.test.util;
+
+import android.content.Context;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.TouchUtils;
+import android.text.SpannableString;
+import android.text.style.ClickableSpan;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.chromium.chrome.R;
+
+import org.chromium.chrome.browser.infobar.InfoBar;
+import org.chromium.content.browser.test.util.TestTouchUtils;
+
+
+/**
+ * Utility functions for dealing with Translate InfoBars.
+ */
+public class TranslateUtil {
+ /**
+ * Finds the first clickable span inside a TextView and clicks it.
+ *
+ * @return True if the panel is opened.
+ */
+ public static boolean openLanguagePanel(ActivityInstrumentationTestCase2<?> test,
+ InfoBar infoBar) {
+ View view = infoBar.getContentWrapper().findViewById(R.id.infobar_message);
+ if (view == null) {
+ return false;
+ }
+
+ TextView text = (TextView) view.findViewById(R.id.infobar_message);
+
+ SpannableString spannable = (SpannableString) text.getText();
+ ClickableSpan[] clickable =
+ spannable.getSpans(0, spannable.length() -1, ClickableSpan.class);
+ if (clickable.length <= 0) {
+ return false;
+ }
+
+ // Find the approximate coordinates of the first link of the first line of text so we can
+ // click there. Clicking on any character of the link will work so instead of focusing on
+ // the beginning of the link we add one more character so that finding a valid coordinate
+ // is more reliable.
+ int x = spannable.getSpanStart(clickable[0]) + 1;
+ float nChars = text.getLayout().getLineVisibleEnd(0);
+
+ // Not all characters have the same width but this is a good approximation.
+ float sizePerChar = text.getLayout().getLineWidth(0) / nChars;
+ float xPos = text.getPaddingLeft() + (sizePerChar * x);
+ float yPos = text.getHeight() / (float) 2;
+
+ TestTouchUtils.singleClickView(test.getInstrumentation(), text, (int) xPos, (int) yPos);
+
+ return verifyInfoBarText(infoBar,
+ test.getActivity().getString(R.string.translate_infobar_change_languages));
+ }
+
+ public static boolean verifyInfoBarText(InfoBar infoBar, String text) {
+ View view = infoBar.getContentWrapper().findViewById(R.id.infobar_message);
+ if (view == null) {
+ return false;
+ }
+ String infoBarText = findInfoBarText(view);
+ return text.equals(infoBarText);
+ }
+
+ private static String findInfoBarText(View view) {
+ TextView text = (TextView) view.findViewById(R.id.infobar_message);
+ return text != null ? text.getText().toString() : null;
+ }
+}
diff --git a/chrome/test/base/in_process_browser_test_browsertest.cc b/chrome/test/base/in_process_browser_test_browsertest.cc
index 2fbe4194db..5272c35bff 100644
--- a/chrome/test/base/in_process_browser_test_browsertest.cc
+++ b/chrome/test/base/in_process_browser_test_browsertest.cc
@@ -39,6 +39,7 @@ class LoadFailObserver : public content::WebContentsObserver {
virtual void DidFailProvisionalLoad(
int64 frame_id,
+ const string16& frame_unique_name,
bool is_main_frame,
const GURL& validated_url,
int error_code,
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h
index 5895ff1788..1f2804453c 100644
--- a/chrome/test/base/test_browser_window.h
+++ b/chrome/test/base/test_browser_window.h
@@ -90,9 +90,6 @@ class TestBrowserWindow : public BrowserWindow {
bool* is_keyboard_shortcut) OVERRIDE;
virtual void HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) OVERRIDE {}
- virtual void ShowCreateChromeAppShortcutsDialog(
- Profile* profile,
- const extensions::Extension* app) OVERRIDE {}
virtual bool IsBookmarkBarVisible() const OVERRIDE;
virtual bool IsBookmarkBarAnimating() const OVERRIDE;
diff --git a/chrome/test/base/test_launcher_utils.cc b/chrome/test/base/test_launcher_utils.cc
index 8517cc9206..f5bf93c19b 100644
--- a/chrome/test/base/test_launcher_utils.cc
+++ b/chrome/test/base/test_launcher_utils.cc
@@ -47,12 +47,6 @@ void PrepareBrowserCommandLineForTests(CommandLine* command_line) {
// Don't install default apps.
command_line->AppendSwitch(switches::kDisableDefaultApps);
-#if defined(OS_LINUX)
- // Don't collect GPU info, load GPU blacklist, or schedule a GPU blacklist
- // auto-update on Linux bots for now (http://crbug.com/304833).
- command_line->AppendSwitch(switches::kSkipGpuDataLoading);
-#endif
-
#if defined(USE_AURA)
// Disable window animations under Ash as the animations effect the
// coordinates returned and result in flake.
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index 138bb1639b..bc655aa35e 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -47,6 +47,7 @@
#include "chrome/browser/prefs/pref_service_syncable.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.h"
+#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/storage_partition_descriptor.h"
#include "chrome/browser/search_engines/template_url_fetcher_factory.h"
#include "chrome/browser/webdata/web_data_service.h"
@@ -230,6 +231,7 @@ TestingProfile::TestingProfile(
scoped_refptr<ExtensionSpecialStoragePolicy> extension_policy,
scoped_ptr<PrefServiceSyncable> prefs,
bool incognito,
+ const std::string& managed_user_id,
const TestingFactories& factories)
: start_time_(Time::Now()),
prefs_(prefs.release()),
@@ -237,6 +239,7 @@ TestingProfile::TestingProfile(
incognito_(incognito),
force_incognito_(false),
original_profile_(NULL),
+ managed_user_id_(managed_user_id),
last_session_exited_cleanly_(true),
extension_special_storage_policy_(extension_policy),
profile_path_(path),
@@ -355,6 +358,10 @@ void TestingProfile::FinishInit() {
content::Source<Profile>(static_cast<Profile*>(this)),
content::NotificationService::NoDetails());
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ if (profile_manager)
+ profile_manager->InitProfileUserPrefs(this);
+
if (delegate_)
delegate_->OnProfileCreated(this, true, false);
}
@@ -586,7 +593,7 @@ Profile* TestingProfile::GetOriginalProfile() {
}
bool TestingProfile::IsManaged() {
- return !GetPrefs()->GetString(prefs::kManagedUserId).empty();
+ return !managed_user_id_.empty();
}
ExtensionService* TestingProfile::GetExtensionService() {
@@ -866,6 +873,11 @@ void TestingProfile::Builder::SetIncognito() {
incognito_ = true;
}
+void TestingProfile::Builder::SetManagedUserId(
+ const std::string& managed_user_id) {
+ managed_user_id_ = managed_user_id;
+}
+
void TestingProfile::Builder::AddTestingFactory(
BrowserContextKeyedServiceFactory* service_factory,
BrowserContextKeyedServiceFactory::FactoryFunction callback) {
@@ -875,11 +887,13 @@ void TestingProfile::Builder::AddTestingFactory(
scoped_ptr<TestingProfile> TestingProfile::Builder::Build() {
DCHECK(!build_called_);
build_called_ = true;
+
return scoped_ptr<TestingProfile>(new TestingProfile(
path_,
delegate_,
extension_policy_,
pref_service_.Pass(),
incognito_,
+ managed_user_id_,
testing_factories_));
}
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h
index 4bcd052d69..297cb9529f 100644
--- a/chrome/test/base/testing_profile.h
+++ b/chrome/test/base/testing_profile.h
@@ -100,6 +100,10 @@ class TestingProfile : public Profile {
// Makes the Profile being built an incognito profile.
void SetIncognito();
+ // Sets the managed user ID (which is empty by default). If it is set to a
+ // non-empty string, the profile is managed.
+ void SetManagedUserId(const std::string& managed_user_id);
+
// Creates the TestingProfile using previously-set settings.
scoped_ptr<TestingProfile> Build();
@@ -113,6 +117,7 @@ class TestingProfile : public Profile {
base::FilePath path_;
Delegate* delegate_;
bool incognito_;
+ std::string managed_user_id_;
TestingFactories testing_factories_;
DISALLOW_COPY_AND_ASSIGN(Builder);
@@ -138,6 +143,7 @@ class TestingProfile : public Profile {
scoped_refptr<ExtensionSpecialStoragePolicy> extension_policy,
scoped_ptr<PrefServiceSyncable> prefs,
bool incognito,
+ const std::string& managed_user_id,
const TestingFactories& factories);
virtual ~TestingProfile();
@@ -348,6 +354,8 @@ class TestingProfile : public Profile {
scoped_ptr<Profile> incognito_profile_;
Profile* original_profile_;
+ std::string managed_user_id_;
+
// Did the last session exit cleanly? Default is true.
bool last_session_exited_cleanly_;
diff --git a/chrome/test/base/testing_profile_manager.cc b/chrome/test/base/testing_profile_manager.cc
index 644760cc22..a5ef121bfe 100644
--- a/chrome/test/base/testing_profile_manager.cc
+++ b/chrome/test/base/testing_profile_manager.cc
@@ -60,6 +60,8 @@ TestingProfile* TestingProfileManager::CreateTestingProfile(
TestingProfile::Builder builder;
builder.SetPath(profile_path);
builder.SetPrefService(prefs.Pass());
+ builder.SetManagedUserId(managed_user_id);
+
TestingProfile* profile = builder.Build().release();
profile_manager_->AddProfile(profile); // Takes ownership.
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index ff0ba43bde..dd38b4b1d5 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -96,12 +96,8 @@ _ANDROID_NEGATIVE_FILTER['com.google.android.apps.chrome'] = (
# Android doesn't support switches and extensions.
'ChromeSwitchesCapabilityTest.*',
'ChromeExtensionsCapabilityTest.*',
- # https://code.google.com/p/chromedriver/issues/detail?id=459
- 'ChromeDriverTest.testShouldHandleNewWindowLoadingProperly',
# https://crbug.com/274650
'ChromeDriverTest.testCloseWindow',
- # https://code.google.com/p/chromedriver/issues/detail?id=259
- 'ChromeDriverTest.testSendKeysToElement',
# https://code.google.com/p/chromedriver/issues/detail?id=270
'ChromeDriverTest.testPopups',
# https://code.google.com/p/chromedriver/issues/detail?id=298
@@ -117,12 +113,7 @@ _ANDROID_NEGATIVE_FILTER['com.google.android.apps.chrome'] = (
]
)
_ANDROID_NEGATIVE_FILTER['com.android.chrome'] = (
- _ANDROID_NEGATIVE_FILTER['com.google.android.apps.chrome'] + [
- # Touch support was added to devtools in Chrome v30.
- 'ChromeDriverTest.testTouchDownUpElement',
- 'ChromeDriverTest.testTouchMovedElement',
- ]
-)
+ _ANDROID_NEGATIVE_FILTER['com.google.android.apps.chrome'])
_ANDROID_NEGATIVE_FILTER['com.chrome.beta'] = (
_ANDROID_NEGATIVE_FILTER['com.google.android.apps.chrome'])
_ANDROID_NEGATIVE_FILTER['org.chromium.chrome.testshell'] = (
@@ -130,6 +121,7 @@ _ANDROID_NEGATIVE_FILTER['org.chromium.chrome.testshell'] = (
# ChromiumTestShell doesn't support multiple tabs.
'ChromeDriverTest.testGetWindowHandles',
'ChromeDriverTest.testSwitchToWindow',
+ 'ChromeDriverTest.testShouldHandleNewWindowLoadingProperly',
]
)
@@ -166,11 +158,14 @@ class ChromeDriverTest(ChromeDriverBaseTest):
def GlobalSetUp():
ChromeDriverTest._http_server = webserver.WebServer(
chrome_paths.GetTestData())
+ ChromeDriverTest._sync_server = webserver.SyncWebServer()
if _ANDROID_PACKAGE:
ChromeDriverTest._adb = android_commands.AndroidCommands()
- host_port = ChromeDriverTest._http_server._server.server_port
+ http_host_port = ChromeDriverTest._http_server._server.server_port
+ sync_host_port = ChromeDriverTest._sync_server._server.server_port
forwarder.Forwarder.Map(
- [(host_port, host_port)], ChromeDriverTest._adb)
+ [(http_host_port, http_host_port), (sync_host_port, sync_host_port)],
+ ChromeDriverTest._adb)
@staticmethod
def GlobalTearDown():
@@ -544,7 +539,6 @@ class ChromeDriverTest(ChromeDriverBaseTest):
def testShouldHandleNewWindowLoadingProperly(self):
"""Tests that ChromeDriver determines loading correctly for new windows."""
- sync_server = webserver.SyncWebServer()
self._http_server.SetDataForPath(
'/newwindow',
"""
@@ -552,7 +546,7 @@ class ChromeDriverTest(ChromeDriverBaseTest):
<body>
<a href='%s' target='_blank'>new window/tab</a>
</body>
- </html>""" % sync_server.GetUrl())
+ </html>""" % self._sync_server.GetUrl())
self._driver.Load(self._http_server.GetUrl() + '/newwindow')
old_windows = self._driver.GetWindowHandles()
self._driver.FindElement('tagName', 'a').Click()
@@ -562,7 +556,7 @@ class ChromeDriverTest(ChromeDriverBaseTest):
self.assertFalse(self._driver.IsLoading())
self._driver.SwitchToWindow(new_window)
self.assertTrue(self._driver.IsLoading())
- sync_server.RespondWithContent('<html>new window</html>')
+ self._sync_server.RespondWithContent('<html>new window</html>')
self._driver.ExecuteScript('return 1') # Shouldn't hang.
def testPopups(self):
diff --git a/chrome/test/functional/ispy/common/ispy_utils.py b/chrome/test/functional/ispy/common/ispy_utils.py
index db8f895822..10669513f0 100644
--- a/chrome/test/functional/ispy/common/ispy_utils.py
+++ b/chrome/test/functional/ispy/common/ispy_utils.py
@@ -13,32 +13,31 @@ import sys
import image_tools
-def GetTestPath(test_run, test_name, file_name=''):
- """Get the path to a test file in the given test run and test.
+def GetExpectationPath(expectation, file_name=''):
+ """Get the path to a test file in the given test run and expectation.
Args:
- test_run: name of the test run.
- test_name: name of the test.
+ expectation: name of the expectation.
file_name: name of the file.
Returns:
the path as a string relative to the bucket.
"""
- return 'tests/%s/%s/%s' % (test_run, test_name, file_name)
+ return 'expectations/%s/%s' % (expectation, file_name)
-def GetFailurePath(test_run, test_name, file_name=''):
+def GetFailurePath(test_run, expectation, file_name=''):
"""Get the path to a failure file in the given test run and test.
Args:
test_run: name of the test run.
- test_name: name of the test.
+ expectation: name of the expectation.
file_name: name of the file.
Returns:
the path as a string relative to the bucket.
"""
- return 'failures/%s/%s/%s' % (test_run, test_name, file_name)
+ return 'failures/%s/%s/%s' % (test_run, expectation, file_name)
class ISpyUtils(object):
@@ -87,120 +86,115 @@ class ISpyUtils(object):
self.cloud_bucket.UpdateFile(full_path, image_tools.EncodePNG(image))
- def UploadTest(self, test_run, test_name, images):
- """Creates and uploads a test to GS from a set of images and name.
+ def UploadExpectation(self, expectation, images):
+ """Creates and uploads an expectation to GS from a set of images and name.
This method generates a mask from the uploaded images, then
- uploads the mask and first of the images to GS as a test.
+ uploads the mask and first of the images to GS as a expectation.
Args:
- test_run: the name of the test_run.
- test_name: the name of the test.
+ expectation: name for this expectation, any existing expectation with the
+ name will be replaced.
images: a list of RGB encoded PIL.Images
"""
mask = image_tools.InflateMask(image_tools.CreateMask(images), 7)
self.UploadImage(
- GetTestPath(test_run, test_name, 'expected.png'), images[0])
- self.UploadImage(GetTestPath(test_run, test_name, 'mask.png'), mask)
+ GetExpectationPath(expectation, 'expected.png'), images[0])
+ self.UploadImage(GetExpectationPath(expectation, 'mask.png'), mask)
- def RunTest(self, test_run, test_name, actual):
+ def RunTest(self, test_run, expectation, actual):
"""Runs an image comparison, and uploads discrepancies to GS.
Args:
test_run: the name of the test_run.
- test_name: the name of the test to run.
- actual: an RGB-encoded PIL.Image that is the actual result of the
- test.
+ expectation: the name of the expectation to use for comparison.
+ actual: an RGB-encoded PIL.Image that is the actual result.
Raises:
- cloud_bucket.NotFoundError: if the given test_name is not found.
+ cloud_bucket.NotFoundError: if the given expectation is not found.
"""
- test = self.GetTest(test_run, test_name)
- if not image_tools.SameImage(actual, test.expected, mask=test.mask):
+ expectation_tuple = self.GetExpectation(expectation)
+ if not image_tools.SameImage(
+ actual, expectation_tuple.expected, mask=expectation_tuple.mask):
self.UploadImage(
- GetFailurePath(test_run, test_name, 'actual.png'), actual)
+ GetFailurePath(test_run, expectation, 'actual.png'), actual)
diff, diff_pxls = image_tools.VisualizeImageDifferences(
- test.expected, actual, mask=test.mask)
- self.UploadImage(GetFailurePath(test_run, test_name, 'diff.png'), diff)
+ expectation_tuple.expected, actual, mask=expectation_tuple.mask)
+ self.UploadImage(GetFailurePath(test_run, expectation, 'diff.png'), diff)
self.cloud_bucket.UploadFile(
- GetFailurePath(test_run, test_name, 'info.txt'),
+ GetFailurePath(test_run, expectation, 'info.txt'),
json.dumps({
'different_pixels': diff_pxls,
'fraction_different':
diff_pxls / float(actual.size[0] * actual.size[1])}),
'application/json')
- def GetTest(self, test_run, test_name):
- """Returns given test from GS.
+ def GetExpectation(self, expectation):
+ """Returns the given expectation from GS.
Args:
- test_run: the name of the test_run.
- test_name: the name of the test to get from GS.
+ expectation: the name of the expectation to get.
Returns:
- A named tuple: 'Test', containing two images: expected and mask.
+ A named tuple: 'Expectation', containing two images: expected and mask.
Raises:
cloud_bucket.NotFoundError: if the test is not found in GS.
"""
- Test = collections.namedtuple('Test', ['expected', 'mask'])
- return Test(self.DownloadImage(GetTestPath(test_run, test_name,
- 'expected.png')),
- self.DownloadImage(GetTestPath(test_run, test_name,
- 'mask.png')))
+ Expectation = collections.namedtuple('Expectation', ['expected', 'mask'])
+ return Expectation(self.DownloadImage(GetExpectationPath(expectation,
+ 'expected.png')),
+ self.DownloadImage(GetExpectationPath(expectation,
+ 'mask.png')))
- def TestExists(self, test_run, test_name):
- """Returns whether the given test exists in GS.
+ def ExpectationExists(self, expectation):
+ """Returns whether the given expectation exists in GS.
Args:
- test_run: the name of the test_run.
- test_name: the name of the test to look for.
+ expectation: the name of the expectation to check.
Returns:
A boolean indicating whether the test exists.
"""
expected_image_exists = self.cloud_bucket.FileExists(
- GetTestPath(test_run, test_name, 'expected.png'))
+ GetExpectationPath(expectation, 'expected.png'))
mask_image_exists = self.cloud_bucket.FileExists(
- GetTestPath(test_run, test_name, 'mask.png'))
+ GetExpectationPath(expectation, 'mask.png'))
return expected_image_exists and mask_image_exists
- def FailureExists(self, test_run, test_name):
- """Returns whether the given run exists in GS.
+ def FailureExists(self, test_run, expectation):
+ """Returns whether a failure for the expectation exists for the given run.
Args:
test_run: the name of the test_run.
- test_name: the name of the test that failed.
+ expectation: the name of the expectation that failed.
Returns:
A boolean indicating whether the failure exists.
"""
actual_image_exists = self.cloud_bucket.FileExists(
- GetFailurePath(test_run, test_name, 'actual.png'))
- test_exists = self.TestExists(test_run, test_name)
+ GetFailurePath(test_run, expectation, 'actual.png'))
+ test_exists = self.ExpectationExists(expectation)
info_exists = self.cloud_bucket.FileExists(
- GetFailurePath(test_run, test_name, 'info.txt'))
+ GetFailurePath(test_run, expectation, 'info.txt'))
return test_exists and actual_image_exists and info_exists
- def RemoveTest(self, test_run, test_name):
- """Removes a Test from GS, and all associated failures with that test.
+ def RemoveExpectation(self, expectation):
+ """Removes an expectation and all associated failures with that test.
Args:
- test_run: the name of the test_run.
- test_name: the name of the test to remove.
+ expectation: the name of the expectation to remove.
"""
test_paths = self.cloud_bucket.GetAllPaths(
- GetTestPath(test_run, test_name))
- failure_paths = self.cloud_bucket.GetAllPaths(
- GetFailurePath(test_run, test_name))
- for path in itertools.chain(failure_paths, test_paths):
+ GetExpectationPath(expectation))
+ for path in test_paths:
self.cloud_bucket.RemoveFile(path)
- def UploadTestPinkOut(self, test_run, test_name, images, pint_out, rgb):
+ def UploadExpectationPinkOut(self, expectation, images, pint_out, rgb):
"""Uploads an ispy-test to GS with the pink_out workaround.
Args:
- test_name: The name of the test to be uploaded.
+ expectation: the name of the expectation to be uploaded.
images: a json encoded list of base64 encoded png images.
pink_out: an image.
RGB: a json list representing the RGB values of a color to mask out.
@@ -214,29 +208,27 @@ class ISpyUtils(object):
mask = image_tools.CreateMask(images)
mask = image_tools.InflateMask(image_tools.CreateMask(images), 7)
combined_mask = image_tools.AddMasks([mask, pink_out])
- self.UploadImage(GetTestPath(test_run, test_name, 'expected.png'),
- images[0])
- self.UploadImage(GetTestPath(test_run, test_name, 'mask.png'),
- combined_mask)
+ self.UploadImage(GetExpectationPath(expectation, 'expected.png'), images[0])
+ self.UploadImage(GetExpectationPath(expectation, 'mask.png'), combined_mask)
- def RemoveFailure(self, test_run, test_name):
+ def RemoveFailure(self, test_run, expectation):
"""Removes a failure from GS.
Args:
test_run: the name of the test_run.
- test_name: the test on which the failure to be removed occured.
+ expectation: the expectation on which the failure to be removed occured.
"""
failure_paths = self.cloud_bucket.GetAllPaths(
- GetFailurePath(test_run, test_name))
+ GetFailurePath(test_run, expectation))
for path in failure_paths:
self.cloud_bucket.RemoveFile(path)
- def GetFailure(self, test_run, test_name):
+ def GetFailure(self, test_run, expectation):
"""Returns a given test failure's expected, diff, and actual images.
Args:
test_run: the name of the test_run.
- test_name: the name of the test the result corresponds to.
+ expectation: the name of the expectation the result corresponds to.
Returns:
A named tuple: Failure containing three images: expected, diff, and
@@ -245,16 +237,14 @@ class ISpyUtils(object):
Raises:
cloud_bucket.NotFoundError: if the result is not found in GS.
"""
- test_path = GetTestPath(test_run, test_name)
- failure_path = GetFailurePath(test_run, test_name)
expected = self.DownloadImage(
- GetTestPath(test_run, test_name, 'expected.png'))
+ GetExpectationPath(expectation, 'expected.png'))
actual = self.DownloadImage(
- GetFailurePath(test_run, test_name, 'actual.png'))
+ GetFailurePath(test_run, expectation, 'actual.png'))
diff = self.DownloadImage(
- GetFailurePath(test_run, test_name, 'diff.png'))
+ GetFailurePath(test_run, expectation, 'diff.png'))
info = json.loads(self.cloud_bucket.DownloadFile(
- GetFailurePath(test_run, test_name, 'info.txt')))
+ GetFailurePath(test_run, expectation, 'info.txt')))
Failure = collections.namedtuple(
'Failure', ['expected', 'diff', 'actual', 'info'])
return Failure(expected, diff, actual, info)
diff --git a/chrome/test/functional/ispy/common/ispy_utils_unittest.py b/chrome/test/functional/ispy/common/ispy_utils_unittest.py
index 14dbb7d4b0..5e66a418a0 100644
--- a/chrome/test/functional/ispy/common/ispy_utils_unittest.py
+++ b/chrome/test/functional/ispy/common/ispy_utils_unittest.py
@@ -4,7 +4,6 @@
import os
from PIL import Image
-import sets
import sys
import unittest
@@ -75,41 +74,44 @@ class ISpyUtilsUnitTest(unittest.TestCase):
self.assertEquals(self.bucket.datastore['path/to/image.png'],
image_tools.EncodePNG(self.black))
- def testUploadTest(self):
+ def testUploadExpectation(self):
self.bucket.Reset()
# Upload some tests to the datastore.
- self.ispy_utils.UploadTest('test', 'test1', [self.white, self.black])
- self.ispy_utils.UploadTest('test', 'test2', [self.black, self.black])
+ self.ispy_utils.UploadExpectation('test', [self.white, self.black])
+ self.ispy_utils.UploadExpectation('test1', [self.black, self.black])
# Confirm that the tests were successfully uploaded.
- self.assertEquals(self.bucket.datastore['tests/test/test1/expected.png'],
- image_tools.EncodePNG(self.white))
- self.assertEquals(self.bucket.datastore['tests/test/test1/mask.png'],
- image_tools.EncodePNG(self.white))
- self.assertEquals(self.bucket.datastore['tests/test/test2/expected.png'],
- image_tools.EncodePNG(self.black))
- self.assertEquals(self.bucket.datastore['tests/test/test2/mask.png'],
- image_tools.EncodePNG(self.black))
+ self.assertEquals(self.bucket.datastore[
+ ispy_utils.GetExpectationPath('test', 'expected.png')],
+ image_tools.EncodePNG(self.white))
+ self.assertEquals(self.bucket.datastore[
+ ispy_utils.GetExpectationPath('test', 'mask.png')],
+ image_tools.EncodePNG(self.white))
+ self.assertEquals(self.bucket.datastore[
+ ispy_utils.GetExpectationPath('test1', 'expected.png')],
+ image_tools.EncodePNG(self.black))
+ self.assertEquals(self.bucket.datastore[
+ ispy_utils.GetExpectationPath('test1', 'mask.png')],
+ image_tools.EncodePNG(self.black))
def testRunTest(self):
self.bucket.Reset()
-
- self.ispy_utils.UploadTest('test', 'test1', [self.red, self.red])
+ self.ispy_utils.UploadExpectation('test1', [self.red, self.red])
self.ispy_utils.RunTest('test', 'test1', self.black)
- self.assertEquals(
- self.bucket.datastore['failures/test/test1/actual.png'],
+ self.assertEquals(self.bucket.datastore[
+ ispy_utils.GetFailurePath('test', 'test1', 'actual.png')],
image_tools.EncodePNG(self.black))
self.ispy_utils.RunTest('test', 'test1', self.red)
- self.assertTrue(
- self.bucket.datastore.has_key('failures/test/test1/actual.png'))
+ self.assertTrue(self.bucket.datastore.has_key(
+ ispy_utils.GetFailurePath('test', 'test1', 'actual.png')))
- def testGetTest(self):
+ def testGetExpectation(self):
self.bucket.Reset()
# Upload some tests to the datastore
- self.ispy_utils.UploadTest('test', 'test1', [self.white, self.black])
- self.ispy_utils.UploadTest('test', 'test2', [self.red, self.white])
- test1 = self.ispy_utils.GetTest('test', 'test1')
- test2 = self.ispy_utils.GetTest('test', 'test2')
- # Check that GetTest gets the appropriate tests.
+ self.ispy_utils.UploadExpectation('test1', [self.white, self.black])
+ self.ispy_utils.UploadExpectation('test2', [self.red, self.white])
+ test1 = self.ispy_utils.GetExpectation('test1')
+ test2 = self.ispy_utils.GetExpectation('test2')
+ # Check that GetExpectation gets the appropriate tests.
self.assertEquals(image_tools.EncodePNG(test1.expected),
image_tools.EncodePNG(self.white))
self.assertEquals(image_tools.EncodePNG(test1.mask),
@@ -118,55 +120,54 @@ class ISpyUtilsUnitTest(unittest.TestCase):
image_tools.EncodePNG(self.red))
self.assertEquals(image_tools.EncodePNG(test2.mask),
image_tools.EncodePNG(self.white))
- # Check that GetTest throws an error for a nonexistant test.
+ # Check that GetExpectation throws an error for a nonexistant test.
self.assertRaises(
- cloud_bucket.FileNotFoundError, self.ispy_utils.GetTest, 'test',
- 'test3')
+ cloud_bucket.FileNotFoundError, self.ispy_utils.GetExpectation, 'test3')
- def testTestExists(self):
+ def testExpectationExists(self):
self.bucket.Reset()
- self.ispy_utils.UploadTest('test', 'test1', [self.white, self.black])
- self.ispy_utils.UploadTest('test', 'test2', [self.white, self.black])
- self.assertTrue(self.ispy_utils.TestExists('test', 'test1'))
- self.assertTrue(self.ispy_utils.TestExists('test', 'test2'))
- self.assertFalse(self.ispy_utils.TestExists('test', 'test3'))
+ self.ispy_utils.UploadExpectation('test1', [self.white, self.black])
+ self.ispy_utils.UploadExpectation('test2', [self.white, self.black])
+ self.assertTrue(self.ispy_utils.ExpectationExists('test1'))
+ self.assertTrue(self.ispy_utils.ExpectationExists('test2'))
+ self.assertFalse(self.ispy_utils.ExpectationExists('test3'))
def testFailureExists(self):
self.bucket.Reset()
- self.ispy_utils.UploadTest('test', 'test1', [self.white, self.white])
+ self.ispy_utils.UploadExpectation('test1', [self.white, self.white])
self.ispy_utils.RunTest('test', 'test1', self.black)
self.ispy_utils.RunTest('test', 'test1', self.white)
self.assertTrue(self.ispy_utils.FailureExists('test', 'test1'))
self.assertFalse(self.ispy_utils.FailureExists('test', 'test2'))
- def testRemoveTest(self):
+ def testRemoveExpectation(self):
self.bucket.Reset()
- self.ispy_utils.UploadTest('test', 'test1', [self.white, self.white])
- self.ispy_utils.UploadTest('test', 'test2', [self.white, self.white])
- self.assertTrue(self.ispy_utils.TestExists('test', 'test1'))
- self.assertTrue(self.ispy_utils.TestExists('test', 'test2'))
- self.ispy_utils.RemoveTest('test', 'test1')
- self.assertFalse(self.ispy_utils.TestExists('test', 'test1'))
- self.assertTrue(self.ispy_utils.TestExists('test', 'test2'))
- self.ispy_utils.RemoveTest('test', 'test2')
- self.assertFalse(self.ispy_utils.TestExists('test', 'test1'))
- self.assertFalse(self.ispy_utils.TestExists('test', 'test2'))
+ self.ispy_utils.UploadExpectation('test1', [self.white, self.white])
+ self.ispy_utils.UploadExpectation('test2', [self.white, self.white])
+ self.assertTrue(self.ispy_utils.ExpectationExists('test1'))
+ self.assertTrue(self.ispy_utils.ExpectationExists('test2'))
+ self.ispy_utils.RemoveExpectation('test1')
+ self.assertFalse(self.ispy_utils.ExpectationExists('test1'))
+ self.assertTrue(self.ispy_utils.ExpectationExists('test2'))
+ self.ispy_utils.RemoveExpectation('test2')
+ self.assertFalse(self.ispy_utils.ExpectationExists('test1'))
+ self.assertFalse(self.ispy_utils.ExpectationExists('test2'))
def testRemoveFailure(self):
self.bucket.Reset()
- self.ispy_utils.UploadTest('test', 'test1', [self.white, self.white])
- self.ispy_utils.UploadTest('test', 'test2', [self.white, self.white])
+ self.ispy_utils.UploadExpectation('test1', [self.white, self.white])
+ self.ispy_utils.UploadExpectation('test2', [self.white, self.white])
self.ispy_utils.RunTest('test', 'test1', self.black)
self.ispy_utils.RemoveFailure('test', 'test1')
self.assertFalse(self.ispy_utils.FailureExists('test', 'test1'))
- self.assertTrue(self.ispy_utils.TestExists('test', 'test1'))
+ self.assertTrue(self.ispy_utils.ExpectationExists('test1'))
self.assertFalse(self.ispy_utils.FailureExists('test', 'test2'))
- self.assertTrue(self.ispy_utils.TestExists('test', 'test2'))
+ self.assertTrue(self.ispy_utils.ExpectationExists('test2'))
def testGetFailure(self):
self.bucket.Reset()
# Upload a result
- self.ispy_utils.UploadTest('test', 'test1', [self.red, self.red])
+ self.ispy_utils.UploadExpectation('test1', [self.red, self.red])
self.ispy_utils.RunTest('test', 'test1', self.black)
res = self.ispy_utils.GetFailure('test', 'test1')
# Check that the function correctly got the result.
@@ -183,22 +184,16 @@ class ISpyUtilsUnitTest(unittest.TestCase):
def testGetAllPaths(self):
self.bucket.Reset()
# Upload some tests.
- self.ispy_utils.UploadTest('test', 'test1', [self.white, self.black])
- self.ispy_utils.UploadTest('test', 'test2', [self.red, self.white])
+ self.ispy_utils.UploadExpectation('test1', [self.white, self.black])
# Check that the function gets all urls matching the prefix.
self.assertEquals(
- sets.Set(self.ispy_utils.GetAllPaths('tests/test/test')),
- sets.Set(['tests/test/test1/expected.png',
- 'tests/test/test1/mask.png',
- 'tests/test/test2/expected.png',
- 'tests/test/test2/mask.png']))
- self.assertEquals(
- sets.Set(self.ispy_utils.GetAllPaths('tests/test/test1')),
- sets.Set(['tests/test/test1/expected.png',
- 'tests/test/test1/mask.png']))
+ set(self.ispy_utils.GetAllPaths(
+ ispy_utils.GetExpectationPath('test1'))),
+ set([ispy_utils.GetExpectationPath('test1', 'expected.png'),
+ ispy_utils.GetExpectationPath('test1', 'mask.png')]))
self.assertEquals(
- sets.Set(self.ispy_utils.GetAllPaths('tests/test/test3')),
- sets.Set())
+ set(self.ispy_utils.GetAllPaths(
+ ispy_utils.GetExpectationPath('test3'))), set())
if __name__ == '__main__':
diff --git a/chrome/test/functional/ispy/server/debug_view_handler.py b/chrome/test/functional/ispy/server/debug_view_handler.py
index 6d74e78776..96bfe3cff1 100644
--- a/chrome/test/functional/ispy/server/debug_view_handler.py
+++ b/chrome/test/functional/ispy/server/debug_view_handler.py
@@ -26,12 +26,12 @@ class DebugViewHandler(webapp2.RequestHandler):
GET Parameters:
test_run: The test run.
- test_name: The test name.
+ expectation: The expectation name.
"""
test_run = self.request.get('test_run')
- test_name = self.request.get('test_name')
- expected_path = ispy_utils.GetTestPath(test_run, test_name, 'expected.png')
- actual_path = ispy_utils.GetFailurePath(test_run, test_name, 'actual.png')
+ expectation = self.request.get('expectation')
+ expected_path = ispy_utils.GetExpectationPath(expectation, 'expected.png')
+ actual_path = ispy_utils.GetFailurePath(test_run, expectation, 'actual.png')
data = {}
def _ImagePath(url):
@@ -40,6 +40,6 @@ class DebugViewHandler(webapp2.RequestHandler):
data['expected'] = _ImagePath(expected_path)
data['actual'] = _ImagePath(actual_path)
data['test_run'] = test_run
- data['test_name'] = test_name
+ data['expectation'] = expectation
template = JINJA.get_template('debug_view.html')
self.response.write(template.render(data))
diff --git a/chrome/test/functional/ispy/server/main_view_handler.py b/chrome/test/functional/ispy/server/main_view_handler.py
index 8254033754..4b3ec103f8 100644
--- a/chrome/test/functional/ispy/server/main_view_handler.py
+++ b/chrome/test/functional/ispy/server/main_view_handler.py
@@ -49,8 +49,8 @@ class MainViewHandler(webapp2.RequestHandler):
"""
template = JINJA.get_template('list_view.html')
data = {}
- test_runs = set([re.match(r'^tests/([^/]+)/.+$', path).groups()[0]
- for path in ispy.GetAllPaths('tests/')])
+ test_runs = set([path.lstrip('/').split('/')[1] for path in
+ ispy.GetAllPaths('failures/')])
base_url = '/?test_run=%s'
data['links'] = [(test_run, base_url % test_run) for test_run in test_runs]
self.response.write(template.render(data))
@@ -67,13 +67,12 @@ class MainViewHandler(webapp2.RequestHandler):
"""
paths = set([path for path in ispy.GetAllPaths('failures/' + test_run)
if path.endswith('actual.png')])
- rows = [self._CreateRow(test_run, path, ispy)
- for path in paths]
+ rows = [self._CreateRow(test_run, path, ispy) for path in paths]
if rows:
# Function that sorts by the different_pixels field in the failure-info.
- def _Sorter(x, y):
- return cmp(y['info']['fraction_different'],
- x['info']['fraction_different'])
+ def _Sorter(a, b):
+ return cmp(b['percent_different'],
+ a['percent_different'])
template = JINJA.get_template('main_view.html')
self.response.write(
template.render({'comparisons': sorted(rows, _Sorter),
@@ -98,16 +97,15 @@ class MainViewHandler(webapp2.RequestHandler):
in the main_view html template.
"""
res = {}
- pattern = r'^failures/%s/([^/]+)/.+$' % test_run
- res['test_name'] = re.match(
- pattern, path).groups()[0]
+ res['expectation'] = path.lstrip('/').split('/')[2]
res['test_run'] = test_run
res['info'] = json.loads(ispy.cloud_bucket.DownloadFile(
- ispy_utils.GetFailurePath(res['test_run'], res['test_name'],
+ ispy_utils.GetFailurePath(res['test_run'], res['expectation'],
'info.txt')))
- expected = ispy_utils.GetTestPath(test_run, res['test_name'],
- 'expected.png')
- diff = ispy_utils.GetFailurePath(test_run, res['test_name'], 'diff.png')
+ expected = ispy_utils.GetExpectationPath(
+ res['expectation'], 'expected.png')
+ diff = ispy_utils.GetFailurePath(test_run, res['expectation'], 'diff.png')
+ res['percent_different'] = res['info']['fraction_different'] * 100
res['expected_path'] = expected
res['diff_path'] = diff
res['actual_path'] = path
diff --git a/chrome/test/functional/ispy/server/update_mask_handler.py b/chrome/test/functional/ispy/server/update_mask_handler.py
index 3c0fb6a80d..4a2a2dabb7 100644
--- a/chrome/test/functional/ispy/server/update_mask_handler.py
+++ b/chrome/test/functional/ispy/server/update_mask_handler.py
@@ -29,31 +29,31 @@ class UpdateMaskHandler(webapp2.RequestHandler):
to the device list view.
"""
test_run = self.request.get('test_run')
- test_name = self.request.get('test_name')
+ expectation = self.request.get('expectation')
# Short-circuit if a parameter is missing.
- if not (test_run and test_name):
+ if not (test_run and expectation):
self.response.header['Content-Type'] = 'json/application'
self.response.write(json.dumps(
- {'error': 'test_run, and test_name, must be '
+ {'error': '\'test_run\' and \'expectation\' must be '
'supplied to update a mask.'}))
return
# Otherwise, set up the utilities.
self.bucket = gs_bucket.GoogleCloudStorageBucket(constants.BUCKET)
self.ispy = ispy_utils.ISpyUtils(self.bucket)
# Short-circuit if the failure does not exist.
- if not self.ispy.FailureExists(test_run, test_name):
+ if not self.ispy.FailureExists(test_run, expectation):
self.response.header['Content-Type'] = 'json/application'
self.response.write(json.dumps(
{'error': 'Could not update mask because failure does not exist.'}))
return
# Get the failure namedtuple (which also computes the diff).
- failure = self.ispy.GetFailure(test_run, test_name)
+ failure = self.ispy.GetFailure(test_run, expectation)
# Upload the new mask in place of the original.
self.ispy.UpdateImage(
- ispy_utils.GetTestPath(test_run, test_name, 'mask.png'),
+ ispy_utils.GetExpectationPath(expectation, 'mask.png'),
image_tools.ConvertDiffToMask(failure.diff))
- # Now that there is no div for the two images, remove the failure.
- self.ispy.RemoveFailure(test_run, test_name)
- # Redirect back to the sites list for the device.
+ # Now that there is no diff for the two images, remove the failure.
+ self.ispy.RemoveFailure(test_run, expectation)
+ # Redirect back to the sites list for the test run.
self.redirect('/?test_run=%s' % test_run)
diff --git a/chrome/test/functional/ispy/server/views/debug_view.html b/chrome/test/functional/ispy/server/views/debug_view.html
index f0a67ac01f..8371280d7b 100644
--- a/chrome/test/functional/ispy/server/views/debug_view.html
+++ b/chrome/test/functional/ispy/server/views/debug_view.html
@@ -1,6 +1,6 @@
<html>
<head>
- <title>Debug {{ test_name }}</title>
+ <title>Debug {{ expectation }}</title>
<script language="javascript">
var current = 0;
var toggle_interval = null;
@@ -38,7 +38,7 @@
<br>
<form action="/update_mask" method="post" onsubmit="return confirmSubmit();">
<input type="hidden" name="test_run" value="{{ test_run }}"/>
- <input type="hidden" name="test_name" value="{{ test_name }}"/>
+ <input type="hidden" name="expectation" value="{{ expectation }}"/>
<input type="submit" value="Ignore similar diffs in the future"/>
</form>
<br>
diff --git a/chrome/test/functional/ispy/server/views/diff_view.html b/chrome/test/functional/ispy/server/views/diff_view.html
deleted file mode 100644
index 6cf10835da..0000000000
--- a/chrome/test/functional/ispy/server/views/diff_view.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<!DOCTYPE html>
-{% autoescape true %}
-<html>
- <head>
- <style>
- #container {
- display: table;
- background-color:#A8A8A8;
- border:2px solid black;
- }
- #row {
- display: table-row;
- }
- #left, #right, #middle {
- display: table-cell;
- padding-right: 25px;
- padding-left: 25px;
- }
- #left p, #right p, #middle p {
- margin: 1px 1px;
- }
- #title {
- display: block;
- text-align: center;
- }
- #info-box {
- background-color:#A8A8A8;
- border:2px solid black;
- display: block;
- width: 400px;
- }
- .image {
- width: 300px;
- }
- </style>
- </head>
- <body>
- <span id="info-box"> Device: {{ device }}<br>
- Site: {{ site }}<br>
- Device_ID: {{ device_id }}</span>
- <form action="/update_mask?{{ encoded_parameters }}" method="post">
- <input type="submit" value="Ignore Diff"/>
- </form>
- <div id="container">
- <div id="row">
- <div id="left">
- <span id="title">Expected</span><br>
- <img class="image" src="{{ expected }}">
- </div>
- <div id="center">
- <span id="title">Diff</span><br>
- <img class="image" src="{{ diff }}">
- </div>
- <div id="right">
- <span id="title">Actual</span><br>
- <img class="image" src="{{ actual }}">
- </div>
- </div>
- </div>
- </body>
-</html>
-{% endautoescape %}
diff --git a/chrome/test/functional/ispy/server/views/main_view.html b/chrome/test/functional/ispy/server/views/main_view.html
index 4cfee440d2..4bc95ad7a8 100644
--- a/chrome/test/functional/ispy/server/views/main_view.html
+++ b/chrome/test/functional/ispy/server/views/main_view.html
@@ -29,7 +29,7 @@
{% for comp in comparisons %}
<div class="row">
<div class="cell">
- Diff<br>
+ Diff&nbsp;&nbsp;({{ "%.1f"|format(comp['percent_different']) }}%)<br>
<a class="imagelink" href="{{ comp['diff'] }}">
<img class="image" src={{ comp['diff'] }}>
</a>
@@ -49,8 +49,8 @@
<div class="cell">
<br>
<div class="info">
- {{ comp['test_name'] }}<br>
- <a href='/debug_view?test_run={{ comp['test_run'] }}&test_name={{ comp['test_name'] }}'>Debug View</a>
+ {{ comp['expectation'] }}<br>
+ <a href='/debug_view?test_run={{ comp['test_run'] }}&expectation={{ comp['expectation'] }}'>Debug View</a>
</div>
</div>
</div>
diff --git a/chrome/test/gpu/gpu_feature_browsertest.cc b/chrome/test/gpu/gpu_feature_browsertest.cc
index e3eecb5eb5..2192831a7c 100644
--- a/chrome/test/gpu/gpu_feature_browsertest.cc
+++ b/chrome/test/gpu/gpu_feature_browsertest.cc
@@ -369,8 +369,7 @@ IN_PROC_BROWSER_TEST_F(GpuFeatureTest, Canvas2DAllowed) {
} expected_state = ENABLED;
#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
// Blacklist rule #24 disables accelerated_2d_canvas on Linux.
- // TODO(gab): Enable GPU control lists on Linux.
- // expected_state = BLACKLISTED;
+ expected_state = BLACKLISTED;
#elif defined(OS_WIN)
// Blacklist rule #67 disables accelerated_2d_canvas on XP.
if (base::win::GetVersion() < base::win::VERSION_VISTA)
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index 921436804a..66524df496 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -315,7 +315,13 @@ TEST_PPAPI_OUT_OF_PROCESS(ImageData)
TEST_PPAPI_NACL(ImageData)
TEST_PPAPI_IN_PROCESS(BrowserFont)
-TEST_PPAPI_OUT_OF_PROCESS(BrowserFont)
+// crbug.com/308949
+#if defined(OS_WIN)
+#define MAYBE_OUT_BrowserFont DISABLED_BrowserFont
+#else
+#define MAYBE_OUT_BrowserFont BrowserFont
+#endif
+TEST_PPAPI_OUT_OF_PROCESS(MAYBE_OUT_BrowserFont)
TEST_PPAPI_IN_PROCESS(Buffer)
TEST_PPAPI_OUT_OF_PROCESS(Buffer)
@@ -561,7 +567,8 @@ IN_PROC_BROWSER_TEST_F(PPAPINaClNewlibTest, URLLoader) {
LIST_TEST(URLLoader_PrefetchBufferThreshold)
);
}
-IN_PROC_BROWSER_TEST_F(PPAPINaClGLibcTest, MAYBE_GLIBC(URLLoader)) {
+// http://crbug.com/308906
+IN_PROC_BROWSER_TEST_F(PPAPINaClGLibcTest, DISABLED_URLLoader) {
RunTestViaHTTP(
LIST_TEST(URLLoader_BasicGET)
LIST_TEST(URLLoader_BasicPOST)
@@ -676,6 +683,10 @@ TEST_PPAPI_IN_PROCESS(Var)
TEST_PPAPI_OUT_OF_PROCESS(Var)
TEST_PPAPI_NACL(Var)
+TEST_PPAPI_IN_PROCESS(VarResource)
+TEST_PPAPI_OUT_OF_PROCESS(VarResource)
+TEST_PPAPI_NACL(VarResource)
+
// Flaky on mac, http://crbug.com/121107
#if defined(OS_MACOSX)
#define MAYBE_VarDeprecated DISABLED_VarDeprecated
@@ -822,7 +833,8 @@ IN_PROC_BROWSER_TEST_F(PPAPINaClNewlibTest, FileIO) {
LIST_TEST(FileIO_Mmap)
);
}
-IN_PROC_BROWSER_TEST_F(PPAPINaClGLibcTest, MAYBE_GLIBC(FileIO)) {
+// http://crbug.com/308905
+IN_PROC_BROWSER_TEST_F(PPAPINaClGLibcTest, DISABLED_FileIO) {
RunTestViaHTTP(
LIST_TEST(FileIO_Open)
LIST_TEST(FileIO_AbortCalls)
@@ -903,7 +915,8 @@ IN_PROC_BROWSER_TEST_F(PPAPINaClNewlibTest, FileRef) {
LIST_TEST(DISABLED_FileRef_ReadDirectoryEntries)
);
}
-IN_PROC_BROWSER_TEST_F(PPAPINaClGLibcTest, MAYBE_GLIBC(FileRef)) {
+// http://crbug.com/308908
+IN_PROC_BROWSER_TEST_F(PPAPINaClGLibcTest, DISABLED_FileRef) {
RunTestViaHTTP(
LIST_TEST(FileRef_Create)
LIST_TEST(FileRef_GetFileSystemType)
diff --git a/chrome/test/remoting/page_load_notification_observer.cc b/chrome/test/remoting/page_load_notification_observer.cc
new file mode 100644
index 0000000000..4898680bc8
--- /dev/null
+++ b/chrome/test/remoting/page_load_notification_observer.cc
@@ -0,0 +1,29 @@
+// Copyright 2013 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/remoting/page_load_notification_observer.h"
+
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/web_contents.h"
+
+namespace remoting {
+
+PageLoadNotificationObserver::PageLoadNotificationObserver(const GURL& target)
+ : WindowedNotificationObserver(
+ content::NOTIFICATION_LOAD_STOP,
+ base::Bind(&PageLoadNotificationObserver::IsTargetLoaded,
+ base::Unretained(this))),
+ target_(target) {
+}
+
+PageLoadNotificationObserver::~PageLoadNotificationObserver() {}
+
+bool PageLoadNotificationObserver::IsTargetLoaded() {
+ content::NavigationController* controller =
+ content::Source<content::NavigationController>(source()).ptr();
+ return controller->GetWebContents()->GetURL() == target_;
+}
+
+} // namespace remoting
diff --git a/chrome/test/remoting/page_load_notification_observer.h b/chrome/test/remoting/page_load_notification_observer.h
new file mode 100644
index 0000000000..42e3a6cbdd
--- /dev/null
+++ b/chrome/test/remoting/page_load_notification_observer.h
@@ -0,0 +1,34 @@
+// Copyright 2013 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_REMOTING_PAGE_LOAD_NOTIFICATION_OBSERVER_H_
+#define CHROME_TEST_REMOTING_PAGE_LOAD_NOTIFICATION_OBSERVER_H_
+
+#include "content/public/test/test_utils.h"
+#include "url/gurl.h"
+
+namespace remoting {
+
+// A PageLoadNotificationObserver allows code to wait until a give URL is loaded
+// in any tab in any browser window, i.e. NotificationService::AllSources().
+// This simple pattern is not easy to implement using
+// WindowedNotificationObserver because we need to bind the observer object
+// in the callback but we also need to provide the callback when constructing
+// the observer object.
+class PageLoadNotificationObserver
+ : public content::WindowedNotificationObserver {
+ public:
+ explicit PageLoadNotificationObserver(const GURL& target);
+
+ virtual ~PageLoadNotificationObserver();
+
+ private:
+ bool IsTargetLoaded();
+ GURL target_;
+ DISALLOW_COPY_AND_ASSIGN(PageLoadNotificationObserver);
+};
+
+} // namespace remoting
+
+#endif // CHROME_TEST_REMOTING_PAGE_LOAD_NOTIFICATION_OBSERVER_H_
diff --git a/chrome/test/remoting/remote_desktop_browsertest.cc b/chrome/test/remoting/remote_desktop_browsertest.cc
index f56bacc0ad..156d532f2a 100644
--- a/chrome/test/remoting/remote_desktop_browsertest.cc
+++ b/chrome/test/remoting/remote_desktop_browsertest.cc
@@ -6,35 +6,41 @@
#include "base/command_line.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/unpacked_installer.h"
+#include "chrome/browser/ui/extensions/application_launch.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/test/remoting/key_code_conv.h"
+#include "chrome/test/remoting/page_load_notification_observer.h"
#include "chrome/test/remoting/waiter.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/test/test_utils.h"
-
-using extensions::Extension;
+#include "ui/base/window_open_disposition.h"
namespace remoting {
-RemoteDesktopBrowserTest::RemoteDesktopBrowserTest() {}
+RemoteDesktopBrowserTest::RemoteDesktopBrowserTest()
+ : extension_(NULL) {
+}
RemoteDesktopBrowserTest::~RemoteDesktopBrowserTest() {}
void RemoteDesktopBrowserTest::SetUp() {
ParseCommandLine();
- ExtensionBrowserTest::SetUp();
+ PlatformAppBrowserTest::SetUp();
}
void RemoteDesktopBrowserTest::SetUpOnMainThread() {
- ExtensionBrowserTest::SetUpOnMainThread();
+ PlatformAppBrowserTest::SetUpOnMainThread();
- // Initializing to browser() before RunTestOnMainThread() and after
- // |InProcessBrowserTest::browser_| is initialized in
- // InProcessBrowserTest::RunTestOnMainThreadLoop()
- active_browser_ = browser();
+ // Pushing the initial WebContents instance onto the stack before
+ // RunTestOnMainThread() and after |InProcessBrowserTest::browser_|
+ // is initialized in InProcessBrowserTest::RunTestOnMainThreadLoop()
+ web_contents_stack_.push_back(
+ browser()->tab_strip_model()->GetActiveWebContents());
}
// Change behavior of the default host resolver to avoid DNS lookup errors,
@@ -50,8 +56,8 @@ void RemoteDesktopBrowserTest::TearDownInProcessBrowserTestFixture() {
}
void RemoteDesktopBrowserTest::VerifyInternetAccess() {
- GURL google_url("http://www.google.com");
- NavigateToURLAndWaitForPageLoad(google_url);
+ ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
+ browser(), GURL("http://www.google.com"), 1);
EXPECT_EQ(GetCurrentURL().host(), "www.google.com");
}
@@ -76,17 +82,37 @@ bool RemoteDesktopBrowserTest::HtmlElementVisible(const std::string& name) {
"isElementVisible(\"" + name + "\")");
}
-void RemoteDesktopBrowserTest::InstallChromotingApp() {
+void RemoteDesktopBrowserTest::InstallChromotingAppCrx() {
+ ASSERT_TRUE(!is_unpacked());
+
base::FilePath install_dir(WebAppCrxPath());
scoped_refptr<const Extension> extension(InstallExtensionWithUIAutoConfirm(
- install_dir, 1, active_browser_));
+ install_dir, 1, browser()));
EXPECT_FALSE(extension.get() == NULL);
+
+ extension_ = extension.get();
+}
+
+void RemoteDesktopBrowserTest::InstallChromotingAppUnpacked() {
+ ASSERT_TRUE(is_unpacked());
+
+ scoped_refptr<extensions::UnpackedInstaller> installer =
+ extensions::UnpackedInstaller::Create(extension_service());
+ installer->set_prompt_for_plugins(false);
+
+ content::WindowedNotificationObserver observer(
+ chrome::NOTIFICATION_EXTENSION_LOADED,
+ content::NotificationService::AllSources());
+
+ installer->Load(webapp_unpacked_);
+
+ observer.Wait();
}
void RemoteDesktopBrowserTest::UninstallChromotingApp() {
UninstallExtension(ChromotingID());
- chromoting_id_.clear();
+ extension_ = NULL;
}
void RemoteDesktopBrowserTest::VerifyChromotingLoaded(bool expected) {
@@ -107,10 +133,15 @@ void RemoteDesktopBrowserTest::VerifyChromotingLoaded(bool expected) {
}
if (installed) {
- chromoting_id_ = extension->id();
+ if (extension_)
+ EXPECT_EQ(extension, extension_);
+ else
+ extension_ = extension.get();
- EXPECT_EQ(extension->GetType(),
- extensions::Manifest::TYPE_LEGACY_PACKAGED_APP);
+ // Either a V1 (TYPE_LEGACY_PACKAGED_APP) or a V2 (TYPE_PLATFORM_APP ) app.
+ extensions::Manifest::Type type = extension->GetType();
+ EXPECT_TRUE(type == extensions::Manifest::TYPE_PLATFORM_APP ||
+ type == extensions::Manifest::TYPE_LEGACY_PACKAGED_APP);
EXPECT_TRUE(extension->ShouldDisplayInAppLauncher());
}
@@ -119,36 +150,62 @@ void RemoteDesktopBrowserTest::VerifyChromotingLoaded(bool expected) {
}
void RemoteDesktopBrowserTest::LaunchChromotingApp() {
- ASSERT_FALSE(ChromotingID().empty());
+ ASSERT_TRUE(extension_);
+
+ GURL chromoting_main = Chromoting_Main_URL();
+ // We cannot simply wait for any page load because the first page
+ // loaded could be the generated background page. We need to wait
+ // till the chromoting main page is loaded.
+ PageLoadNotificationObserver observer(chromoting_main);
+
+ OpenApplication(AppLaunchParams(
+ browser()->profile(),
+ extension_,
+ is_platform_app() ? extension_misc::LAUNCH_NONE :
+ extension_misc::LAUNCH_TAB,
+ is_platform_app() ? NEW_WINDOW : CURRENT_TAB));
+
+ observer.Wait();
- const GURL chromoting_main = Chromoting_Main_URL();
- NavigateToURLAndWaitForPageLoad(chromoting_main);
- EXPECT_EQ(GetCurrentURL(), chromoting_main);
+ // The active WebContents instance should be the source of the LOAD_STOP
+ // notification.
+ content::NavigationController* controller =
+ content::Source<content::NavigationController>(observer.source()).ptr();
+
+ content::WebContents* web_contents = controller->GetWebContents();
+ if (web_contents != active_web_contents())
+ web_contents_stack_.push_back(web_contents);
+
+ if (is_platform_app()) {
+ EXPECT_EQ(GetFirstShellWindowWebContents(), active_web_contents());
+ } else {
+ // For apps v1 only, the DOMOperationObserver is not ready at the LOAD_STOP
+ // event. A half second wait is necessary for the subsequent javascript
+ // injection to work.
+ // TODO(weitaosu): Find out whether there is a more appropriate notification
+ // to wait for so we can get rid of this wait.
+ ASSERT_TRUE(TimeoutWaiter(base::TimeDelta::FromMilliseconds(500)).Wait());
+ }
+
+ EXPECT_EQ(Chromoting_Main_URL(), GetCurrentURL());
}
void RemoteDesktopBrowserTest::Authorize() {
// The chromoting extension should be installed.
- ASSERT_FALSE(ChromotingID().empty());
+ ASSERT_TRUE(extension_);
// The chromoting main page should be loaded in the current tab
// and isAuthenticated() should be false (auth dialog visible).
ASSERT_EQ(Chromoting_Main_URL(), GetCurrentURL());
- ASSERT_FALSE(ExecuteScriptAndExtractBool(
- "remoting.oauth2.isAuthenticated()"));
-
- // The first observer monitors the creation of the new window for
- // the Google loging page.
- content::WindowedNotificationObserver observer(
- chrome::NOTIFICATION_BROWSER_OPENED,
- content::NotificationService::AllSources());
+ ASSERT_FALSE(IsAuthenticated());
// The second observer monitors the loading of the Google login page.
// Unfortunately we cannot specify a source in this observer because
// we can't get a handle of the new window until the first observer
// has finished waiting. But we will assert that the source of the
// load stop event is indeed the newly created browser window.
- content::WindowedNotificationObserver observer2(
+ content::WindowedNotificationObserver observer(
content::NOTIFICATION_LOAD_STOP,
content::NotificationService::AllSources());
@@ -156,19 +213,10 @@ void RemoteDesktopBrowserTest::Authorize() {
observer.Wait();
- const content::Source<Browser>* source =
- static_cast<const content::Source<Browser>*>(&observer.source());
- active_browser_ = source->ptr();
-
- observer2.Wait();
-
- const content::Source<content::NavigationController>* source2 =
- static_cast<const content::Source<content::NavigationController>*>(
- &observer2.source());
- content::NavigationController* controller = source2->ptr();
+ content::NavigationController* controller =
+ content::Source<content::NavigationController>(observer.source()).ptr();
- EXPECT_EQ(controller->GetWebContents(),
- active_browser_->tab_strip_model()->GetActiveWebContents());
+ web_contents_stack_.push_back(controller->GetWebContents());
// Verify the active tab is at the "Google Accounts" login page.
EXPECT_EQ("accounts.google.com", GetCurrentURL().host());
@@ -178,7 +226,7 @@ void RemoteDesktopBrowserTest::Authorize() {
void RemoteDesktopBrowserTest::Authenticate() {
// The chromoting extension should be installed.
- ASSERT_FALSE(ChromotingID().empty());
+ ASSERT_TRUE(extension_);
// The active tab should have the "Google Accounts" login page loaded.
ASSERT_EQ("accounts.google.com", GetCurrentURL().host());
@@ -191,59 +239,79 @@ void RemoteDesktopBrowserTest::Authenticate() {
"document.getElementById(\"Passwd\").value = \"" + password_ +"\";" +
"document.forms[\"gaia_loginform\"].submit();");
- EXPECT_EQ(GetCurrentURL().host(), "accounts.google.com");
-
// TODO(weitaosu): Is there a better way to verify we are on the
// "Request for Permission" page?
- EXPECT_TRUE(HtmlElementExists("submit_approve_access"));
+ // V2 app won't ask for approval here because the chromoting test account
+ // has already been granted permissions.
+ if (!is_platform_app()) {
+ EXPECT_EQ(GetCurrentURL().host(), "accounts.google.com");
+ EXPECT_TRUE(HtmlElementExists("submit_approve_access"));
+ }
}
void RemoteDesktopBrowserTest::Approve() {
// The chromoting extension should be installed.
- ASSERT_FALSE(ChromotingID().empty());
-
- // The active tab should have the chromoting app loaded.
- ASSERT_EQ("accounts.google.com", GetCurrentURL().host());
-
- // Is there a better way to verify we are on the "Request for Permission"
- // page?
- ASSERT_TRUE(HtmlElementExists("submit_approve_access"));
-
- const GURL chromoting_main = Chromoting_Main_URL();
-
- // |active_browser_| is still set to the login window but the observer
- // should be set up to observe the chromoting window because that is
- // where we'll receive the message from the login window and reload the
- // chromoting app.
- content::WindowedNotificationObserver observer(
- content::NOTIFICATION_LOAD_STOP,
+ ASSERT_TRUE(extension_);
+
+ if (is_platform_app()) {
+ // Popping the login window off the stack to return to the chromoting
+ // window.
+ web_contents_stack_.pop_back();
+
+ // There is nothing for the V2 app to approve because the chromoting test
+ // account has already been granted permissions.
+ // TODO(weitaosu): Revoke the permission at the beginning of the test so
+ // that we can test first-time experience here.
+ ConditionalTimeoutWaiter waiter(
+ base::TimeDelta::FromSeconds(3),
+ base::TimeDelta::FromSeconds(1),
base::Bind(
- &RemoteDesktopBrowserTest::IsAuthenticated, browser()));
-
- ExecuteScript(
- "lso.approveButtonAction();"
- "document.forms[\"connect-approve\"].submit();");
-
- observer.Wait();
-
- // Resetting |active_browser_| to browser() now that the Google login
- // window is closed and the focus has returned to the chromoting window.
- active_browser_ = browser();
+ &RemoteDesktopBrowserTest::IsAuthenticatedInWindow,
+ active_web_contents()));
+
+ ASSERT_TRUE(waiter.Wait());
+ } else {
+ ASSERT_EQ("accounts.google.com", GetCurrentURL().host());
+
+ // Is there a better way to verify we are on the "Request for Permission"
+ // page?
+ ASSERT_TRUE(HtmlElementExists("submit_approve_access"));
+
+ const GURL chromoting_main = Chromoting_Main_URL();
+
+ // active_web_contents() is still the login window but the observer
+ // should be set up to observe the chromoting window because that is
+ // where we'll receive the message from the login window and reload the
+ // chromoting app.
+ content::WindowedNotificationObserver observer(
+ content::NOTIFICATION_LOAD_STOP,
+ base::Bind(
+ &RemoteDesktopBrowserTest::IsAuthenticatedInWindow,
+ browser()->tab_strip_model()->GetActiveWebContents()));
+
+ ExecuteScript(
+ "lso.approveButtonAction();"
+ "document.forms[\"connect-approve\"].submit();");
+
+ observer.Wait();
+
+ // Popping the login window off the stack to return to the chromoting
+ // window.
+ web_contents_stack_.pop_back();
+ }
- ASSERT_TRUE(GetCurrentURL() == chromoting_main);
+ ASSERT_TRUE(GetCurrentURL() == Chromoting_Main_URL());
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- "remoting.oauth2.isAuthenticated()"));
+ EXPECT_TRUE(IsAuthenticated());
}
void RemoteDesktopBrowserTest::StartMe2Me() {
// The chromoting extension should be installed.
- ASSERT_FALSE(ChromotingID().empty());
+ ASSERT_TRUE(extension_);
// The active tab should have the chromoting app loaded.
ASSERT_EQ(Chromoting_Main_URL(), GetCurrentURL());
- EXPECT_TRUE(ExecuteScriptAndExtractBool(
- "remoting.oauth2.isAuthenticated()"));
+ EXPECT_TRUE(IsAuthenticated());
// The Me2Me host list should be hidden.
ASSERT_FALSE(HtmlElementVisible("me2me-content"));
@@ -272,7 +340,7 @@ void RemoteDesktopBrowserTest::StartMe2Me() {
void RemoteDesktopBrowserTest::DisconnectMe2Me() {
// The chromoting extension should be installed.
- ASSERT_FALSE(ChromotingID().empty());
+ ASSERT_TRUE(extension_);
// The active tab should have the chromoting app loaded.
ASSERT_EQ(Chromoting_Main_URL(), GetCurrentURL());
@@ -307,7 +375,7 @@ void RemoteDesktopBrowserTest::SimulateKeyPressWithCode(
bool alt,
bool command) {
content::SimulateKeyPressWithCode(
- active_browser_->tab_strip_model()->GetActiveWebContents(),
+ active_web_contents(),
keyCode,
code,
control,
@@ -336,6 +404,8 @@ void RemoteDesktopBrowserTest::SimulateMouseLeftClickAt(int x, int y) {
void RemoteDesktopBrowserTest::SimulateMouseClickAt(
int modifiers, WebKit::WebMouseEvent::Button button, int x, int y) {
+ // TODO(weitaosu): The coordinate translation doesn't work correctly for
+ // apps v2.
ExecuteScript(
"var clientPluginElement = "
"document.getElementById('session-client-plugin');"
@@ -359,10 +429,12 @@ void RemoteDesktopBrowserTest::SimulateMouseClickAt(
}
void RemoteDesktopBrowserTest::Install() {
- // TODO(weitaosu): add support for unpacked extension (the v2 app needs it).
if (!NoInstall()) {
VerifyChromotingLoaded(false);
- InstallChromotingApp();
+ if (is_unpacked())
+ InstallChromotingAppUnpacked();
+ else
+ InstallChromotingAppCrx();
}
VerifyChromotingLoaded(true);
@@ -372,9 +444,8 @@ void RemoteDesktopBrowserTest::Cleanup() {
// TODO(weitaosu): Remove this hack by blocking on the appropriate
// notification.
// The browser may still be loading images embedded in the webapp. If we
- // uinstall it now those load will fail. Navigating away to avoid the load
- // failures.
- ui_test_utils::NavigateToURL(active_browser_, GURL("about:blank"));
+ // uinstall it now those load will fail.
+ ASSERT_TRUE(TimeoutWaiter(base::TimeDelta::FromSeconds(2)).Wait());
if (!NoCleanup()) {
UninstallChromotingApp();
@@ -477,13 +548,14 @@ void RemoteDesktopBrowserTest::ParseCommandLine() {
if (!no_install_) {
webapp_crx_ = command_line->GetSwitchValuePath(kWebAppCrx);
- ASSERT_FALSE(webapp_crx_.empty());
+ webapp_unpacked_ = command_line->GetSwitchValuePath(kWebAppUnpacked);
+ // One and only one of these two arguments should be provided.
+ ASSERT_NE(webapp_crx_.empty(), webapp_unpacked_.empty());
}
}
void RemoteDesktopBrowserTest::ExecuteScript(const std::string& script) {
- ASSERT_TRUE(content::ExecuteScript(
- active_browser_->tab_strip_model()->GetActiveWebContents(), script));
+ ASSERT_TRUE(content::ExecuteScript(active_web_contents(), script));
}
void RemoteDesktopBrowserTest::ExecuteScriptAndWaitForAnyPageLoad(
@@ -491,7 +563,7 @@ void RemoteDesktopBrowserTest::ExecuteScriptAndWaitForAnyPageLoad(
content::WindowedNotificationObserver observer(
content::NOTIFICATION_LOAD_STOP,
content::Source<content::NavigationController>(
- &active_browser_->tab_strip_model()->GetActiveWebContents()->
+ &active_web_contents()->
GetController()));
ExecuteScript(script);
@@ -499,67 +571,42 @@ void RemoteDesktopBrowserTest::ExecuteScriptAndWaitForAnyPageLoad(
observer.Wait();
}
-void RemoteDesktopBrowserTest::ExecuteScriptAndWaitForPageLoad(
- const std::string& script,
- const GURL& target) {
- content::WindowedNotificationObserver observer(
- content::NOTIFICATION_LOAD_STOP,
- base::Bind(&RemoteDesktopBrowserTest::IsURLLoadedInWindow,
- active_browser_,
- target));
-
- ExecuteScript(script);
-
- observer.Wait();
-}
-
// static
bool RemoteDesktopBrowserTest::ExecuteScriptAndExtractBool(
- Browser* browser, const std::string& script) {
+ content::WebContents* web_contents, const std::string& script) {
bool result;
- _ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
- browser->tab_strip_model()->GetActiveWebContents(),
+ EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+ web_contents,
"window.domAutomationController.send(" + script + ");",
&result));
return result;
}
+// static
int RemoteDesktopBrowserTest::ExecuteScriptAndExtractInt(
- const std::string& script) {
+ content::WebContents* web_contents, const std::string& script) {
int result;
_ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
- active_browser_->tab_strip_model()->GetActiveWebContents(),
+ web_contents,
"window.domAutomationController.send(" + script + ");",
&result));
return result;
}
+// static
std::string RemoteDesktopBrowserTest::ExecuteScriptAndExtractString(
- const std::string& script) {
+ content::WebContents* web_contents, const std::string& script) {
std::string result;
_ASSERT_TRUE(content::ExecuteScriptAndExtractString(
- active_browser_->tab_strip_model()->GetActiveWebContents(),
+ web_contents,
"window.domAutomationController.send(" + script + ");",
&result));
return result;
}
-// Helper to navigate to a given url.
-void RemoteDesktopBrowserTest::NavigateToURLAndWaitForPageLoad(
- const GURL& url) {
- content::WindowedNotificationObserver observer(
- content::NOTIFICATION_LOAD_STOP,
- content::Source<content::NavigationController>(
- &active_browser_->tab_strip_model()->GetActiveWebContents()->
- GetController()));
-
- ui_test_utils::NavigateToURL(active_browser_, url);
- observer.Wait();
-}
-
void RemoteDesktopBrowserTest::ClickOnControl(const std::string& name) {
ASSERT_TRUE(HtmlElementVisible(name));
@@ -624,15 +671,10 @@ bool RemoteDesktopBrowserTest::IsPinFormVisible() {
}
// static
-bool RemoteDesktopBrowserTest::IsURLLoadedInWindow(Browser* browser,
- const GURL& url) {
- return GetCurrentURLInBrowser(browser) == url;
-}
-
-// static
-bool RemoteDesktopBrowserTest::IsAuthenticated(Browser* browser) {
+bool RemoteDesktopBrowserTest::IsAuthenticatedInWindow(
+ content::WebContents* web_contents) {
return ExecuteScriptAndExtractBool(
- browser, "remoting.oauth2.isAuthenticated()");
+ web_contents, "remoting.identity.isAuthenticated()");
}
} // namespace remoting
diff --git a/chrome/test/remoting/remote_desktop_browsertest.h b/chrome/test/remoting/remote_desktop_browsertest.h
index 32c291157f..faa3a895a7 100644
--- a/chrome/test/remoting/remote_desktop_browsertest.h
+++ b/chrome/test/remoting/remote_desktop_browsertest.h
@@ -5,8 +5,8 @@
#ifndef CHROME_TEST_REMOTING_REMOTE_DESKTOP_BROWSERTEST_H_
#define CHROME_TEST_REMOTING_REMOTE_DESKTOP_BROWSERTEST_H_
+#include "chrome/browser/apps/app_browsertest_util.h"
#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/notification_service.h"
@@ -19,6 +19,7 @@ const char kOverrideUserDataDir[] = "override-user-data-dir";
const char kNoCleanup[] = "no-cleanup";
const char kNoInstall[] = "no-install";
const char kWebAppCrx[] = "webapp-crx";
+const char kWebAppUnpacked[] = "webapp-unpacked";
const char kUsername[] = "username";
const char kkPassword[] = "password";
const char kMe2MePin[] = "me2me-pin";
@@ -33,9 +34,11 @@ inline void _ASSERT_TRUE(bool condition) {
} // namespace
+using extensions::Extension;
+
namespace remoting {
-class RemoteDesktopBrowserTest : public ExtensionBrowserTest {
+class RemoteDesktopBrowserTest : public extensions::PlatformAppBrowserTest {
public:
RemoteDesktopBrowserTest();
virtual ~RemoteDesktopBrowserTest();
@@ -57,7 +60,10 @@ class RemoteDesktopBrowserTest : public ExtensionBrowserTest {
void VerifyInternetAccess();
// Install the chromoting extension from a crx file.
- void InstallChromotingApp();
+ void InstallChromotingAppCrx();
+
+ // Install the unpacked chromoting extension.
+ void InstallChromotingAppUnpacked();
// Uninstall the chromoting extension.
void UninstallChromotingApp();
@@ -151,7 +157,23 @@ class RemoteDesktopBrowserTest : public ExtensionBrowserTest {
base::FilePath WebAppCrxPath() { return webapp_crx_; }
// Helper to get the extension ID of the installed chromoting webapp.
- std::string ChromotingID() { return chromoting_id_; }
+ std::string ChromotingID() { return extension_->id(); }
+
+ // Is this a appsv2 web app?
+ bool is_platform_app() {
+ return extension_->GetType() == extensions::Manifest::TYPE_PLATFORM_APP;
+ }
+
+ // Are we testing an unpacked extension?
+ bool is_unpacked() {
+ return !webapp_unpacked_.empty();
+ }
+
+ // The "active" WebContents instance the test needs to interact with.
+ content::WebContents* active_web_contents() {
+ DCHECK(!web_contents_stack_.empty());
+ return web_contents_stack_.back();
+ }
// Whether to perform the cleanup tasks (uninstalling chromoting, etc).
// This is useful for diagnostic purposes.
@@ -166,67 +188,62 @@ class RemoteDesktopBrowserTest : public ExtensionBrowserTest {
return GURL("chrome-extension://" + ChromotingID() + "/main.html");
}
- // Helper to retrieve the current URL of the active tab in the active browser
- // window.
+ // Helper to retrieve the current URL in the active WebContents.
GURL GetCurrentURL() {
- return GetCurrentURLInBrowser(active_browser_);
- }
-
- // Helper to retrieve the current URL of the active tab in the given browser
- // window.
- static GURL GetCurrentURLInBrowser(Browser* browser) {
- return browser->tab_strip_model()->GetActiveWebContents()->GetURL();
+ return active_web_contents()->GetURL();
}
// Helpers to execute javascript code on a web page.
- // Helper to execute a javascript code snippet on the current page of
- // the active browser window.
+ // Helper to execute a javascript code snippet in the active WebContents.
void ExecuteScript(const std::string& script);
- // Helper to execute a javascript code snippet one the current page of
- // the active browser window and wait for page load to complete.
+ // Helper to execute a javascript code snippet in the active WebContents
+ // and wait for page load to complete.
void ExecuteScriptAndWaitForAnyPageLoad(const std::string& script);
- // Helper to execute a javascript code snippet one the current page of
- // the active browser window and wait until the target url is loaded.
- // This is used when the target page is loaded after one or more redirections.
- void ExecuteScriptAndWaitForPageLoad(const std::string& script,
- const GURL& target);
-
- // Helper to execute a javascript code snippet on the current page of
- // the active browser window and extract the boolean result.
+ // Helper to execute a javascript code snippet in the active WebContents
+ // and extract the boolean result.
bool ExecuteScriptAndExtractBool(const std::string& script) {
- return ExecuteScriptAndExtractBool(active_browser_, script);
+ return ExecuteScriptAndExtractBool(active_web_contents(), script);
}
- // Helper to execute a javascript code snippet one the current page of
- // the active browser window and extract the boolean result.
- static bool ExecuteScriptAndExtractBool(Browser* browser,
+ // Helper to execute a javascript code snippet and extract the boolean result.
+ static bool ExecuteScriptAndExtractBool(content::WebContents* web_contents,
const std::string& script);
- // Helper to execute a javascript code snippet one the current page of
- // the active browser window and extract the int result.
- int ExecuteScriptAndExtractInt(const std::string& script);
+ // Helper to execute a javascript code snippet in the active WebContents
+ // and extract the int result.
+ int ExecuteScriptAndExtractInt(const std::string& script) {
+ return ExecuteScriptAndExtractInt(active_web_contents(), script);
+ }
+
+ // Helper to execute a javascript code snippet and extract the int result.
+ static int ExecuteScriptAndExtractInt(content::WebContents* web_contents,
+ const std::string& script);
- // Helper to execute a javascript code snippet one the current page of
- // the active browser window and extract the string result.
- std::string ExecuteScriptAndExtractString(const std::string& script);
+ // Helper to execute a javascript code snippet in the active WebContents
+ // and extract the string result.
+ std::string ExecuteScriptAndExtractString(const std::string& script) {
+ return ExecuteScriptAndExtractString(active_web_contents(), script);
+ }
- // Helper to navigate to a given url.
- void NavigateToURLAndWaitForPageLoad(const GURL& url);
+ // Helper to execute a javascript code snippet and extract the string result.
+ static std::string ExecuteScriptAndExtractString(
+ content::WebContents* web_contents, const std::string& script);
- // Helper to check whether an html element with the given name exists on
- // the current page of the active browser window.
+ // Helper to check whether an html element with the given name exists in
+ // the active WebContents.
bool HtmlElementExists(const std::string& name) {
return ExecuteScriptAndExtractBool(
"document.getElementById(\"" + name + "\") != null");
}
- // Helper to check whether a html element with the given name is visible.
+ // Helper to check whether a html element with the given name is visible in
+ // the active WebContents.
bool HtmlElementVisible(const std::string& name);
- // Click on the named HTML control.
+ // Click on the named HTML control in the active WebContents.
void ClickOnControl(const std::string& name);
// Wait for the me2me connection to be established.
@@ -243,13 +260,15 @@ class RemoteDesktopBrowserTest : public ExtensionBrowserTest {
// has been established.
bool IsSessionConnected();
- // Callback used by ExecuteScriptAndWaitForPageLoad to check whether
- // the given page is currently loaded in the given browser window.
- static bool IsURLLoadedInWindow(Browser* browser, const GURL& url);
+ // Callback used by Approve to check whether the chromoting app has
+ // successfully authenticated with the Google services.
+ bool IsAuthenticated() {
+ return IsAuthenticatedInWindow(active_web_contents());
+ }
// Callback used by Approve to check whether the chromoting app has
- // successfully authenticated with the google services.
- static bool IsAuthenticated(Browser* browser);
+ // successfully authenticated with the Google services.
+ static bool IsAuthenticatedInWindow(content::WebContents* web_contents);
// Fields
@@ -258,27 +277,22 @@ class RemoteDesktopBrowserTest : public ExtensionBrowserTest {
// to override the default resolver while the test is active.
scoped_ptr<net::ScopedDefaultHostResolverProc> mock_host_resolver_override_;
- // The "active" browser window the test needs to interact with.
- // We initialize |active_browser_| to the browser instance created by
- // InProcessBrowserTest as the initial browser window to run test in.
- // Whenever a new browser window is spawned and needs attention
- // |active_browser_| is set to that browser window and all subsequent
- // test actions happen there.
- // And when the focus is returned to the original browser window
- // |active_browser_| is reset to browser().
- // This pattern is sufficient for simple streamlined workflows where all
- // the browser windows form a LIFO stack. The test always interacts
- // with the "active" window which is always on the top of the "browser
- // stack". See also http://crrev.com/chrome/browser/ui/browser_list.h
- // If we ever need to deal with more complicated workflows the test
- // code will need to explicitly pass browser instances to the helper
- // routines.
- Browser* active_browser_;
+ // Stores all the WebContents instance in a stack so that we can easily
+ // return to the previous instance.
+ // The active WebContents instance is always stored at the top of the stack.
+ // Initially the stack contains the WebContents instance created by
+ // InProcessBrowserTest as the initial context to run test in.
+ // Whenever a WebContents instance is spawned and needs attention we
+ // push it onto the stack and that becomes the active instance.
+ // And once we are done with the current WebContents instance
+ // we pop it off the stack, returning to the previous instance.
+ std::vector<content::WebContents*> web_contents_stack_;
bool no_cleanup_;
bool no_install_;
- std::string chromoting_id_;
+ const Extension* extension_;
base::FilePath webapp_crx_;
+ base::FilePath webapp_unpacked_;
std::string username_;
std::string password_;
std::string me2me_pin_;