summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-03 00:27:35 +0000
committerjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-03 00:27:35 +0000
commit3682c7736e9cb6cf952c644cf967591bebd5f93a (patch)
tree52d82d11acc398a145fb6424c6b79c5b7ba4f134
parent307f211eff77a5bfcba3485996ce6b77e73aaeab (diff)
downloadchromium_src-3682c7736e9cb6cf952c644cf967591bebd5f93a.zip
chromium_src-3682c7736e9cb6cf952c644cf967591bebd5f93a.tar.gz
chromium_src-3682c7736e9cb6cf952c644cf967591bebd5f93a.tar.bz2
Remove pyauto tests.
BUG=224072 R=avi@chromium.org Review URL: https://codereview.chromium.org/222873002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@261240 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/test/functional.DEPS/DEPS25
-rw-r--r--chrome/test/functional/OWNERS4
-rw-r--r--chrome/test/functional/PYAUTO_TESTS500
-rwxr-xr-xchrome/test/functional/about_plugins_ui.py138
-rw-r--r--chrome/test/functional/ap_lab/ap_configurator.py355
-rw-r--r--chrome/test/functional/ap_lab/ap_configurator_factory.py39
-rw-r--r--chrome/test/functional/ap_lab/ap_configurator_test.py139
-rw-r--r--chrome/test/functional/ap_lab/dlink_ap_configurator.py291
-rw-r--r--chrome/test/functional/ap_lab/linksys_ap_configurator.py195
-rw-r--r--chrome/test/functional/ap_lab/pyauto_ap_configurator.py25
-rw-r--r--chrome/test/functional/apptest.py74
-rwxr-xr-xchrome/test/functional/autofill.py223
-rwxr-xr-xchrome/test/functional/chromeos_accessibility.py115
-rwxr-xr-xchrome/test/functional/chromeos_basic.py52
-rwxr-xr-xchrome/test/functional/chromeos_battery.py124
-rwxr-xr-xchrome/test/functional/chromeos_browser.py52
-rwxr-xr-xchrome/test/functional/chromeos_crosh.py174
-rwxr-xr-xchrome/test/functional/chromeos_longterm_test.py131
-rwxr-xr-xchrome/test/functional/chromeos_power.py23
-rwxr-xr-xchrome/test/functional/chromeos_prefs.py46
-rwxr-xr-xchrome/test/functional/chromeos_security.py42
-rwxr-xr-xchrome/test/functional/chromeos_time.py95
-rwxr-xr-xchrome/test/functional/chromeos_volume.py95
-rw-r--r--chrome/test/functional/chromoting/__init__.py0
-rwxr-xr-xchrome/test/functional/chromoting/auth.py42
-rw-r--r--chrome/test/functional/chromoting/chromoting_base.py47
-rwxr-xr-xchrome/test/functional/chromoting/it2me_basic.py48
-rwxr-xr-xchrome/test/functional/chromoting/me2me_connect.py91
-rwxr-xr-xchrome/test/functional/chromoting/me2me_enable.py53
-rwxr-xr-xchrome/test/functional/codesign.py54
-rwxr-xr-xchrome/test/functional/crash_reporter.py47
-rwxr-xr-xchrome/test/functional/execute_javascript.py72
-rwxr-xr-xchrome/test/functional/extensions.py346
-rwxr-xr-xchrome/test/functional/fullscreen_mouselock.py618
-rwxr-xr-xchrome/test/functional/gpu.py79
-rw-r--r--chrome/test/functional/gtalk/__init__.py0
-rw-r--r--chrome/test/functional/gtalk/gtalk_base_test.py348
-rw-r--r--chrome/test/functional/gtalk/jsutils.js109
-rwxr-xr-xchrome/test/functional/gtalk/pyauto_gtalk.py25
-rwxr-xr-xchrome/test/functional/gtalk/test_basic.py312
-rwxr-xr-xchrome/test/functional/infobars.py322
-rw-r--r--chrome/test/functional/ispy/OWNERS2
-rw-r--r--chrome/test/functional/ispy/__init__.py0
-rw-r--r--chrome/test/functional/ispy/app.yaml17
-rw-r--r--chrome/test/functional/ispy/client/__init__.py0
-rw-r--r--chrome/test/functional/ispy/client/boto_bucket.py88
-rw-r--r--chrome/test/functional/ispy/client/dom.py29
-rw-r--r--chrome/test/functional/ispy/client/wait_on_ajax.js18
-rw-r--r--chrome/test/functional/ispy/common/__init__.py0
-rw-r--r--chrome/test/functional/ispy/common/cloud_bucket.py91
-rw-r--r--chrome/test/functional/ispy/common/constants.py7
-rw-r--r--chrome/test/functional/ispy/common/image_tools.py322
-rw-r--r--chrome/test/functional/ispy/common/image_tools_unittest.py183
-rw-r--r--chrome/test/functional/ispy/common/ispy_utils.py304
-rw-r--r--chrome/test/functional/ispy/common/ispy_utils_unittest.py207
-rw-r--r--chrome/test/functional/ispy/common/mock_cloud_bucket.py65
-rw-r--r--chrome/test/functional/ispy/ispy_api.py229
-rwxr-xr-xchrome/test/functional/ispy/ispy_api_unittest.py68
-rw-r--r--chrome/test/functional/ispy/server/__init__.py0
-rw-r--r--chrome/test/functional/ispy/server/app.py22
-rw-r--r--chrome/test/functional/ispy/server/debug_view_handler.py45
-rw-r--r--chrome/test/functional/ispy/server/gs_bucket.py72
-rw-r--r--chrome/test/functional/ispy/server/image_handler.py38
-rw-r--r--chrome/test/functional/ispy/server/main_view_handler.py116
-rw-r--r--chrome/test/functional/ispy/server/rebaseline_handler.py38
-rw-r--r--chrome/test/functional/ispy/server/update_mask_handler.py59
-rw-r--r--chrome/test/functional/ispy/server/views/__init__.py0
-rw-r--r--chrome/test/functional/ispy/server/views/debug_view.html47
-rw-r--r--chrome/test/functional/ispy/server/views/list_view.html28
-rw-r--r--chrome/test/functional/ispy/server/views/main_view.html78
-rw-r--r--chrome/test/functional/media/OWNERS3
-rw-r--r--chrome/test/functional/media/README49
-rw-r--r--chrome/test/functional/media/__init__.py0
-rwxr-xr-xchrome/test/functional/media/audio_latency_perf.py41
-rwxr-xr-xchrome/test/functional/media/audio_playback_perf.py103
-rwxr-xr-xchrome/test/functional/media/audio_tools.py168
-rw-r--r--chrome/test/functional/media/cns_test_base.py201
-rwxr-xr-xchrome/test/functional/media/media_basic_playback.py78
-rwxr-xr-xchrome/test/functional/media/media_constrained_network_perf.py210
-rwxr-xr-xchrome/test/functional/media/media_jerky.py224
-rwxr-xr-xchrome/test/functional/media/media_scrub_perf.py66
-rwxr-xr-xchrome/test/functional/media/media_seek_perf.py117
-rwxr-xr-xchrome/test/functional/media/media_stat_perf.py85
-rwxr-xr-xchrome/test/functional/media/mixed_audio_latency_perf.py43
-rw-r--r--chrome/test/functional/media/pyauto_media.py41
-rw-r--r--chrome/test/functional/media/worker_thread.py154
-rwxr-xr-xchrome/test/functional/memory.py134
-rwxr-xr-xchrome/test/functional/multiprofile.py314
-rwxr-xr-xchrome/test/functional/nacl_sdk.py796
-rwxr-xr-xchrome/test/functional/netflix.py256
-rwxr-xr-xchrome/test/functional/ntp.py473
-rwxr-xr-xchrome/test/functional/omnibox.py369
-rw-r--r--chrome/test/functional/perf.cfg26
-rwxr-xr-xchrome/test/functional/perf.py2426
-rw-r--r--chrome/test/functional/perf/endure_graphs/config.js8
-rw-r--r--chrome/test/functional/perf/endure_graphs/endure_plotter.html114
-rw-r--r--chrome/test/functional/perf/endure_graphs/endure_plotter.js553
-rw-r--r--chrome/test/functional/perf/endure_graphs/js/common.js89
-rw-r--r--chrome/test/functional/perf/endure_graphs/js/coordinates.js212
-rw-r--r--chrome/test/functional/perf/endure_graphs/js/dom_utils.js43
-rw-r--r--chrome/test/functional/perf/endure_graphs/js/graph_utils.js141
-rw-r--r--chrome/test/functional/perf/endure_graphs/js/plotter.js1199
-rwxr-xr-xchrome/test/functional/perf/endure_result_parser.py824
-rwxr-xr-xchrome/test/functional/perf/endure_server.py79
-rwxr-xr-xchrome/test/functional/perf/endure_setup.py337
-rwxr-xr-xchrome/test/functional/perf_endure.py776
-rwxr-xr-xchrome/test/functional/prefetch.py141
-rwxr-xr-xchrome/test/functional/prefs.py238
-rwxr-xr-xchrome/test/functional/prefs_ui.py343
-rwxr-xr-xchrome/test/functional/pyauto_functional.py123
-rwxr-xr-xchrome/test/functional/pyauto_webdriver.py33
-rwxr-xr-xchrome/test/functional/remote_host_functional.py16
-rwxr-xr-xchrome/test/functional/rlz/rlztest.py270
-rwxr-xr-xchrome/test/functional/search_engines.py110
-rwxr-xr-xchrome/test/functional/secure_shell.py109
-rwxr-xr-xchrome/test/functional/special_tabs.py328
-rwxr-xr-xchrome/test/functional/stress.py806
-rwxr-xr-xchrome/test/functional/test_pyauto.py72
-rw-r--r--chrome/test/functional/test_utils.py401
-rwxr-xr-xchrome/test/functional/tracing/pyauto_tracing.py22
-rw-r--r--chrome/test/functional/tracing/tab_tracker.py83
-rw-r--r--chrome/test/functional/tracing/timeline_model.py57
-rw-r--r--chrome/test/functional/tracing/timeline_model_shim.js53
-rw-r--r--chrome/test/functional/tracing/tracer.js34
-rw-r--r--chrome/test/functional/tracing/tracer.py86
-rwxr-xr-xchrome/test/functional/tracing/tracing_smoke_test.py57
-rw-r--r--chrome/test/functional/webdriver_pages/__init__.py0
-rw-r--r--chrome/test/functional/webdriver_pages/settings.py699
-rwxr-xr-xchrome/test/functional/webpagereplay.py255
-rw-r--r--chrome/test/functional/webrtc_write_wsh.py76
-rwxr-xr-xchrome/test/functional/youtube.py273
-rw-r--r--chrome/test/pyautolib/OWNERS1
-rw-r--r--chrome/test/pyautolib/PYAUTO_TESTS22
-rw-r--r--chrome/test/pyautolib/argc_argv.i30
-rw-r--r--chrome/test/pyautolib/asan_stub.c137
-rw-r--r--chrome/test/pyautolib/bookmark_model.py99
-rw-r--r--chrome/test/pyautolib/chrome_driver_factory.py82
-rw-r--r--chrome/test/pyautolib/chromeos/__init__.py0
-rwxr-xr-xchrome/test/pyautolib/chromeos/chromeos_utils.py38
-rwxr-xr-xchrome/test/pyautolib/chromeos/enable_testing.py53
-rw-r--r--chrome/test/pyautolib/chromeos/power_strip.py119
-rwxr-xr-xchrome/test/pyautolib/chromeos/suid_actions.py153
-rw-r--r--chrome/test/pyautolib/chromeos_network.py100
-rw-r--r--chrome/test/pyautolib/chromoting_cert.p12bin2427 -> 0 bytes
-rw-r--r--chrome/test/pyautolib/chromoting_helper.py200
-rw-r--r--chrome/test/pyautolib/chromoting_key.p12bin2427 -> 0 bytes
-rw-r--r--chrome/test/pyautolib/chromotinglib.py619
-rw-r--r--chrome/test/pyautolib/dom_mutation_observer.js276
-rw-r--r--chrome/test/pyautolib/download_info.py78
-rwxr-xr-xchrome/test/pyautolib/fetch_prebuilt_pyauto.py214
-rwxr-xr-xchrome/test/pyautolib/generate_docs.py57
-rw-r--r--chrome/test/pyautolib/history_info.py77
-rw-r--r--chrome/test/pyautolib/mock_pref_pane.py124
-rw-r--r--chrome/test/pyautolib/omnibox_info.py140
-rw-r--r--chrome/test/pyautolib/plugins_info.py112
-rw-r--r--chrome/test/pyautolib/policy_base.py586
-rwxr-xr-xchrome/test/pyautolib/policy_posix_util.py37
-rw-r--r--chrome/test/pyautolib/prefs_info.py99
-rwxr-xr-xchrome/test/pyautolib/pyauto.py5426
-rw-r--r--chrome/test/pyautolib/pyauto_errors.py35
-rw-r--r--chrome/test/pyautolib/pyauto_paths.py51
-rw-r--r--chrome/test/pyautolib/pyauto_utils.py277
-rwxr-xr-xchrome/test/pyautolib/pyauto_utils_test.py86
-rw-r--r--chrome/test/pyautolib/pyautolib.cc163
-rw-r--r--chrome/test/pyautolib/pyautolib.h121
-rw-r--r--chrome/test/pyautolib/pyautolib.i248
-rwxr-xr-xchrome/test/pyautolib/remote_host.py101
-rwxr-xr-xchrome/test/pyautolib/remote_inspector_client.py1211
-rw-r--r--chrome/test/pyautolib/timer_queue.py85
-rw-r--r--chrome/test/pyautolib/webdriver.DEPS/DEPS5
170 files changed, 0 insertions, 34442 deletions
diff --git a/chrome/test/functional.DEPS/DEPS b/chrome/test/functional.DEPS/DEPS
deleted file mode 100644
index 60bfa47..0000000
--- a/chrome/test/functional.DEPS/DEPS
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-deps = {
- 'src/chrome/test/data': '/trunk/src/chrome/test/data',
- 'src/chrome/test/functional': '/trunk/src/chrome/test/functional',
- 'src/chrome/test/pyautolib': '/trunk/src/chrome/test/pyautolib',
- 'src/content/test/data': '/trunk/src/content/test/data',
- 'src/net/data/ssl/certificates': '/trunk/src/net/data/ssl/certificates',
- 'src/net/tools/testserver': '/trunk/src/net/tools/testserver',
- 'src/third_party/pyftpdlib/src': 'http://pyftpdlib.googlecode.com/svn/trunk',
- 'src/third_party/pywebsocket/src':
- 'http://pywebsocket.googlecode.com/svn/trunk/src@662',
- 'src/third_party/simplejson': '/trunk/src/third_party/simplejson',
- 'src/third_party/tlslite': '/trunk/src/third_party/tlslite',
- 'src/third_party/webdriver/pylib/selenium':
- 'http://selenium.googlecode.com/svn/trunk/py/selenium@18337',
- 'src/third_party/webpagereplay':
- 'http://web-page-replay.googlecode.com/svn/trunk@492',
-}
-
-deps_os = {
- 'win': {
- 'src/third_party/python_26': '/trunk/tools/third_party/python_26@66685',
- }
-}
diff --git a/chrome/test/functional/OWNERS b/chrome/test/functional/OWNERS
deleted file mode 100644
index 54bfe2c..0000000
--- a/chrome/test/functional/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-stgao@chromium.org
-
-# for media stuff
-dalecurtis@chromium.org
diff --git a/chrome/test/functional/PYAUTO_TESTS b/chrome/test/functional/PYAUTO_TESTS
deleted file mode 100644
index b2346b2..0000000
--- a/chrome/test/functional/PYAUTO_TESTS
+++ /dev/null
@@ -1,500 +0,0 @@
-# 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.
-#
-# This file lists the pyauto tests that run as a part of the functional test
-# suite.
-#
-# Tests can be enabled on a per-platform basis. Tests not listed here will
-# not be run.
-#
-# Within each platform, tests are specified in up to 3 groups: (1) enabled
-# tests; (2) tests that are permanently disabled because they do not apply
-# to the given platform and hence should not be run; and (3) disabled tests
-# that need to be investigated/fixed. Tests are listed alphabetically within
-# each group.
-#
-# Test names can be specified in any of the following ways:
-# 1. as a module, in which case all tests in that module will be run
-# example: 'test_basic'
-# 2. or as a test case, in which case all tests in that test case will be run
-# example: 'test_basic.SimpleTest'
-# 3. or as an individual test
-# example: 'test_basic.SimpleTest.testCanOpenGoogle'
-#
-# Tests beginning with '-' will be excluded. This can be used to enforce
-# exclusions for a particular platform.
-# Names beginning with '@' will be treated as suite names and will be
-# recursively expanded.
-
-{
- # This suite gets run on 'Google Chrome' builds.
- 'FULL': {
- 'all': [
- 'about_plugins_ui.AboutPluginsUITest',
- 'about_plugins_ui.ChromeAboutPluginsUITest',
- 'apptest',
- 'autofill',
- 'codesign',
- 'crash_reporter',
- 'execute_javascript',
- 'extensions',
- 'fullscreen_mouselock',
- 'gtalk.test_basic',
- 'infobars',
- 'media.media_basic_playback',
- 'multiprofile',
- 'nacl_sdk',
- 'ntp',
- 'omnibox',
- 'passwords',
- 'prefs',
- 'prefs_ui',
- 'pyauto_webdriver',
- 'search_engines',
- 'special_tabs',
- 'test_pyauto',
-
- # ===========================
- # Permanently-disabled tests.
- # ===========================
-
- # ==================================================
- # Disabled tests that need to be investigated/fixed.
- # ==================================================
- # crbug.com/145006
- '-about_plugins_ui.ChromeAboutPluginsUITest.testEnableAndDisableFlashPlugin',
- # crbug.com/100365
- '-autofill.AutofillTest.testDisplayLineItemForEntriesWithNoCCNum',
- # crbug.com/171828
- '-autofill.AutofillTest.testNoDuplicatePhoneNumsInPrefs',
- # The source is behind. Waiting for dev to automate the update.
- # crbug.com/109160
- '-execute_javascript.ExecuteJavascriptTest.testExecuteJavascriptInExtension',
- # crbug.com/123396
- '-fullscreen_mouselock.FullscreenMouselockTest.testPatternsForFSAndML',
- # crbug.com/132665
- '-fullscreen_mouselock.FullscreenMouselockTest.testTabFSExitWhenNavBackToPrevPage',
- '-fullscreen_mouselock.FullscreenMouselockTest.testTabFSExitWhenNavToNewPage',
- '-fullscreen_mouselock.FullscreenMouselockTest.testMLExitWhenNavBackToPrevPage',
- '-fullscreen_mouselock.FullscreenMouselockTest.testMLExitWhenNavToNewPage',
- # crbug.com/140460
- '-fullscreen_mouselock.FullscreenMouselockTest.testNoTabFSExitWhenJSExitMouseLock',
- # crosbug.com/136875
- '-fullscreen_mouselock.FullscreenMouselockTest.testTabFSDoesNotExitForAnchorLinks',
- # crbug.com/179263
- '-gtalk.test_basic.BasicTest.testCurrentVersion',
- '-gtalk.test_basic.BasicTest.testRCVersion',
- # crbug.com/165796
- '-infobars.OneClickInfobarTest',
- # crbug.com/131874
- '-infobars.OneClickInfobarTest.testNoOneClickInfobarAfterCancel',
- # crbug.com/133315
- '-infobars.OneClickInfobarTest.testDisplayOneClickInfobarAfterDismiss',
- # Mysteriously broken?
- # crbug.com/138857
- '-multiprofile.MultiprofileTest.testMakeSearchEngineDefaultInMultiprofile',
- # crbug.com/179268
- '-ntp.NTPTest.testCannotUninstallWebStore',
- '-ntp.NTPTest.testGetAppsInNewProfile',
- '-ntp.NTPTest.testGetAppsWhenInstallApp',
- '-ntp.NTPTest.testGetAppsWhenInstallNonApps',
- '-ntp.NTPTest.testUninstallApp',
- # crbug.com/143308
- '-omnibox.OmniboxLiveTest.testGoogleSearch',
- # crbug.com/71715
- '-omnibox.OmniboxTest.testHistoryResult',
- # crbug.com/123019
- '-omnibox.OmniboxTest.testAutoCompleteForNonAsciiSearch',
- # crbug.com/137041
- '-omnibox.OmniboxTest.testDifferentTypesOfResults',
- # crbug.com/162341
- '-prefs.PrefsTest.testAllowSelectedGeoTracking',
- '-prefs.PrefsTest.testDismissedInfobarSavesNoEntry',
- '-prefs.PrefsTest.testGeolocationBlockedWhenTrackingDenied',
- '-prefs.PrefsTest.testGeolocationPref',
- # crbug.com/85600
- '-prefs.PrefsTest.testNavigationStateOnSessionRestore',
- # crbug.com/157271
- '-prefs_ui.BasicSettingsUITest.testCancelStartupURLSetting',
- '-prefs_ui.BasicSettingsUITest.testSetStartupPages',
- '-prefs_ui.BasicSettingsUITest.testUseCurrentPagesForStartup',
- # crbug.com/162341
- '-prefs_ui.PrefsUITest.testBehaviorValueCorrectlyDisplayed',
- # crbug.com/112051
- '-prefs_ui.PrefsUITest.testChangeExceptionBehaviorUI',
- # crbug.com/157271
- '-prefs_ui.PrefsUITest.testDeleteExceptionUI',
- # crbug.com/151973
- '-prefs_ui.PrefsUITest.testInitialLineEntryInIncognitoUI',
- # crbug.com/162341
- '-prefs_ui.PrefsUITest.testLocationSettingOptionsUI',
- '-prefs_ui.PrefsUITest.testNoInitialLineEntryInUI',
- # crbug.com/132285
- '-special_tabs.SpecialTabsTest.testSpecialURLTabs',
- # crbug.com/168081
- '-ntp.NTPTest.testCloseOneTab',
- ],
-
- 'win': [
- 'gpu',
- # ===========================
- # Permanently-disabled tests.
- # ===========================
-
- # ==================================================
- # Disabled tests that need to be investigated/fixed.
- # ==================================================
- # crbug.com/105948
- '-autofill.AutofillTest.testPostalCodeAndStateLabelsBasedOnCountry',
- # crbug.com/111289
- '-extensions.ExtensionsTest.testAllowAccessFileURLs',
- # crbug.com/113090
- '-extensions.ExtensionsTest.testAllowIncognitoExtension',
- # crbug.com/171490
- '-passwords.PasswordTest.testPasswdInfoNotStoredWhenAutocompleteOff',
- # crbug.com/117569
- '-passwords.PasswordTest.testSavedPasswordInTabsAndWindows',
- # crbug.com/98526
- '-pyauto_webdriver.PyAutoWebDriverTest.testCanConnectToRestartedBrowser',
- '-pyauto_webdriver.PyAutoWebDriverTest.testTypeIntoTextBox',
- ],
-
- 'mac': [
- # ===========================
- # Permanently-disabled tests.
- # ===========================
-
- # ==================================================
- # Disabled tests that need to be investigated/fixed.
- # ==================================================
- # Keychain popups make autofill/password tests difficult: crbug.com/49378
- '-prefs_ui.PrefsUITest.testSetPasswordAndDelete',
- # codesign tests should run *after* signing. crbug.com/50481
- '-codesign',
- # crbug.com/124922
- '-fullscreen_mouselock.FullscreenMouselockTest.testMouseLockExitWhenBrowserLoseFocus',
- # crbug.com/125989
- '-fullscreen_mouselock.FullscreenMouselockTest.testMouseLockExitWhenAlertDialogShow',
- # Fails on chrome-mac-10_7-qa only: crbug.com/124886
- '-fullscreen_mouselock.FullscreenMouselockTest.testPrefsForFullscreenExit',
- '-fullscreen_mouselock.FullscreenMouselockTest.testNoMouseLockWhenCancelFS',
- # crbug.com/121484
- '-multiprofile.MultiprofileTest.test20NewProfiles',
- '-ntp.NTPTest.testLaunchAppNewWindow', # crbug.com/79812
- # crbug.com/70437
- '-omnibox.OmniboxTest.testHistoryResult',
- # crbug.com/91617
- '-omnibox.OmniboxTest.testContentHistory',
- # Keychain popups make autofill/password tests difficult: crbug.com/49378
- '-passwords',
- # crbug.com/69619
- '-search_engines.SearchEnginesTest.testDiscoverSearchEngine',
- # crbug.com/98526
- '-pyauto_webdriver.PyAutoWebDriverTest.testCanConnectToRestartedBrowser',
- '-pyauto_webdriver.PyAutoWebDriverTest.testTypeIntoTextBox',
- ],
-
- 'linux': [
- 'test_clean_exit',
-
- # ===========================
- # Permanently-disabled tests.
- # ===========================
- # System password manager obstructs password automation.
- '-passwords',
-
- # ==================================================
- # Disabled tests that need to be investigated/fixed.
- # ==================================================
- # crbug.com/111289
- '-extensions.ExtensionsTest.testAllowAccessFileURLs',
- # crbug.com/91033
- '-omnibox.OmniboxTest.testOmniboxSearchHistory',
- ],
-
- 'chromeos': [
- 'chromeos_basic',
- 'chromeos_browser',
- 'chromeos_crosh',
- 'chromeos_power',
- 'chromeos_prefs',
- 'chromeos_security',
- 'chromeos_time',
- 'secure_shell',
- 'youtube',
-
- # ===========================
- # Permanently-disabled tests.
- # ===========================
- # No codesign verification on ChromeOS.
- '-codesign',
- # Sync is already signed in with the login account.
- # So one-click infobar tests do tno apply to chromeos.
- '-infobars.OneClickInfobarTest',
- # Multi-profile doesn't apply to chromeos yet.
- '-multiprofile',
- '-ntp.NTPTest.testDifferentProfileNotAppearInMostVisited',
- # No NaCl support on ChromeOS.
- '-nacl_sdk',
-
- # ==================================================
- # Disabled tests that need to be investigated/fixed.
- # ==================================================
- # crbug.com/132337
- '-autofill.AutofillTest.testTabOrderForEditAddress',
- # crosbug.com/19556
- '-extensions.ExtensionsTest.testAllowAccessFileURLs',
- '-extensions.ExtensionsTest.testAllowIncognitoExtension',
- '-extensions.ExtensionsTest.testDisableEnableExtension',
- # crbug.com/134593
- '-gtalk.test_basic.BasicTest.testCurrentVersion',
- '-gtalk.test_basic.BasicTest.testRCVersion',
- # crosbug.com/24496
- '-infobars.InfobarTest.testPluginCrashForMultiTabs',
- # crbug.com/109035
- '-infobars.InfobarTest.testPluginCrashInfobar',
- # crosbug.com/14256
- '-ntp.NTPTest.testLaunchAppFullScreen',
- # Content history broken in omnibox. crosbug.com/14416
- '-omnibox.OmniboxTest.testContentHistory',
- # crbug.com/91033
- '-omnibox.OmniboxTest.testOmniboxSearchHistory',
- # crosbug.com/19760
- '-passwords.PasswordTest.testClearFetchedCredForNewUserName',
- '-passwords.PasswordTest.testSavedPasswordInTabsAndWindows',
- # onunload popups get created in the same window on chromeos
- # Session restore not working with PyAuto. crosbug.com/12648
- '-prefs.PrefsTest.testNavigationStateOnSessionRestore',
- '-prefs.PrefsTest.testSessionRestoreURLs',
- '-prefs.PrefsTest.testSessionRestore',
- # Deal with i18n chars. crosbug.com/12639
- '-omnibox.OmniboxTest.testCrazyFilenames',
- # crosbug.com/20025
- '-chromeos_browser.ChromeosBrowserTest.testFullScreen',
- # Chrome driver does not work in Chrome OS.
- # crosbug.com/19556
- '-prefs_ui',
- '-prefs.PrefsTest.testGeolocationBlockedWhenTrackingDenied',
- '-prefs.PrefsTest.testGeolocationPref',
- '-pyauto_webdriver',
- ],
- },
-
- # Performance tests.
- 'PERFORMANCE': {
- 'all': [
- 'perf',
-
- # ==================================================
- # Disabled tests that need to be investigated/fixed.
- # ==================================================
- '-perf.HTML5BenchmarkTest', # crbug.com/134476
- '-perf.LiveWebappLoadTest.testNewTabGmail', # crbug.com/136554
- '-perf.ScrollTest.testGmailScroll', # crbug.com/136554
- '-perf.WebGLTest.testWebGLField', # crbug.com/132797
-
- # ===========================
- # Permanently-disabled tests.
- # ===========================
- # Invoked outside of the pyauto_tests framework.
- '-perf.BenchmarkPerfTest.testSpaceport',
- '-perf.PopularSitesScrollTest.test2012Q3',
- ],
- 'win': [
- # ==================================================
- # Disabled tests that need to be investigated/fixed.
- # ==================================================
- '-perf.GPUPerfTest', # Fails. Discuss with prachij@.
- '-perf.PageCyclerNetSimTest', # Dependence missing: crbug.com/132559
- '-perf.LiveGamePerfTest', # Requires linux /proc/stat.
- '-perf.YoutubePerfTest', # AttributeError: AssertPlayingState.
-
- # ===========================
- # Permanently-disabled tests.
- # ===========================
- '-perf.MemoryTest', # Designed only for ChromeOS.
- '-perf.NetflixPerfTest', # Designed only for ChromeOS.
- ],
- 'mac': [
- # ==================================================
- # Disabled tests that need to be investigated/fixed.
- # ==================================================
- '-perf.GPUPerfTest', # Fails. Discuss with prachij@.
- '-perf.PageCyclerNetSimTest', # Dependence missing: crbug.com/132559
- '-perf.LiveGamePerfTest', # Requires linux /proc/stat.
- '-perf.YoutubePerfTest', # AttributeError: AssertPlayingState.
-
- # ===========================
- # Permanently-disabled tests.
- # ===========================
- '-perf.MemoryTest', # Designed only for ChromeOS.
- '-perf.NetflixPerfTest', # Designed only for ChromeOS.
- ],
- 'linux': [
- # ==================================================
- # Disabled tests that need to be investigated/fixed.
- # ==================================================
- '-perf.GPUPerfTest', # Fails. Discuss with prachij@.
- '-perf.PageCyclerNetSimTest', # Dependence missing: crbug.com/132559
- '-perf.WebGLTest', # May not render WebGL; need to verify on QA bot.
- '-perf.YoutubePerfTest', # AttributeError: AssertPlayingState.
-
- # ===========================
- # Permanently-disabled tests.
- # ===========================
- '-perf.MemoryTest', # Designed only for ChromeOS.
- '-perf.NetflixPerfTest', # Designed only for ChromeOS.
- ],
- 'chromeos': [
- # ==================================================
- # Disabled tests that need to be investigated/fixed.
- # ==================================================
- '-perf.NetflixPerfTest', # crosbug.com/32320.
- '-perf.YoutubePerfTest', # crbug.com/233706
-
- # ===========================
- # Permanently-disabled tests.
- # ===========================
- '-perf.GPUPerfTest', # Designed only for Chrome desktop.
- ],
- },
-
- 'PERFORMANCE_LAB': {
- 'all': [
- 'perf.BenchmarkPerfTest.testV8BenchmarkSuite',
- 'perf.FlashTest.testFlashGaming',
- 'perf.ScrollTest.testGooglePlusScroll',
- 'perf.TabPerfTest.test20Tabs',
- 'perf.WebGLTest.testWebGLSpaceRocks',
- ],
- },
-
- 'EMPTY': {
- },
-
- # ChromeOS flash tests.
- 'CHROMEOS_FLASH': {
- 'chromeos': [
- 'flash',
- ],
- },
-
- # ChromeOS volume tests.
- 'CHROMEOS_VOLUME': {
- 'chromeos': [
- 'chromeos_volume',
- ],
- },
-
- # ChromeOS Accessibility tests.
- 'CHROMEOS_ACCESSIBILITY': {
- 'chromeos': [
- 'chromeos_accessibility',
- ],
- },
-
- # PGO performance suite.
- 'PGO': {
- 'chromeos': [
- 'perf.BenchmarkPerfTest.testV8BenchmarkSuite',
- 'perf.PageCyclerTest',
- 'perf.ScrollTest.testGooglePlusScroll',
- ],
- },
-
- # Subset of ChromeOS performance tests for seaboard.
- 'CHROMEOS_PERF_SEABOARD': {
- 'chromeos': [
- 'perf.ScrollTest.testBlankPageScroll',
- 'perf.ScrollTest.testGooglePlusScroll',
- 'perf.ScrollTest.testTextScroll',
- ],
- },
-
- # HTML5 media performance tests.
- 'AV_PERF': {
- 'linux': [
- 'media.audio_latency_perf',
- 'media.audio_playback_perf',
- 'media.media_constrained_network_perf',
- 'media.media_scrub_perf',
- 'media.media_seek_perf',
- 'media.media_stat_perf',
- 'media.mixed_audio_latency_perf',
- ],
- 'win': [
- 'media.audio_latency_perf',
- 'media.audio_playback_perf',
- 'media.media_constrained_network_perf',
- 'media.media_scrub_perf',
- 'media.media_seek_perf',
- 'media.media_stat_perf',
- 'media.mixed_audio_latency_perf',
- ],
- },
-
- # Trace event tests.
- 'TRACING': {
- 'all': [
- 'tracing.tracing_smoke_test',
- ],
- },
-
- # Chromoting tests.
- 'CHROMOTING': {
- 'all': [
- 'chromoting.auth',
- 'chromoting.it2me_basic',
- 'chromoting.me2me_connect',
- 'chromoting.me2me_enable',
- ],
- 'linux': [
- # TODO(yihongg): Me2me test against Linux is not working yet.
- '-chromoting.me2me_connect',
- '-chromoting.me2me_enable',
- ],
- 'chromeos': [
- # ChromeOS doesn't yet support the chromoting host.
- '-chromoting.auth',
- '-chromoting.it2me_basic',
- '-chromoting.me2me_connect',
- '-chromoting.me2me_enable',
- ],
- },
-
- # Pyauto functional tests running on coverage bots.
- 'CODE_COVERAGE': {
- 'all': [
- '@FULL',
- ],
- 'linux': [
- # These tests fail on coverage bots. Disabling for now.
- '-test_clean_exit',
- '-about_plugins_ui',
- '-autofill',
- '-pyauto_webdriver',
- '-extensions',
- '-flash',
- '-fullscreen_mouselock',
- '-gtalk.test_basic',
- '-infobars',
- '-multiprofile',
- '-prefs',
- '-prefs_ui',
- '-apptest',
- '-plugins',
- '-omnibox',
- '-special_tabs',
- '-ntp.NTPTest.testLaunchAppFullScreen',
- '-media.media_basic_playback.MediaBasicPlaybackTest.testBasicPlaybackMatrix',
- '-search_engines.SearchEnginesTest.testDiscoverSearchEngine',
- '-ntp.NTPTest.testUninstallApp',
- '-ntp.NTPTest.testLaunchAppWithDefaultSettings',
- '-ntp.NTPTest.testLaunchAppRegularTab',
- '-ntp.NTPTest.testLaunchAppPinnedTab',
- '-ntp.NTPTest.testGetAppsWhenInstallApp',
- '-ntp.NTPTest.testLaunchAppNewWindow',
- ],
- },
-}
diff --git a/chrome/test/functional/about_plugins_ui.py b/chrome/test/functional/about_plugins_ui.py
deleted file mode 100755
index 0ebde00..0000000
--- a/chrome/test/functional/about_plugins_ui.py
+++ /dev/null
@@ -1,138 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import os
-import re
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-import pyauto_utils
-
-
-class AboutPluginsUITest(pyauto.PyUITest):
- """Testcase for chrome://plugins UI."""
-
- def testAboutPluginDetailInfo(self):
- """Verify chrome://plugins page shows plugin details."""
- self.NavigateToURL('chrome://plugins/')
- driver = self.NewWebDriver()
- detail_link = driver.find_element_by_id('details-link')
- self.assertTrue(self.WaitUntil(lambda: detail_link.is_displayed()),
- msg='Details link could not be found.')
- detail_link.click()
- # Verify that detail info for Remote Viewer plugin shows up.
- # Remote Viewer plugin is expected to be present on all platforms.
- self.assertTrue(self.WaitUntil(lambda: len(driver.find_elements_by_xpath(
- '//*[@jscontent="path"][text()="internal-remoting-viewer"]'))))
-
-
-class ChromeAboutPluginsUITest(pyauto.PyUITest):
- """Testcase for official build only plugins in chrome://plugins UI."""
-
- def Debug(self):
- """chrome://plugins test debug method.
-
- This method will not run automatically.
- """
- self.NavigateToURL('chrome://plugins/')
- driver = self.NewWebDriver()
- import pdb
- pdb.set_trace()
-
- def _IsEnabled(self, driver, plugin_name):
- """Checks if plugin is enabled.
-
- Args:
- driver: A Chrome driver object.
- plugin_name: Plugin name to verify.
-
- Returns:
- True, if plugin is enabled, or False otherwise.
- """
- check_plugin_enabled_js = 'return navigator.plugins["%s"] != undefined' % \
- plugin_name
- return driver.execute_script(check_plugin_enabled_js)
-
- def _ExpandDetailInfoLink(self, driver):
- """Expand detail info link.
-
- Args:
- driver: A Chrome driver object.
- """
- detail_link = driver.find_element_by_id('details-link')
- self.assertTrue(self.WaitUntil(lambda: detail_link.is_displayed()),
- msg='Details link could not be found.')
- detail_link.click()
-
- def _OverridePluginPageAnimation(self, driver):
- """Override the animation for expanding detail info to make sure element
- remain at the same location where web driver found it.
-
- Args:
- driver: A Chrome driver object.
- """
- override_animation_style_js = """
- style = document.createElement('style');
- style.innerHTML = "* { -webkit-transition: all 0s ease-in !important}";
- document.head.appendChild(style);
- """
- driver.execute_script(override_animation_style_js)
-
- def testAboutPluginEnableAndDisablePDFPlugin(self):
- """Verify enable and disable pdf plugins from about:plugins page."""
- self.NavigateToURL('chrome://plugins/')
- driver = self.NewWebDriver()
-
- self._OverridePluginPageAnimation(driver)
- self._ExpandDetailInfoLink(driver)
-
- pdf_disable_path = '//*[@class="plugin-name"][text()="Chrome PDF Viewer"' \
- ']//ancestor::*[@class="plugin-text"]//a[text()="Disable"]'
- pdf_enable_path = '//*[@class="plugin-name"][text()="Chrome PDF Viewer"' \
- ']//ancestor::*[@class="plugin-text"]//a[text()="Enable"]'
-
- # Confirm Chrome PDF Viewer plugin is found and find disable PDF link.
- pdf_disable_link = pyauto_utils.WaitForDomElement(self, driver,
- pdf_disable_path)
-
- # Disable PDF viewer plugin in about:plugins.
- pdf_disable_link.click()
- self.assertTrue(self.WaitUntil(lambda: not
- self._IsEnabled(driver, 'Chrome PDF Viewer')))
-
- # Re-enable PDF viewer plugin.
- pdf_enable_link = driver.find_element_by_xpath(pdf_enable_path)
- pdf_enable_link.click()
- self.assertTrue(self.WaitUntil(lambda:
- self._IsEnabled(driver, 'Chrome PDF Viewer')))
-
- def testEnableAndDisableFlashPlugin(self):
- """Verify enable and disable flash plugins from about:plugins page."""
- self.NavigateToURL('chrome://plugins/')
- driver = self.NewWebDriver()
-
- self._OverridePluginPageAnimation(driver)
- self._ExpandDetailInfoLink(driver)
- flash_plugins_elem = driver.find_element_by_xpath(
- '//*[@jscontent="name"][text()="Flash"]//ancestor' \
- '::*[@class="plugin-text"]')
-
- # Disable flash plugin from flash detail info.
- flash_disable_link = flash_plugins_elem.find_element_by_xpath(
- './/a[text()="Disable"]')
- flash_disable_link.click()
- self.assertTrue(self.WaitUntil(lambda: not
- self._IsEnabled(driver, 'Shockwave Flash')))
-
- # Re-enable Flash plugin from flash detail info.
- flash_enable_link = flash_plugins_elem.find_element_by_xpath(
- './/a[text()="Enable"]')
- flash_enable_link.click()
- self.assertTrue(self.WaitUntil(lambda:
- self._IsEnabled(driver, 'Shockwave Flash')))
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/ap_lab/ap_configurator.py b/chrome/test/functional/ap_lab/ap_configurator.py
deleted file mode 100644
index b356028..0000000
--- a/chrome/test/functional/ap_lab/ap_configurator.py
+++ /dev/null
@@ -1,355 +0,0 @@
-# Copyright (c) 2012 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.
-
-import copy
-import logging
-import os
-
-import pyauto_ap_configurator
-import pyauto
-
-import selenium.common.exceptions
-from selenium.webdriver.support.ui import WebDriverWait
-
-
-class APConfigurator(object):
- """Base class for objects to configure access points using webdriver."""
-
- def __init__(self, pyauto_instance):
- self.pyauto_instance = pyauto_instance
- self._driver = pyauto_instance.NewWebDriver()
- # Any call to wait.until() will raise an exception if the timeout is hit.
- self._wait = WebDriverWait(self._driver, timeout=5)
-
- # Possible bands
- self.band_2ghz = '2.4GHz'
- self.band_5ghz = '5GHz'
-
- # Possible modes
- self.mode_a = 0x0001
- self.mode_b = 0x0010
- self.mode_g = 0x0100
- self.mode_n = 0x1000
-
- # Possible security settings
- self.security_disabled = 'Disabled'
- self.security_wep = 'WEP'
- self.security_wpawpsk = 'WPA-Personal'
- self.security_wpa2wpsk = 'WPA2-Personal'
- self.security_wpa8021x = 'WPA-Enterprise'
- self.security_wpa28021x = 'WPA2-Enterprise'
-
- self.wep_authentication_open = 'Open'
- self.wep_authentication_shared = 'Shared Key'
-
- self._command_list = []
-
- def _WaitForObjectByXPath(self, xpath):
- """Waits for an object to appear."""
- try:
- self._wait.until(lambda _: self._driver.find_element_by_xpath(xpath))
- except selenium.common.exceptions.TimeoutException, e:
- logging.exception('Unable to find the wait for object by xpath: %s\n'
- 'WebDriver exception: %s', xpath, str(e))
-
- def SelectItemFromPopupByID(self, item, element_id, wait_for_xpath=None):
- """Selects an item from a popup, by passing the element ID.
-
- Args:
- item: the item to select from the popup
- element_id: the html ID of the item
- wait_for_xpath: an item to wait for before returning
- """
- xpath = 'id("%s")' % element_id
- self.SelectItemFromPopupByXPath(item, xpath, wait_for_xpath)
-
- def SelectItemFromPopupByXPath(self, item, xpath, wait_for_xpath=None):
- """Selects an item from a popup, by passing the xpath of the popup.
-
- Args:
- item: the item to select from the popup
- xpath: the xpath of the popup
- wait_for_xpath: an item to wait for before returning
- """
- popup = self._driver.find_element_by_xpath(xpath)
- for option in popup.find_elements_by_tag_name('option'):
- if option.text == item:
- option.click()
- break
- if wait_for_xpath: self._WaitForObjectByXPath(wait_for_xpath)
-
- def SetContentOfTextFieldByID(self, content, text_field_id,
- wait_for_xpath=None):
- """Sets the content of a textfield, by passing the element ID.
-
- Args:
- content: the content to apply to the textfield
- text_field_id: the html ID of the textfield
- wait_for_xpath: an item to wait for before returning
- """
- xpath = 'id("%s")' % text_field_id
- self.SetConentsOfTextFieldByXPath(content, xpath, wait_for_xpath)
-
- def SetConentsOfTextFieldByXPath(self, content, xpath, wait_for_xpath=None):
- """Sets the content of a textfield, by passing the xpath.
-
- Args:
- content: the content to apply to the textfield
- xpath: the xpath of the textfield
- wait_for_xpath: an item to wait for before returning
- """
- # When we can get the value we know the text field is ready.
- text_field = self._driver.find_element_by_xpath(xpath)
- try:
- self._wait.until(lambda _: text_field.get_attribute('value'))
- except selenium.common.exceptions.TimeoutException, e:
- logging.exception('Unable to obtain the value of the text field %s.\n'
- 'WebDriver exception: %s', wait_for_xpath, str(e))
- text_field = self._driver.find_element_by_xpath(xpath)
- text_field.clear()
- text_field.send_keys(content)
- if wait_for_xpath: self._WaitForObjectByXPath(wait_for_xpath)
-
- def SetCheckBoxSelectedByID(self, check_box_id, selected=True,
- wait_for_xpath=None):
- """Sets the state of a checkbox, by passing the ID.
-
- Args:
- check_box_id: the html id of the checkbox
- selected: True to enable the checkbox; False otherwise
- wait_for_xpath: an item to wait for before returning
- """
- xpath = 'id("%s")' % check_box_id
- self.SetCheckBoxSelectedByXPath(xpath, selected, wait_for_xpath)
-
- def SetCheckBoxSelectedByXPath(self, xpath, selected=True,
- wait_for_xpath=None):
- """Sets the state of a checkbox, by passing the xpath.
-
- Args:
- xpath: the xpath of the checkbox
- selected: True to enable the checkbox; False otherwise
- wait_for_xpath: an item to wait for before returning
- """
- check_box = self._driver.find_element_by_xpath(xpath)
- value = check_box.get_attribute('value')
- if (value == '1' and not selected) or (value == '0' and selected):
- check_box.click()
- if wait_for_xpath: self._WaitForObjectByXPath(wait_for_xpath)
-
- def AddItemToCommandList(self, method, args, page, priority):
- """Adds commands to be executed against the AP web UI.
-
- Args:
- method: the method to run
- args: the arguments for the method you want executed
- page: the page on the web ui where the method should be run against
- priority: the priority of the method
- """
- self._command_list.append({'method': method,
- 'args': copy.copy(args),
- 'page': page,
- 'priority': priority})
-
- def GetRouterName(self):
- """Returns a string to describe the router.
-
- Note: The derived class must implement this method.
- """
- raise NotImplementedError
-
- def GetRouterShortName(self):
- """Returns a short string to describe the router.
-
- Note: The derived class must implement this method.
- """
- raise NotImplementedError
-
- def GetNumberOfPages(self):
- """Returns the number of web pages used to configure the router.
-
- Note: This is used internally by applySettings, and this method must be
- implemented by the derived class.
- """
- raise NotImplementedError
-
- def GetSupportedBands(self):
- """Returns a list of dictionaries describing the supported bands.
-
- Example: returned is a dictionary of band and a list of channels. The band
- object returned must be one of those defined in the __init___ of
- this class.
-
- supported_bands = [{'band' : self.band_2GHz,
- 'channels' : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]},
- {'band' : self.band_5ghz,
- 'channels' : [26, 40, 44, 48, 149, 153, 157, 161, 165]}]
-
- Returns:
- A list of dictionaries as described above
-
- Note: The derived class must implement this method.
- """
- raise NotImplementedError
-
- def GetSupportedModes(self):
- """Returns a list of dictionaries describing the supported modes.
-
- Example: returned is a dictionary of band and a list of modess. The band
- and modes objects returned must be one of those defined in the
- __init___ of this class.
-
- supported_modes = [{'band' : self.band_2GHz,
- 'modes' : [mode_b, mode_b | mode_g]},
- {'band' : self.band_5ghz,
- 'modes' : [mode_a, mode_n, mode_a | mode_n]}]
-
- Returns:
- A list of dictionaries as described above
-
- Note: The derived class must implement this method.
- """
- raise NotImplementedError
-
- def NavigateToPage(self, page_number):
- """Navigates to the page corresponding to the given page number.
-
- This method performs the translation between a page number and a url to
- load. This is used internally by applySettings.
-
- Args:
- page_number: Page number of the page to load
-
- Returns:
- True if navigation is successful; False otherwise.
-
- Note: The derived class must implement this method.
- """
- raise NotImplementedError
-
- def SavePage(self, page_number):
- """Saves the given page.
-
- Args:
- page_number: Page number of the page to save.
-
- Returns:
- True if navigation is successful; False otherwise.
-
- Note: The derived class must implement this method.
- """
- raise NotImplementedError
-
- def SetMode(self, mode, band=None):
- """Sets the mode.
-
- Args:
- mode: must be one of the modes listed in __init__()
- band: the band to select
-
- Note: The derived class must implement this method
- """
- raise NotImplementedError
-
- def SetRadio(self, enabled=True):
- """Turns the radio on and off.
-
- Args:
- enabled: True to turn on the radio; False otherwise
-
- Note: The derived class must implement this method.
- """
- raise NotImplementedError
-
- def SetSSID(self, ssid):
- """Sets the SSID of the wireless network.
-
- Args:
- ssid: Name of the wireless network
-
- Note: The derived class must implement this method.
- """
- raise NotImplementedError
-
- def SetChannel(self, channel):
- """Sets the channel of the wireless network.
-
- Args:
- channel: Integer value of the channel
-
- Note: The derived class must implement this method.
- """
- raise NotImplementedError
-
- def SetBand(self, band):
- """Sets the band of the wireless network.
-
- Currently there are only two possible values for band 2kGHz and 5kGHz.
-
- Args:
- band: Constant describing the band type
-
- Note: The derived class must implement this method.
- """
- raise NotImplementedError
-
- def SetSecurityDisabled(self):
- """Disables the security of the wireless network.
-
- Note: The derived class must implement this method.
- """
- raise NotImplementedError
-
- def SetSecurityWEP(self, key_value, authentication):
- """Enabled WEP security for the wireless network.
-
- Args:
- key_value: encryption key to use
- authentication: one of two supported authentication types:
- wep_authentication_open or wep_authentication_shared
-
- Note: The derived class must implement this method.
- """
- raise NotImplementedError
-
- def SetSecurityWPAPSK(self, shared_key, update_interval=1800):
- """Enabled WPA using a private security key for the wireless network.
-
- Args:
- shared_key: shared encryption key to use
- update_interval: number of seconds to wait before updating
-
- Note: The derived class must implement this method.
- """
- raise NotImplementedError
-
- def SetVisibility(self, visible=True):
- """Set the visibility of the wireless network.
-
- Args:
- visible: True for visible; False otherwise
-
- Note: The derived class must implement this method.
- """
- raise NotImplementedError
-
- def ApplySettings(self):
- """Apply all settings to the access point."""
- # Pull items by page and then sort
- if self.GetNumberOfPages() == -1:
- self.fail(msg='Number of pages is not set.')
- page_range = range(1, self.GetNumberOfPages() + 1)
- for i in page_range:
- page_commands = []
- for command in self._command_list:
- if command['page'] == i:
- page_commands.append(command)
- # Sort the commands in this page by priority
- sorted_page_commands = sorted(page_commands, key=lambda k: k['priority'])
- if sorted_page_commands and self.NavigateToPage(i):
- for command in sorted_page_commands:
- command['method'](*command['args'])
- self.SavePage(i)
- self._command_list = []
-
diff --git a/chrome/test/functional/ap_lab/ap_configurator_factory.py b/chrome/test/functional/ap_lab/ap_configurator_factory.py
deleted file mode 100644
index aa8dcd6..0000000
--- a/chrome/test/functional/ap_lab/ap_configurator_factory.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (c) 2012 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.
-
-import os
-
-import dlink_ap_configurator
-import linksys_ap_configurator
-
-import pyauto_ap_configurator # must preceed pyauto
-import pyauto
-
-
-class APConfiguratorFactory(object):
- """Class that instantiates all available APConfigurators."""
-
- def __init__(self, pyauto_instance, config_dict_file_path=None):
- if not config_dict_file_path:
- # Load the default dictionary file
- config_dict_file_path = os.path.join(pyauto_instance.DataDir(),
- 'pyauto_private', 'chromeos',
- 'network', 'wifi_compat_config')
- assert os.path.exists(config_dict_file_path), ('%s missing' %
- config_dict_file_path)
- ap_dict = pyauto_instance.EvalDataFrom(config_dict_file_path)
- self.ap_list = []
- self.ap_list.append(linksys_ap_configurator.LinksysAPConfigurator(
- pyauto_instance, ap_dict['LinksysAPConfigurator']))
- self.ap_list.append(dlink_ap_configurator.DLinkAPConfigurator(
- pyauto_instance, ap_dict['DLinkAPConfigurator']))
-
- def GetAPConfigurators(self):
- return self.ap_list
-
- def GetAPConfiguratorByShortName(self, name):
- for ap in self.ap_list:
- if ap.GetRouterShortName() == name:
- return ap
- return None
diff --git a/chrome/test/functional/ap_lab/ap_configurator_test.py b/chrome/test/functional/ap_lab/ap_configurator_test.py
deleted file mode 100644
index 92daa90..0000000
--- a/chrome/test/functional/ap_lab/ap_configurator_test.py
+++ /dev/null
@@ -1,139 +0,0 @@
-# Copyright (c) 2012 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.
-
-import unittest
-
-import ap_configurator_factory
-import dlink_ap_configurator
-import linksys_ap_configurator
-
-import pyauto_ap_configurator # must preceed pyauto
-import pyauto
-
-
-class ConfiguratorTest(pyauto.PyUITest):
- """This test needs to be run against the UI interface.
-
- The purpose of this test is to act as a basic acceptance test when developing
- a new AP configurator class. Use this to make sure all core functionality is
- implemented.
-
- This test does not verify that everything works.
-
- """
-
- def setUp(self):
- pyauto.PyUITest.setUp(self)
- factory = ap_configurator_factory.APConfiguratorFactory(self)
- # Set self.ap to the one you want to test against.
- self.ap = factory.GetAPConfiguratorByShortName('DAP-1522')
-
- def testMakeNoChanges(self):
- """Test saving with no changes doesn't throw an error."""
- # Set to a known state.
- self.ap.SetRadio(True)
- self.ap.ApplySettings()
- # Set the same setting again.
- self.ap.SetRadio(True)
- self.ap.ApplySettings()
-
- def testRadio(self):
- """Test we can adjust the radio setting."""
- self.ap.SetRadio(True)
- self.ap.ApplySettings()
- self.ap.SetRadio(False)
- self.ap.ApplySettings()
-
- def testChannel(self):
- """Test adjusting the channel."""
- self.ap.SetRadio(4)
- self.ap.ApplySettings()
-
- def testVisibility(self):
- """Test adjusting the visibility."""
- self.ap.SetVisibility(False)
- self.ap.ApplySettings()
- self.ap.SetVisibility(True)
- self.ap.ApplySettings()
-
- def testSSID(self):
- """Test setting the SSID."""
- self.ap.SetSSID('AP-automated-ssid')
- self.ap.ApplySettings()
-
- def testSecurityWEP(self):
- """Test configuring WEP security."""
- self.ap.SetSecurityWEP('45678', self.ap.wep_authentication_open)
- self.ap.ApplySettings()
- self.ap.SetSecurityWEP('90123', self.ap.wep_authentication_shared)
- self.ap.ApplySettings()
-
- def testPrioritySets(self):
- """Test that commands are run in the right priority."""
- self.ap.SetRadio(False)
- self.ap.SetVisibility(True)
- self.ap.SetSSID('priority_test')
- self.ap.ApplySettings()
-
- def testSecurityAndGeneralSettings(self):
- """Test updating settings that are general and security related."""
- self.ap.SetRadio(False)
- self.ap.SetVisibility(True)
- self.ap.SetSecurityWEP('88888', self.ap.wep_authentication_open)
- self.ap.SetSSID('sec&gen_test')
- self.ap.ApplySettings()
-
- def testModes(self):
- """Tests switching modes."""
- modes_info = self.ap.GetSupportedModes()
- self.assertFalse(not modes_info,
- msg='Returned an invalid mode list. Is this method'
- ' implemented?')
- for band_modes in modes_info:
- for mode in band_modes['modes']:
- self.ap.SetMode(mode)
- self.ap.ApplySettings()
-
- def testModesWithBand(self):
- """Tests switching modes that support adjusting the band."""
- # Check if we support self.kModeN across multiple bands
- modes_info = self.ap.GetSupportedModes()
- n_bands = []
- for band_modes in modes_info:
- if self.ap.mode_n in band_modes['modes']:
- n_bands.append(band_modes['band'])
- if len(n_bands) > 1:
- for n_band in n_bands:
- self.ap.SetMode(self.ap.mode_n, band=n_band)
- self.ap.ApplySettings()
-
- def testFastCycleSecurity(self):
- """Mini stress for changing security settings rapidly."""
- self.ap.SetRadio(True)
- self.ap.SetSecurityWEP('77777', self.ap.wep_authentication_open)
- self.ap.SetSecurityDisabled()
- self.ap.SetSecurityWPAPSK('qwertyuiolkjhgfsdfg')
- self.ap.ApplySettings()
-
- def testCycleSecurity(self):
- """Test switching between different security settings."""
- self.ap.SetRadio(True)
- self.ap.SetSecurityWEP('77777', self.ap.wep_authentication_open)
- self.ap.ApplySettings()
- self.ap.SetSecurityDisabled()
- self.ap.ApplySettings()
- self.ap.SetSecurityWPAPSK('qwertyuiolkjhgfsdfg')
- self.ap.ApplySettings()
-
- def testActionsWhenRadioDisabled(self):
- """Test making changes when the radio is diabled."""
- self.ap.SetRadio(False)
- self.ap.ApplySettings()
- self.ap.SetSecurityWEP('77777', self.ap.wep_authentication_open)
- self.ap.SetRadio(False)
- self.ap.ApplySettings()
-
-
-if __name__ == '__main__':
- pyauto_ap_configurator.Main()
diff --git a/chrome/test/functional/ap_lab/dlink_ap_configurator.py b/chrome/test/functional/ap_lab/dlink_ap_configurator.py
deleted file mode 100644
index 12c7d2d..0000000
--- a/chrome/test/functional/ap_lab/dlink_ap_configurator.py
+++ /dev/null
@@ -1,291 +0,0 @@
-# Copyright (c) 2012 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.
-
-import logging
-import os
-
-import ap_configurator
-import selenium.common.exceptions
-
-
-class DLinkAPConfigurator(ap_configurator.APConfigurator):
- """Derived class to control the DLink DAP-1522."""
-
- def __init__(self, pyauto_instance, admin_interface_url):
- super(DLinkAPConfigurator, self).__init__(pyauto_instance)
- # Override constants
- self.security_disabled = 'Disable Wireless Security (not recommended)'
- self.security_wep = 'WEP'
- self.security_wpapsk = 'WPA-Personal'
- self.security_wpa2psk = 'WPA-Personal'
- self.security_wpa8021x = 'WPA-Enterprise'
- self.security_wpa28021x = 'WPA2-Enterprise'
-
- self.admin_interface_url = admin_interface_url
-
- def _OpenLandingPage(self):
- self.pyauto_instance.NavigateToURL('http://%s/index.php' %
- self.admin_interface_url)
- page_name = os.path.basename(self.pyauto_instance.GetActiveTabURL().spec())
- if page_name == 'login.php' or page_name == 'index.php':
- try:
- self._wait.until(lambda _: self._driver.find_element_by_xpath(
- '//*[@name="login"]'))
- except selenium.common.exceptions.TimeoutException, e:
- # Maybe we were re-routes to the configuration page
- if (os.path.basename(self.pyauto_instance.GetActiveTabURL().spec()) ==
- 'bsc_wizard.php'):
- return
- logging.exception('WebDriver exception: %s', str(e))
- login_button = self._driver.find_element_by_xpath('//*[@name="login"]')
- login_button.click()
-
- def _OpenConfigurationPage(self):
- self._OpenLandingPage()
- if (os.path.basename(self.pyauto_instance.GetActiveTabURL().spec()) !=
- 'bsc_wizard.php'):
- self.fail(msg='Taken to an unknown page %s' %
- self.pyauto_instance.GetActiveTabURL().spec())
-
- # Else we are being logged in automatically to the landing page
- wlan = '//*[@name="wlan_wireless"]'
- try:
- self._wait.until(lambda _: self._driver.find_element_by_xpath(wlan))
- except selenium.common.exceptions.TimeoutException, e:
- logging.exception('WebDriver exception: %s', str(e))
-
- wlan_button = self._driver.find_element_by_xpath(wlan)
- wlan_button.click()
- # Wait for the main configuration page, look for the radio button
- try:
- self._wait.until(lambda _: self._driver.find_element_by_xpath(
- 'id("enable")'))
- except selenium.common.exceptions.TimeoutException, e:
- logging.exception('Unable to find the radio button on the main landing '
- 'page.\nWebDriver exception: %s', str(e))
-
- def GetRouterName(self):
- return 'Router Name: DAP-1522; Class: DLinkAPConfigurator'
-
- def GetRouterShortName(self):
- return 'DAP-1522'
-
- def GetNumberOfPages(self):
- return 1
-
- def GetSupportedBands(self):
- return [{'band': self.band_2ghz,
- 'channels': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]},
- {'band': self.band_5ghz,
- 'channels': [26, 40, 44, 48, 149, 153, 157, 161, 165]}]
-
- def GetSupportedModes(self):
- return [{'band': self.band_2ghz,
- 'modes': [self.mode_b, self.mode_g, self.mode_n,
- self.mode_b | self.mode_g, self.mode_g | self.mode_n]},
- {'band': self.band_5ghz,
- 'modes': [self.mode_a, self.mode_n, self.mode_a | self.mode_n]}]
-
- def NavigateToPage(self, page_number):
- # All settings are on the same page, so we always open the config page
- self._OpenConfigurationPage()
- return True
-
- def SavePage(self, page_number):
- # All settings are on the same page, we can ignore page_number
- button = self._driver.find_element_by_xpath('//input[@name="apply"]')
- button.click()
- # If we did not make changes so we are sent to the continue screen.
- continue_screen = True
- button_xpath = '//input[@name="bt"]'
- try:
- self._wait.until(lambda _:
- self._driver.find_element_by_xpath(button_xpath))
- except selenium.common.exceptions.TimeoutException, e:
- continue_screen = False
- if continue_screen:
- button = self._driver.find_element_by_xpath(button_xpath)
- button.click()
- # We will be returned to the landing page when complete
- try:
- self._wait.until(lambda _:
- self._driver.find_element_by_xpath('id("enable")'))
- except selenium.common.exceptions.TimeoutException, e:
- logging.exception('Unable to find the radio button on the main landing '
- 'page.\nWebDriver exception: %s', str(e))
- return False
- return True
-
- def SetMode(self, mode, band=None):
- # Mode overrides the band. So if a band change is made after a mode change
- # it may make an incompatible pairing.
- self.AddItemToCommandList(self._SetMode, (mode, band), 1, 800)
-
- def _SetMode(self, mode, band=None):
- # Create the mode to popup item mapping
- mode_mapping = {self.mode_b: '802.11b Only', self.mode_g: '802.11g Only',
- self.mode_n: '802.11n Only',
- self.mode_b | self.mode_g: 'Mixed 802.11g and 802.11b',
- self.mode_n | self.mode_g: 'Mixed 802.11n and 802.11g',
- self.mode_n | self.mode_g | self.mode_b:
- 'Mixed 802.11n, 802.11g, and 802.11b',
- self.mode_n | self.mode_g | self.mode_b:
- 'Mixed 802.11n, 802.11g, and 802.11b',
- self.mode_a: '802.11a Only',
- self.mode_n | self.mode_a: 'Mixed 802.11n and 802.11a'}
- band_value = self.band_2ghz
- if mode in mode_mapping.keys():
- popup_value = mode_mapping[mode]
- # If the mode contains 802.11a we use 5Ghz
- if mode & self.mode_a == self.mode_a:
- band_value = self.band_5ghz
- # If the mode is 802.11n mixed with 802.11a it must be 5Ghz
- elif mode & (self.mode_n | self.mode_a) == (self.mode_n | self.mode_a):
- band_value = self.band_5ghz
- # If the mode is 802.11n mixed with something other than 802.11a its 2Ghz
- elif mode & self.mode_n == self.mode_n and mode ^ self.mode_n > 0:
- band_value = self.band_2ghz
- # If the mode is 802.11n then we default to 5Ghz unless there is a band
- elif mode == self.mode_n:
- band_value = self.band_5ghz
- if band:
- band_value = band
- else:
- logging.exception('The mode selected %d is not supported by router %s.',
- hex(mode), self.getRouterName())
- # Set the band first
- self._SetBand(band_value)
- popup_id = 'mode_80211_11g'
- if band_value == self.band_5ghz:
- popup_id = 'mode_80211_11a'
- self.SelectItemFromPopupByID(popup_value, popup_id)
-
- def SetRadio(self, enabled=True):
- # If we are enabling we are activating all other UI components, do it first.
- # Otherwise we are turning everything off so do it last.
- if enabled:
- weight = 1
- else:
- weight = 1000
- # This disables all UI so it should be the last item to be changed
- self.AddItemToCommandList(self._SetRadio, (enabled,), 1, weight)
-
- def _SetRadio(self, enabled=True):
- # The radio checkbox for this router always has a value of 1. So we need to
- # use other methods to determine if the radio is on or not. Check if the
- # ssid textfield is disabled.
- ssid = self._driver.find_element_by_xpath('//input[@name="ssid"]')
- if ssid.get_attribute('disabled') == 'true':
- radio_enabled = False
- else:
- radio_enabled = True
- if radio_enabled == enabled:
- # Nothing to do
- return
- self.SetCheckBoxSelectedByID('enable', selected=False,
- wait_for_xpath='id("security_type_ap")')
-
- def SetSSID(self, ssid):
- # Can be done as long as it is enabled
- self.AddItemToCommandList(self._SetSSID, (ssid,), 1, 900)
-
- def _SetSSID(self, ssid):
- self._SetRadio(enabled=True)
- self.SetContentOfTextFieldByID(ssid, 'ssid')
-
- def SetChannel(self, channel):
- self.AddItemToCommandList(self._SetChannel, (channel,), 1, 900)
-
- def _SetChannel(self, channel):
- self._SetRadio(enabled=True)
- self.SetCheckBoxSelectedByID('autochann', selected=False)
- self.SelectItemFromPopupByID(str(channel), 'channel_g')
-
- # Experimental
- def GetBand(self):
- # The radio buttons do more than run a script that adjusts the possible
- # channels. We will just check the channel to popup.
- self.setRadioSetting(enabled=True)
- xpath = ('id("channel_g")')
- self._OpenConfigurationPage()
- try:
- self._wait.until(lambda _: self._driver.find_element_by_xpath(xpath))
- except selenium.common.exceptions.TimeoutException, e:
- logging.exception('WebDriver exception: %s', str(e))
- element = self._driver.find_element_by_xpath(xpath)
- if element.find_elements_by_tag_name('option')[0].text == '1':
- return self.band_2ghz
- return self.band_5ghz
-
- def SetBand(self, band):
- if band != self.band_2GHz or band != self.band_5ghz:
- self.fail(msg='Invalid band sent %s' % band)
- self.AddItemToCommandList(self._SetBand, (band,), 1, 900)
-
- def _SetBand(self, band):
- self._SetRadio(enabled=True)
- if band == self.band_2ghz:
- int_value = 0
- wait_for_xpath = 'id("mode_80211_11g")'
- elif band == self.band_5ghz:
- int_value = 1
- wait_for_xpath = 'id("mode_80211_11a")'
- xpath = ('//*[contains(@class, "l_tb")]/input[@value="%d" and @name="band"]'
- % int_value)
- element = self._driver.find_element_by_xpath(xpath)
- element.click()
- try:
- self._wait.until(lambda _:
- self._driver.find_element_by_xpath(wait_for_xpath))
- except selenium.common.exceptions.TimeoutException, e:
- logging.exception('The appropriate mode popup could not be found after '
- 'adjusting the band. WebDriver exception: %s', str(e))
-
- def SetSecurityDisabled(self):
- self.AddItemToCommandList(self._SetSecurityDisabled, (), 1, 900)
-
- def _SetSecurityDisabled(self):
- self._SetRadio(enabled=True)
- self.SelectItemFromPopupByID(self.security_disabled, 'security_type_ap')
-
- def SetSecurityWEP(self, key_value, authentication):
- self.AddItemToCommandList(self._SetSecurityWEP, (key_value, authentication),
- 1, 900)
-
- def _SetSecurityWEP(self, key_value, authentication):
- self._SetRadio(enabled=True)
- self.SelectItemFromPopupByID(self.security_wep, 'security_type_ap',
- wait_for_xpath='id("auth_type")')
- self.SelectItemFromPopupByID(authentication, 'auth_type',
- wait_for_xpath='id("wep_key_value")')
- self.SetContentOfTextFieldByID(key_value, 'wep_key_value')
- self.SetContentOfTextFieldByID(key_value, 'verify_wep_key_value')
-
- def SetSecurityWPAPSK(self, shared_key, update_interval=1800):
- self.AddItemToCommandList(self._SetSecurityWPAPSK,
- (shared_key, update_interval), 1, 900)
-
- def _SetSecurityWPAPSK(self, shared_key, update_interval=1800):
- self._SetRadio(enabled=True)
- self.SelectItemFromPopupByID(self.security_wpapsk, 'security_type_ap',
- wait_for_xpath='id("wpa_mode")')
- self.SelectItemFromPopupByID('WPA Only', 'wpa_mode',
- wait_for_xpath='id("grp_key_interval")')
- self.SetContentOfTextFieldByID(str(update_interval), 'grp_key_interval')
- self.SetContentOfTextFieldByID(shared_key, 'wpapsk1')
-
- def SetVisibility(self, visible=True):
- self.AddItemToCommandList(self._SetVisibility, (visible,), 1, 900)
-
- def _SetVisibility(self, visible=True):
- self._SetRadio(enabled=True)
- # value=0 is visible; value=1 is invisible
- int_value = 0
- if not visible:
- int_value = 1
- xpath = ('//*[contains(@class, "l_tb")]/input[@value="%d" '
- 'and @name="visibility_status"]' % int_value)
- element = self._driver.find_element_by_xpath(xpath)
- element.click()
-
diff --git a/chrome/test/functional/ap_lab/linksys_ap_configurator.py b/chrome/test/functional/ap_lab/linksys_ap_configurator.py
deleted file mode 100644
index bdff34d..0000000
--- a/chrome/test/functional/ap_lab/linksys_ap_configurator.py
+++ /dev/null
@@ -1,195 +0,0 @@
-# Copyright (c) 2012 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.
-
-import logging
-import os
-
-import ap_configurator
-import selenium.common.exceptions
-
-
-class LinksysAPConfigurator(ap_configurator.APConfigurator):
-
- def __init__(self, pyauto_instance, admin_interface_url):
- super(LinksysAPConfigurator, self).__init__(pyauto_instance)
- # Override constants
- self.security_disabled = 'Disabled'
- self.security_wep = 'WEP'
- self.security_wpapsk = 'WPA Personal'
- self.security_wpa2psk = 'WPA2 Personal'
- self.security_wpa8021x = 'WPA Enterprise'
- self.security_wpa28021x = 'WPA2 Enterprise'
-
- self.admin_interface_url = admin_interface_url
-
- def GetRouterName(self):
- return 'Router Name: WRT54G2; Class: LinksysAPConfigurator'
-
- def GetRouterShortName(self):
- return 'WRT54G2'
-
- def GetNumberOfPages(self):
- return 2
-
- def GetSupportedBands(self):
- return [{'band': self.k2GHz,
- 'channels': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]}]
-
- def GetSupportedModes(self):
- return [{'band': self.band_2ghz,
- 'modes': [self.mode_b, self.mode_g, self.mode_b | self.mode_g]}]
-
- def NavigateToPage(self, page_number):
- if page_number == 1:
- self.pyauto_instance.NavigateToURL('http://%s/wireless.htm'
- % self.admin_interface_url)
- elif page_number == 2:
- self.pyauto_instance.NavigateToURL('http://%s/WSecurity.htm'
- % self.admin_interface_url)
- else:
- logging.exception('Invalid page number passed. Number of pages %d, '
- 'page value sent was %d', self.GetNumberOfPages(),
- page_number)
- return False
- return True
-
- def SavePage(self, page_number):
- try:
- self._wait.until(lambda _:
- self._driver.find_element_by_xpath('id("divBT1")'))
- except selenium.common.exceptions.TimeoutException, e:
- logging.exception('Unable to locate the save button.\nWebDriver'
- ' exception: %s', str(e))
- return False
- button = self._driver.find_element_by_xpath('id("divBT1")')
- button.click()
- # Wait for the continue button
- continue_xpath = '//input[@value="Continue" and @type="button"]'
- try:
- self._wait.until(lambda _:
- self._driver.find_element_by_xpath(continue_xpath))
- except selenium.common.exceptions.TimeoutException, e:
- logging.exception('Unable to location the continue button, save probably'
- ' failed.\nWebDriver exception: %s', str(e))
- return False
- button = self._driver.find_element_by_xpath(continue_xpath)
- button.click()
- return True
-
- def SetMode(self, mode, band=None):
- self.AddItemToCommandList(self._SetMode, (mode,), 1, 900)
-
- def _SetMode(self, mode):
- # Different bands are not supported so we ignore.
- # Create the mode to popup item mapping
- mode_mapping = {self.mode_b: 'B-Only', self.mode_g: 'G-Only',
- self.mode_b | self.mode_g: 'Mixed'}
- mode_name = ''
- if mode in mode_mapping.keys():
- mode_name = mode_mapping[mode]
- else:
- logging.exception('The mode selected %d is not supported by router %s.',
- hex(mode), self.getRouterName())
- xpath = ('//select[@onchange="SelWL()" and @name="Mode"]')
- self.SelectItemFromPopupByXPath(mode_name, xpath)
-
- def SetRadio(self, enabled=True):
- # If we are enabling we are activating all other UI components, do it
- # first. Otherwise we are turning everything off so do it last.
- if enabled:
- weight = 1
- else:
- weight = 1000
- self.AddItemToCommandList(self._SetRadio, (enabled,), 1, weight)
-
- def _SetRadio(self, enabled=True):
- xpath = ('//select[@onchange="SelWL()" and @name="Mode"]')
- # To turn off we pick disabled, to turn on we set to G
- if not enabled:
- setting = 'Disabled'
- else:
- setting = 'G-Only'
- self.SelectItemFromPopupByXPath(setting, xpath)
-
- def SetSSID(self, ssid):
- self.AddItemToCommandList(self._SetSSID, (ssid,), 1, 900)
-
- def _SetSSID(self, ssid):
- self._SetRadio(enabled=True)
- xpath = ('//input[@maxlength="32" and @name="SSID"]')
- self.SetConentsOfTextFieldByXPath(ssid, xpath)
-
- def SetChannel(self, channel):
- self.AddItemToCommandList(self._SetChannel, (channel,), 1, 900)
-
- def _SetChannel(self, channel):
- self._SetRadio(enabled=True)
- channel_choices = ['1 - 2.412GHz', '2 - 2.417GHz', '3 - 2.422GHz',
- '4 - 2.427GHz', '5 - 2.432GHz', '6 - 2.437GHz',
- '7 - 2.442GHz', '8 - 2.447GHz', '9 - 2.452GHz',
- '10 - 2.457GHz', '11 - 2.462GHz']
- xpath = ('//select[@onfocus="check_action(this,0)" and @name="Freq"]')
- self.SelectItemFromPopupByXPath(channel_choices[channel - 1], xpath)
-
- def SetBand(self, band):
- return None
-
- def SetSecurityDisabled(self):
- self.AddItemToCommandList(self._SetSecurityDisabled, (), 2, 1000)
-
- def _SetSecurityDisabled(self):
- xpath = ('//select[@name="SecurityMode"]')
- self.SelectItemFromPopupByXPath(self.security_disabled, xpath)
-
- def SetSecurityWEP(self, key_value, authentication):
- self.AddItemToCommandList(self._SetSecurityWEP, (key_value, authentication),
- 2, 1000)
-
- def _SetSecurityWEP(self, key_value, authentication):
- logging.info('This router %s does not support WEP authentication type: %s',
- self.GetRouterName(), authentication)
- popup = '//select[@name="SecurityMode"]'
- try:
- self._wait.until(lambda _: self._driver.find_element_by_xpath(popup))
- except selenium.common.exceptions.TimeoutException, e:
- logging.exception('Unable to find the security mode pop up.\nWebDriver '
- ' exception: %s', str(e))
- text_field = ('//input[@name="wl_passphrase"]')
- self.SelectItemFromPopupByXPath(self.security_wep, popup,
- wait_for_xpath=text_field)
- self.SetConentsOfTextFieldByXPath(key_value, text_field)
- button = self._driver.find_element_by_xpath('//input[@value="Generate"]')
- button.click()
-
- def SetSecurityWPAPSK(self, shared_key, update_interval=1800):
- self.AddItemToCommandList(self._SetSecurityWPAPSK,
- (shared_key, update_interval), 1, 900)
-
- def _SetSecurityWPAPSK(self, shared_key, update_interval=1800):
- popup = '//select[@name="SecurityMode"]'
- try:
- self._wait.until(lambda _: self._driver.find_element_by_xpath(popup))
- except selenium.common.exceptions.TimeoutException, e:
- logging.exception('Unable to find the security mode pop up. WebDriver '
- ' exception: %s', str(e))
- key_field = '//input[@name="PassPhrase"]'
- self.SelectItemFromPopupByXPath(self.security_wpapsk, popup,
- wait_for_xpath=key_field)
- self.SetConentsOfTextFieldByXPath(shared_key, key_field)
- interval_field = ('//input[@name="GkuInterval"]')
- self.SetConentsOfTextFieldByXPath(str(update_interval), interval_field)
-
- def SetVisibility(self, visible=True):
- self.AddItemToCommandList(self._SetVisibility, (visible,), 1, 900)
-
- def _SetVisibility(self, visible=True):
- self._SetRadio(enabled=True)
- # value=1 is visible; value=0 is invisible
- int_value = 1
- if not visible:
- int_value = 0
- xpath = ('//input[@value="%d" and @name="wl_closed"]' % int_value)
- element = self._driver.find_element_by_xpath(xpath)
- element.click()
-
diff --git a/chrome/test/functional/ap_lab/pyauto_ap_configurator.py b/chrome/test/functional/ap_lab/pyauto_ap_configurator.py
deleted file mode 100644
index 3e99a5517..0000000
--- a/chrome/test/functional/ap_lab/pyauto_ap_configurator.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# Copyright (c) 2012 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.
-
-"""Setup for AP Configurator Pyauto tests."""
-
-import os
-import sys
-
-
-def _SetupPaths():
- """Setting path to find pyauto_functional.py."""
- ap_configurator_dir = os.path.abspath(os.path.dirname(__file__))
- sys.path.append(ap_configurator_dir)
- sys.path.append(os.path.normpath(os.path.join(ap_configurator_dir,
- os.pardir)))
-
-_SetupPaths()
-
-
-from pyauto_functional import Main
-
-
-if __name__ == '__main__':
- Main()
diff --git a/chrome/test/functional/apptest.py b/chrome/test/functional/apptest.py
deleted file mode 100644
index 8a6ef83..0000000
--- a/chrome/test/functional/apptest.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# Copyright (c) 2012 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.
-
-import pyauto_functional # must be imported before pyauto
-import pyauto
-
-class PyAutoEventsTest(pyauto.PyUITest):
- """Tests using the event queue."""
-
- def testBasicEvents(self):
- """Basic test for the event queue."""
- url = self.GetHttpURLForDataPath('apptest', 'basic.html')
- driver = self.NewWebDriver()
- event_id = self.AddDomEventObserver(automation_id=4444, recurring=True)
- success_id = self.AddDomEventObserver('test success', automation_id=4444)
- self.NavigateToURL(url)
- self._ExpectEvent(event_id, 'init')
- self._ExpectEvent(event_id, 'login ready')
- driver.find_element_by_id('login').click()
- self._ExpectEvent(event_id, 'login start')
- self._ExpectEvent(event_id, 'login done')
- self.GetNextEvent(success_id)
-
- def testDomMutationEvents(self):
- """Basic tests for WaitForDomNode."""
- url = self.GetHttpURLForDataPath('apptest', 'dom_mutations.html')
- self.NavigateToURL(url)
- self.WaitForDomNode('id("login")', expected_value='Log In')
- self.NewWebDriver().find_element_by_id('login').click()
- self.WaitForDomNode('id("console")', expected_value='.*succeeded.*')
-
- def testDomMutationGenericXPath(self):
- """Test mutation observers with a generic xpath and regexp."""
- url = self.GetHttpURLForDataPath('apptest', 'dom_mutations.html')
- self.NavigateToURL(url)
- self.WaitForDomNode('//a', expected_value='Log In')
- self.NewWebDriver().find_element_by_id('login').click()
- self.WaitForDomNode('//div', expected_value='.*succeeded.*')
-
- def testDomMutationObservers(self):
- """Tests for the various types of Dom Mutation observers."""
- url = self.GetHttpURLForDataPath('apptest', 'dom_mutations.html')
- self.NavigateToURL(url)
- self.GetNextEvent(self.AddDomMutationObserver('add', 'id("login")',
- expected_value='Log In'))
- success_id = self.AddDomMutationObserver('change', 'id("console")',
- expected_value='.*succeeded.*')
- self.NewWebDriver().find_element_by_id('login').click()
- self.GetNextEvent(self.AddDomMutationObserver('remove', 'id("fail")/a'))
- self.GetNextEvent(success_id)
-
- def testWaitUntilNavigationCompletes(self):
- """Basic test for WaitUntilNavigationCompletes."""
- url = self.GetHttpURLForDataPath('apptest', 'dom_mutations.html')
- js = """window.onunload =
- function() {
- window.domAutomationController.send("done");
- };
- window.location.href = "%s";""" % url
- self.ExecuteJavascript(js)
- self.WaitUntilNavigationCompletes()
- self.WaitUntilNavigationCompletes()
- self.WaitForDomNode('id("login")')
-
- def _ExpectEvent(self, event_id, expected_event_name):
- """Checks that the next event is expected."""
- e = self.GetNextEvent(event_id)
- self.assertEqual(e.get('name'), expected_event_name,
- msg="unexpected event: %s" % e)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/autofill.py b/chrome/test/functional/autofill.py
deleted file mode 100755
index a90b491..0000000
--- a/chrome/test/functional/autofill.py
+++ /dev/null
@@ -1,223 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import logging
-import os
-import pickle
-import re
-import simplejson
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-import test_utils
-from selenium.webdriver.common.keys import Keys
-from selenium.webdriver.common.action_chains import ActionChains
-from webdriver_pages import settings
-
-
-class AutofillTest(pyauto.PyUITest):
- """Tests that autofill UI works correctly. Also contains a manual test for
- the crowdsourcing server."""
-
- def setUp(self):
- pyauto.PyUITest.setUp(self)
- self._driver = self.NewWebDriver()
-
- def AutofillCrowdsourcing(self):
- """Test able to send POST request of web form to Autofill server.
-
- The Autofill server processes the data offline, so it can take a few days
- for the result to be detectable. Manual verification is required.
- """
- # HTML file needs to be run from a specific http:// url to be able to verify
- # the results a few days later by visiting the same url.
- url = 'http://www.corp.google.com/~dyu/autofill/crowdsourcing-test.html'
- # Autofill server captures 2.5% of the data posted.
- # Looping 1000 times is a safe minimum to exceed the server's threshold or
- # noise.
- for i in range(1000):
- fname = 'David'
- lname = 'Yu'
- email = 'david.yu@gmail.com'
- # Submit form to collect crowdsourcing data for Autofill.
- self.NavigateToURL(url, 0, 0)
- profile = {'fn': fname, 'ln': lname, 'em': email}
- js = ''.join(['document.getElementById("%s").value = "%s";' %
- (key, value) for key, value in profile.iteritems()])
- js += 'document.getElementById("testform").submit();'
- self.ExecuteJavascript(js)
-
- def _SelectOptionXpath(self, value):
- """Returns an xpath query used to select an item from a dropdown list.
- Args:
- value: Option selected for the drop-down list field.
-
- Returns:
- The value of the xpath query.
- """
- return '//option[@value="%s"]' % value
-
- def testPostalCodeAndStateLabelsBasedOnCountry(self):
- """Verify postal code and state labels based on selected country."""
- data_file = os.path.join(self.DataDir(), 'autofill', 'functional',
- 'state_zip_labels.txt')
- test_data = simplejson.loads(open(data_file).read())
-
- page = settings.AutofillEditAddressDialog.FromNavigation(self._driver)
- # Initial check of State and ZIP labels.
- self.assertEqual('State', page.GetStateLabel())
- self.assertEqual('ZIP code', page.GetPostalCodeLabel())
-
- for country_code in test_data:
- page.Fill(country_code=country_code)
-
- # Compare postal code labels.
- actual_postal_label = page.GetPostalCodeLabel()
- self.assertEqual(
- test_data[country_code]['postalCodeLabel'],
- actual_postal_label,
- msg=('Postal code label "%s" does not match Country "%s"' %
- (actual_postal_label, country_code)))
-
- # Compare state labels.
- actual_state_label = page.GetStateLabel()
- self.assertEqual(
- test_data[country_code]['stateLabel'],
- actual_state_label,
- msg=('State label "%s" does not match Country "%s"' %
- (actual_state_label, country_code)))
-
- def testNoDuplicatePhoneNumsInPrefs(self):
- """Test duplicate phone numbers entered in prefs are removed."""
- page = settings.AutofillEditAddressDialog.FromNavigation(self._driver)
- non_duplicates = ['111-1111', '222-2222']
- duplicates = ['111-1111']
- page.Fill(phones=non_duplicates + duplicates)
- self.assertEqual(non_duplicates, page.GetPhones(),
- msg='Duplicate phone number in prefs unexpectedly saved.')
-
- def testDisplayLineItemForEntriesWithNoCCNum(self):
- """Verify Autofill creates a line item for CC entries with no CC number."""
- self.NavigateToURL('chrome://settings-frame/autofillEditCreditCard')
- self._driver.find_element_by_id('name-on-card').send_keys('Jane Doe')
- query_month = self._SelectOptionXpath('12')
- query_year = self._SelectOptionXpath('2014')
- self._driver.find_element_by_id('expiration-month').find_element_by_xpath(
- query_month).click()
- self._driver.find_element_by_id('expiration-year').find_element_by_xpath(
- query_year).click()
- self._driver.find_element_by_id(
- 'autofill-edit-credit-card-apply-button').click()
- # Refresh the page to ensure the UI is up-to-date.
- self._driver.refresh()
- list_entry = self._driver.find_element_by_class_name('autofill-list-item')
- self.assertTrue(list_entry.is_displayed)
- self.assertEqual('Jane Doe', list_entry.text,
- msg='Saved CC line item not same as what was entered.')
-
- def _GetElementList(self, container_elem, fields_to_select):
- """Returns all sub elements of specific characteristics.
-
- Args:
- container_elem: An element that contains other elements.
- fields_to_select: A list of fields to select with strings that
- help create an xpath string, which in turn identifies
- the elements needed.
- For example: ['input', 'button']
- ['div[@id]', 'button[@disabled]']
- ['*[class="example"]']
-
- Returns:
- List of all subelements found in the container element.
- """
- self.assertTrue(fields_to_select, msg='No fields specified for selection.')
- fields_to_select = ['.//' + field for field in fields_to_select]
- xpath_arg = ' | '.join(fields_to_select)
- field_elems = container_elem.find_elements_by_xpath(xpath_arg)
- return field_elems
-
- def _GetElementInfo(self, element):
- """Returns visual comprehensive info about an element.
-
- This function identifies the text of the correspoinding label when tab
- ordering fails.
- This info consists of:
- The labels, buttons, ids, placeholder attribute values, or the element id.
-
- Args:
- element: The target element.
-
- Returns:
- A string that identifies the element in the page.
- """
- element_info = ''
- if element.tag_name == 'button':
- element_info = element.text
- element_info = (element_info or element.get_attribute('id') or
- element.get_attribute('placeholder') or
- element.get_attribute('class') or element.id)
- return '%s: %s' % (element.tag_name, element_info)
-
- def _LoadPageAndGetFieldList(self):
- """Navigate to autofillEditAddress page and finds the elements with focus.
-
- These elements are of input, select, and button types.
-
- Returns:
- A list with all elements that can receive focus.
- """
- url = 'chrome://settings-frame/autofillEditAddress'
- self._driver.get(url)
- container_elem = self._driver.find_element_by_id(
- 'autofill-edit-address-overlay')
- # The container element contains input, select and button fields. Some of
- # the buttons are disabled so they are ignored.
- field_list = self._GetElementList(container_elem,
- ['input', 'select',
- 'button[not(@disabled)]'])
- self.assertTrue(field_list, 'No fields found in "%s".' % url)
- return field_list
-
- def testTabOrderForEditAddress(self):
- """Verify the TAB ordering for Edit Address page is correct."""
- tab_press = ActionChains(self._driver).send_keys(Keys.TAB)
- field_list = self._LoadPageAndGetFieldList()
-
- # Creates a dictionary where a field key returns the value of the next field
- # in the field list. The last field of the field list is mapped to the first
- # field of the field list.
- field_nextfield_dict = dict(
- zip(field_list, field_list[1:] + field_list[:1]))
-
- # Wait until a field of |field_list| has received the focus.
- self.WaitUntil(lambda:
- self._driver.switch_to_active_element().id in
- [f.id for f in field_list])
- # The first field is expected to receive the focus.
- self.assertEqual(self._driver.switch_to_active_element().id,
- field_list[0].id,
- msg='The first field did not receive tab focus.')
- for field in field_list:
- tab_press.perform()
- # Wait until a field of |field_list|, other than the current field, has
- # received the focus.
- self.WaitUntil(lambda:
- self._driver.switch_to_active_element().id != field.id and
- self._driver.switch_to_active_element().id in
- [f.id for f in field_list])
-
- self.assertEqual(self._driver.switch_to_active_element().id,
- field_nextfield_dict[field].id,
- msg=('The TAB ordering is broken. Previous field: "%s"\n'
- 'Field expected to receive focus: "%s"\n'
- 'Field that received focus instead: "%s"')
- % (self._GetElementInfo(field),
- self._GetElementInfo(field_nextfield_dict[field]),
- self._GetElementInfo(
- self._driver.switch_to_active_element())))
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_accessibility.py b/chrome/test/functional/chromeos_accessibility.py
deleted file mode 100755
index 0dec404..0000000
--- a/chrome/test/functional/chromeos_accessibility.py
+++ /dev/null
@@ -1,115 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import logging
-import os
-import subprocess
-import sys
-import time
-
-import pyauto_functional
-import pyauto
-
-sys.path.append('/usr/local') # To make autotest libs importable.
-from autotest.cros import cros_ui
-from autotest.cros import cryptohome
-
-
-class AccessibilityTest(pyauto.PyUITest):
- """Tests for Accessibility.
-
- Test various chromeos functionalities while Accessibility is turned on.
- """
- find_test_data_dir = 'find_in_page'
-
- def ShouldAutoLogin(self):
- return False
-
- def setUp(self):
- # We want a clean session_manager instance for every run,
- # so restart ui now.
- cros_ui.stop(allow_fail=True)
- cryptohome.remove_all_vaults()
- cros_ui.start(wait_for_login_prompt=False)
- pyauto.PyUITest.setUp(self)
-
- def tearDown(self):
- self._DisableSpokenFeedback()
- pyauto.PyUITest.tearDown(self)
-
- def _Login(self):
- """Perform login."""
- credentials = self.GetPrivateInfo()['test_google_account']
- self.Login(credentials['username'], credentials['password'])
- logging.info('Logging in as %s' % credentials['username'])
- login_info = self.GetLoginInfo()
- self.assertTrue(login_info['is_logged_in'], msg='Login failed.')
-
- def _LoginWithSpokenFeedback(self):
- self.EnableSpokenFeedback(True)
- self._Login()
- self.assertTrue(self.IsSpokenFeedbackEnabled(),
- msg='Could not enable spoken feedback accessibility mode.')
-
- def _EnableSpokenFeedback(self):
- self.EnableSpokenFeedback(True)
- self.assertTrue(self.IsSpokenFeedbackEnabled(),
- msg='Could not enable spoken feedback accessibility mode.')
-
- def _DisableSpokenFeedback(self):
- self.EnableSpokenFeedback(False)
- self.assertFalse(self.IsSpokenFeedbackEnabled(),
- msg='Could not disable spoken feedback accessibility mode.')
-
- def testCanEnableSpokenFeedback(self):
- """Tests that spoken feedback accessibility mode can be enabled."""
- self._EnableSpokenFeedback()
-
- def testLoginAsGuest(self):
- """Test that Guest user login is possible when Accessibility is on."""
- self._EnableSpokenFeedback()
- self.LoginAsGuest()
- login_info = self.GetLoginInfo()
- self.assertTrue(login_info['is_logged_in'], msg='Not logged in at all.')
- self.assertTrue(login_info['is_guest'], msg='Not logged in as guest.')
- url = self.GetFileURLForDataPath('title1.html')
- self.NavigateToURL(url)
- self.assertEqual(1, self.FindInPage('title')['match_count'],
- msg='Failed to load the page or find the page contents.')
- # crbug.com/129218: adding a volume change functionality to automate this
- # issue. Please note that we don't verify any functionality here.
- default_volume = self.GetVolumeInfo()
- for test_volume in (50.00, 77.00, 85.00, 20.00):
- self.SetVolume(test_volume)
- time.sleep(1)
- self.SetVolume(default_volume.get('volume'))
-
- def testAccessibilityBeforeLogin(self):
- """Test Accessibility before login."""
- self._LoginWithSpokenFeedback()
- self.Logout()
- self.assertFalse(self.GetLoginInfo()['is_logged_in'],
- msg='Still logged in when we should be logged out.')
- self.assertTrue(self.IsSpokenFeedbackEnabled(),
- msg='Spoken feedback accessibility mode disabled after loggin out.')
-
- def testAccessibilityAfterLogin(self):
- """Test Accessibility after login."""
- self._Login()
- self._EnableSpokenFeedback()
-
- def testPagePerformance(self):
- """Test Chrome works fine when Accessibility is on."""
- self._LoginWithSpokenFeedback()
- # Verify that opened tab page behaves normally when Spoken Feedback is
- # enabled. crosbug.com/26731
- url = self.GetFileURLForDataPath(self.find_test_data_dir, 'largepage.html')
- self.NavigateToURL(url)
- self.assertEqual(373, self.FindInPage('daughter of Prince')['match_count'],
- msg='Failed to load the page or find the page contents.')
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_basic.py b/chrome/test/functional/chromeos_basic.py
deleted file mode 100755
index 1071741..0000000
--- a/chrome/test/functional/chromeos_basic.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import pyauto_functional
-import pyauto
-
-
-class ChromeosBasic(pyauto.PyUITest):
- """Basic tests for ChromeOS.
-
- Requires ChromeOS to be logged in.
- """
-
- def testAppendTabs(self):
- """Basic test for primary chrome on ChromeOS (named testing interface)."""
- self.AppendTab(pyauto.GURL('about:version'))
- self.assertEqual(self.GetTabCount(), 2, msg='Expected 2 tabs')
-
- def testRestart(self):
- """Basic test which involves restarting chrome on ChromeOS."""
- file_url = self.GetFileURLForDataPath('title2.html')
- self.NavigateToURL(file_url)
- self.assertEqual(1, len(self.GetHistoryInfo().History()))
- self.RestartBrowser(clear_profile=False)
- self.assertEqual(1, len(self.GetHistoryInfo().History()))
-
- def testSetDownloadShelfVisible(self):
- self.assertFalse(self.IsDownloadShelfVisible())
- self.SetDownloadShelfVisible(True)
- self.assertTrue(self.IsDownloadShelfVisible())
- self.SetDownloadShelfVisible(False)
- self.assertFalse(self.IsDownloadShelfVisible())
-
- def testSetVolume(self):
- """Basic test for setting and getting the volume and mute state."""
- volume_info = self.GetVolumeInfo()
- for mute_setting in (False, True, False):
- self.SetMute(mute_setting)
- self.assertEqual(mute_setting, self.GetVolumeInfo()['is_mute'])
- for volume_setting in (40, 0, 100, 70):
- self.SetVolume(volume_setting)
- self.assertEqual(volume_setting, round(self.GetVolumeInfo()['volume']))
-
- self.SetVolume(volume_info['volume'])
- self.SetMute(volume_info['is_mute'])
- self.assertEqual(volume_info, self.GetVolumeInfo())
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_battery.py b/chrome/test/functional/chromeos_battery.py
deleted file mode 100755
index 1fd613b..0000000
--- a/chrome/test/functional/chromeos_battery.py
+++ /dev/null
@@ -1,124 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import os
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-
-from chromeos.power_strip import PowerStrip
-
-class ChromeosBattery(pyauto.PyUITest):
- """Tests ChromeOS Battery Status.
-
- Preconditions:
- 1) Device under test (DUT) is connected to the LAN via an
- Ethernet-to-USB adapter plugged into one of its USB ports.
- 2) AC power cable is connected to the DUT, and plugged into
- the IP controlled Power Switch, outlet #4, located in the lab.
- 3) Battery is installed in the DUT, and battery is not fully
- discharged.
- 4) Tester should have physical access to the power switch.
-
- Note about time calculation:
- When AC power is turned off or on, the battery will take from 2
- to 60 seconds to calculate the time remaining to empty or full.
- While calculating, the keys 'battery_time_to_full' and
- 'battery_time_to_empty' are absent.
- """
-
- _BATTERY_CONFIG_FILE = os.path.join(pyauto.PyUITest.DataDir(),
- 'pyauto_private', 'chromeos', 'power',
- 'battery_testbed_config')
-
- def setUp(self):
- pyauto.PyUITest.setUp(self)
- self.InitPowerStrip()
-
- def tearDown(self):
- # Leave AC power ON so battery does not discharge between tests
- self._power_strip.PowerOn(self._outlet_battery_full)
- pyauto.PyUITest.tearDown(self)
-
- def InitPowerStrip(self):
- assert os.path.exists(ChromeosBattery._BATTERY_CONFIG_FILE), \
- 'Power Strip configuration file does not exist.'
- power_config = pyauto.PyUITest.EvalDataFrom(
- ChromeosBattery._BATTERY_CONFIG_FILE)
- self._power_strip = PowerStrip(power_config['strip_ip'])
- self._outlet_battery_full = (power_config['configs']
- ['battery_full']
- ['outlet_id'])
-
- def WaitUntilBatteryState(self, ac_power_on, time_key):
- assert self.WaitUntil(lambda: self.BatteryPowerAndChargeStateAgree(
- ac_power_on, time_key), timeout=60, retry_sleep=1), \
- 'Battery charge/discharge time was not calculated.'
- return
-
- def BatteryPowerAndChargeStateAgree(self, ac_power_on, time_key):
- battery_status = self.GetBatteryInfo()
- return (battery_status.get('line_power_on') == ac_power_on and
- time_key in battery_status)
-
- def testBatteryChargesWhenACisOn(self):
- """Calculate battery time to full when AC is ON"""
- # Apply AC power to chromebook with battery.
- self._power_strip.PowerOn(self._outlet_battery_full)
-
- # Get info about charging battery
- self.WaitUntilBatteryState(True,'battery_time_to_full')
- battery_status = self.GetBatteryInfo()
- self.assertTrue(battery_status.get('battery_is_present'),
- msg='Battery is not present.')
- self.assertTrue(battery_status.get('line_power_on'),
- msg='Line power is off.')
- self.assertTrue(battery_status.get('battery_time_to_full') >= 0,
- msg='Battery charge time is negative.')
-
- def testBatteryDischargesWhenACisOff(self):
- """Calculate battery time to empty when AC is OFF"""
- self._power_strip.PowerOff(self._outlet_battery_full)
-
- # Get info about discharging battery
- self.WaitUntilBatteryState(False,'battery_time_to_empty')
- battery_status = self.GetBatteryInfo()
- self.assertTrue(battery_status.get('battery_is_present'),
- msg='Battery is not present.')
- self.assertFalse(battery_status.get('line_power_on'),
- msg='Line power is on.')
- self.assertTrue(battery_status.get('battery_time_to_empty') >= 0,
- msg='Battery discharge time is negative.')
-
- def testBatteryTimesAreDifferent(self):
- """Time to full and time to empty should be different"""
- # Turn AC Power ON
- self._power_strip.PowerOn(self._outlet_battery_full)
-
- # Get charging battery time to full
- self.WaitUntilBatteryState(True,'battery_time_to_full')
- battery_status = self.GetBatteryInfo()
- time_to_full = battery_status.get('battery_time_to_full')
-
- # Turn AC Power OFF
- self._power_strip.PowerOff(self._outlet_battery_full)
-
- # Get discharging battery time to empty
- self.WaitUntilBatteryState(False,'battery_time_to_empty')
- battery_status = self.GetBatteryInfo()
- time_to_empty = battery_status.get('battery_time_to_empty')
-
- # Compare charge to discharge time
- """Confirm that time to full and time to empty are not
- returning the same value, but that the values are
- different (e.g., both are not zero)."""
- self.assertNotEqual(time_to_full, time_to_empty,
- msg='Battery time to full equals time to empty. '
- 'Though very unlikely, this is not impossible. '
- 'If test failed falsely, Kris owes Scott a beer.')
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_browser.py b/chrome/test/functional/chromeos_browser.py
deleted file mode 100755
index d079a83..0000000
--- a/chrome/test/functional/chromeos_browser.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import pyauto_functional # pyauto_functional must come before pyauto.
-import pyauto
-import test_utils
-
-
-class ChromeosBrowserTest(pyauto.PyUITest):
-
- def testCannotCloseLastIncognito(self):
- """Verify that last incognito window cannot be closed if it's the
- last window"""
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
- self.assertTrue(self.GetBrowserInfo()['windows'][1]['incognito'],
- msg='Incognito window is not displayed')
-
- self.CloseBrowserWindow(0)
- info = self.GetBrowserInfo()['windows']
- self.assertEqual(1, len(info))
- url = info[0]['tabs'][0]['url']
- self.assertEqual('chrome://newtab/', url,
- msg='Unexpected URL: %s' % url)
- self.assertTrue(info[0]['incognito'],
- msg='Incognito window is not displayed.')
-
- def testCrashBrowser(self):
- """Verify that after broswer crash is recovered, user can still navigate
- to other URL."""
- test_utils.CrashBrowser(self)
- self.RestartBrowser(clear_profile=False)
- url = self.GetHttpURLForDataPath('english_page.html')
- self.NavigateToURL(url)
- self.assertEqual('This page is in English', self.GetActiveTabTitle())
-
- def testFullScreen(self):
- """Verify that a browser window can enter and exit full screen mode."""
- self.ApplyAccelerator(pyauto.IDC_FULLSCREEN)
- self.assertTrue(self.WaitUntil(lambda:
- self.GetBrowserInfo()['windows'][0]['fullscreen']),
- msg='Full Screen is not displayed.')
-
- self.ApplyAccelerator(pyauto.IDC_FULLSCREEN)
- self.assertTrue(self.WaitUntil(lambda: not
- self.GetBrowserInfo()['windows'][0]['fullscreen']),
- msg='Normal screen is not displayed.')
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_crosh.py b/chrome/test/functional/chromeos_crosh.py
deleted file mode 100755
index 690c1ef..0000000
--- a/chrome/test/functional/chromeos_crosh.py
+++ /dev/null
@@ -1,174 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import os
-
-import pyauto_functional # must be imported before pyauto
-import pyauto
-import test_utils
-
-
-class CroshTest(pyauto.PyUITest):
- """Tests for crosh."""
-
- def setUp(self):
- """Close all windows at startup."""
- pyauto.PyUITest.setUp(self)
- for _ in range(self.GetBrowserWindowCount()):
- self.CloseBrowserWindow(0)
-
- def testBasic(self):
- """Verify crosh basic flow."""
- test_utils.OpenCroshVerification(self)
-
- # Verify crosh prompt.
- self.WaitForHtermText(text='crosh> ',
- msg='Could not find "crosh> " prompt')
- self.assertTrue(
- self.GetHtermRowsText(start=0, end=2).endswith('crosh> '),
- msg='Could not find "crosh> " prompt')
-
- # Run a crosh command.
- self.SendKeysToHterm('help\\n')
- self.WaitForHtermText(text='help_advanced',
- msg='Could not find "help_advanced" in help output.')
-
- # Exit crosh and close tab.
- self.SendKeysToHterm('exit\\n')
- self.WaitForHtermText(text='command crosh completed with exit code 0',
- msg='Could not exit crosh.')
-
- def testAddBookmark(self):
- """Test crosh URL can be bookmarked"""
- test_utils.OpenCroshVerification(self)
-
- # Add bookmark.
- bookmarks = self.GetBookmarkModel()
- bar_id = bookmarks.BookmarkBar()['id']
- name = 'crosh'
- url = self.GetActiveTabURL()
- count = bookmarks.NodeCount()
- self.AddBookmarkURL(bar_id, 0, name, url.spec())
- bookmarks = self.GetBookmarkModel()
- node = bookmarks.BookmarkBar()['children'][0]
- self.assertEqual(count + 1, bookmarks.NodeCount())
- self.assertEqual(node['type'], 'url')
- self.assertEqual(node['name'], name)
- self.assertEqual(url.spec(), node['url'])
-
- def testMultipleWindowCrosh(self):
- """Test that crosh can be opened in multiple windows."""
- test_utils.OpenCroshVerification(self)
-
- for windex in range (1, 4): # 3 new windows
- self.OpenNewBrowserWindow(True)
- self.OpenCrosh()
- self.assertEqual('crosh', self.GetActiveTabTitle())
-
- # Verify crosh prompt.
- self.WaitForHtermText(text='crosh> ', tab_index=1, windex=windex,
- msg='Could not find "crosh> " prompt')
- self.assertTrue(
- self.GetHtermRowsText(start=0, end=2, tab_index=1,
- windex=windex).endswith('crosh> '),
- msg='Could not find "crosh> " prompt')
-
- # Exit crosh.
- self.SendKeysToHterm('exit\\n', tab_index=1, windex=windex)
- self.WaitForHtermText(text='command crosh completed with exit code 0',
- tab_index=1, windex=windex,
- msg='Could not exit crosh.')
-
- def testShell(self):
- """Test shell can be opened in crosh."""
- test_utils.OpenCroshVerification(self)
-
- # Verify crosh prompt.
- self.WaitForHtermText(text='crosh> ',
- msg='Could not find "crosh> " prompt')
- self.assertTrue(
- self.GetHtermRowsText(start=0, end=2).endswith('crosh> '),
- msg='Could not find "crosh> " prompt')
-
- # Run a shell command.
- self.SendKeysToHterm(r'shell\n')
- self.WaitForHtermText(text='chronos@localhost',
- msg='Could not find "chronos@localhost" in shell output.')
-
- def testConnectToAnotherhost(self):
- """Test ssh to another host."""
- test_utils.OpenCroshVerification(self)
-
- # Verify crosh prompt.
- self.WaitForHtermText(text='crosh> ',
- msg='Could not find "crosh> " prompt')
- self.assertTrue(
- self.GetHtermRowsText(start=0, end=2).endswith('crosh> '),
- msg='Could not find "crosh> " prompt')
-
- # Ssh to another host: chronos@localhost.
- self.SendKeysToHterm(r'ssh chronos@localhost\n')
- self.WaitForHtermText(text='Password',
- msg='Could not find "Password" in shell output.')
- self.SendKeysToHterm(r'test0000\n')
- self.WaitForHtermText(text='chronos@localhost',
- msg='Could not find "chronos@localhost" in shell output.')
-
- def testTabSwitching(self):
- """Test tab can be switched in crosh."""
- test_utils.OpenCroshVerification(self)
-
- # Open 6 tabs
- for x in xrange(3):
- self.AppendTab(self.GetHttpURLForDataPath('title2.html'))
- self.assertEqual('Title Of Awesomeness', self.GetActiveTabTitle(),
- msg='Unable to navigate to title2.html and '
- 'verify tab title.')
- self.OpenCrosh()
- self.assertEqual(7, len(self.GetBrowserInfo()['windows'][0]['tabs']))
-
- # Select tab 5
- self.ApplyAccelerator(pyauto.IDC_SELECT_TAB_4)
- self.assertEqual('crosh', self.GetActiveTabTitle(),
- msg='Unable to naviage to crosh.')
-
- # Run a crosh command.
- self.SendKeysToHterm('help\\n', tab_index=4, windex=0)
- self.WaitForHtermText(text='help_advanced', tab_index=4, windex=0,
- msg='Could not find "help_advanced" in help output.')
-
- def testLargefileCrosh(self):
- """Test large file is displayed in crosh."""
- test_utils.OpenCroshVerification(self)
-
- # Verify crosh prompt.
- self.WaitForHtermText(text='crosh> ',
- msg='Could not find "crosh> " prompt')
- self.assertTrue(
- self.GetHtermRowsText(start=0, end=2).endswith('crosh> '),
- msg='Could not find "crosh> " prompt')
-
- # Login to localhost.
- self.SendKeysToHterm(r'ssh chronos@localhost\n')
- self.WaitForHtermText(text='Password',
- msg='Could not find "Password" in shell output.')
- self.SendKeysToHterm(r'test0000\n')
- self.WaitForHtermText(text='chronos@localhost',
- msg='Could not find "chronos@localhost" in shell output.')
-
- # Create a file with 140 characters per line, 50000 lines.
- bigfn = '/tmp/bigfile.txt'
- with open(bigfn, 'w') as file:
- file.write(('0' * 140 + '\n') * 50000 + 'complete\n')
-
- # Cat a large file.
- self.SendKeysToHterm(r'cat %s\n' % bigfn)
- self.WaitForHtermText(text='complete',
- msg='Could not find "complete" in shell output.')
- os.remove(bigfn)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_longterm_test.py b/chrome/test/functional/chromeos_longterm_test.py
deleted file mode 100755
index b25a350..0000000
--- a/chrome/test/functional/chromeos_longterm_test.py
+++ /dev/null
@@ -1,131 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (c) 2011 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.
-
-import logging
-import time
-
-import pyauto_functional
-import pyauto
-import pyauto_utils
-import timer_queue
-
-
-class ChromeOSLongTerm(pyauto.PyUITest):
- """Set of long running tests for ChromeOS.
-
- This class is comprised of several tests that perform long term tests.
- """
-
- def _ActivateTabWithURL(self, url):
- """Activates the window that has the given tab url.
-
- Args:
- url: The url of the tab to find.
-
- Returns:
- An array of the index values of the tab and window. Returns None if the
- tab connot be found.
- """
- info = self.GetBrowserInfo()
- windows = info['windows']
- for window_index, window in enumerate(windows):
- tabs = window['tabs']
- for tab_index, tab in enumerate(tabs):
- tab['url'] = tab['url'].strip('/')
- if tab['url'] == url:
- self.ActivateTab(tab_index, window_index)
- return [tab_index, window_index]
- return None
-
- def _SetupLongTermWindow(self, long_term_pages):
- """Appends a list of tab to the current active window.
-
- Args:
- long_term_pages: The list of urls to open.
- """
- for url in long_term_pages:
- self.AppendTab(pyauto.GURL(url))
-
- def _RefreshLongTermWindow(self, long_term_pages):
- """ Refreshes all of the tabs from the given list.
-
- Args:
- long_term_pages: The list of urls to refresh.
- """
- for page in long_term_pages:
- long_index = self._ActivateTabWithURL(page)
- if not long_index:
- logging.info('Unable to find page with url: %s.')
- else:
- self.ActivateTab(long_index[0], long_index[1])
- self.ReloadActiveTab(long_index[1])
-
- def _ConfigureNewWindow(self, pages, incognito=False):
- """Setups a windows with multiple tabs running.
-
- This method acts as a state machine. If a window containing a tab with the
- url of the first item of pages it closes that window. If that window
- cannot be found then a new window with the urls in pages is opened.
-
- Args:
- pages: The list of urls to load.
- """
- page_index = self._ActivateTabWithURL(pages[0])
- if not page_index:
- # This means the pages do not exist, load them
- if incognito:
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
- else:
- self.OpenNewBrowserWindow(True)
- for url in pages:
- self.AppendTab(pyauto.GURL(url), self.GetBrowserWindowCount() - 1)
- # Cycle through the pages to make sure they render
- win = self.GetBrowserInfo()['windows'][self.GetBrowserWindowCount() - 1]
- for tab in win['tabs']:
- self.ActivateTab(tab['index'], self.GetBrowserWindowCount() - 1)
- # Give the plugin time to activate
- time.sleep(1.5)
- else:
- self.CloseBrowserWindow(page_index[1])
-
- def testLongTerm(self):
- """Main entry point for the long term tests.
-
- This method will spin in a while loop forever until it encounters a keyboard
- interrupt. Other worker methods will be managed by the TimerQueue.
- """
- long_term_pages = ['http://news.google.com', 'http://www.engadget.com',
- 'http://www.washingtonpost.com']
-
- flash_pages = [
- 'http://www.craftymind.com/factory/guimark2/FlashChartingTest.swf',
- 'http://www.craftymind.com/factory/guimark2/FlashGamingTest.swf',
- 'http://www.craftymind.com/factory/guimark2/FlashTextTest.swf']
-
- incognito_pages = ['http://www.msn.com', 'http://www.ebay.com',
- 'http://www.bu.edu', 'http://www.youtube.com']
-
- start_time = time.time()
- self._SetupLongTermWindow(long_term_pages)
- timers = timer_queue.TimerQueue()
- timers.AddTimer(self._ConfigureNewWindow, 90, args=(flash_pages,))
- timers.AddTimer(self._RefreshLongTermWindow, 30, args=(long_term_pages,))
- timers.AddTimer(self._ConfigureNewWindow, 15, args=(incognito_pages, True))
- timers.start()
- try:
- while True:
- if not timers.is_alive():
- logging.error('Timer queue died, shutting down.')
- return
- time.sleep(1)
-
- except KeyboardInterrupt:
- # Kill the timers
- timers.Stop()
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_power.py b/chrome/test/functional/chromeos_power.py
deleted file mode 100755
index b14886d..0000000
--- a/chrome/test/functional/chromeos_power.py
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import logging
-
-import pyauto_functional
-import pyauto
-
-
-class ChromeosPower(pyauto.PyUITest):
- """Tests for ChromeOS power library and daemon."""
-
- def testBatteryInfo(self):
- """Print some information about the battery."""
- result = self.GetBatteryInfo()
- self.assertTrue(result)
- logging.debug(result)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_prefs.py b/chrome/test/functional/chromeos_prefs.py
deleted file mode 100755
index f6b8e64..0000000
--- a/chrome/test/functional/chromeos_prefs.py
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import os
-import sys
-import time
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-
-sys.path.append('/usr/local') # Required to import autotest libs
-from autotest.cros import constants
-
-
-class ChromeosPrefsTest(pyauto.PyUITest):
- """TestCase for ChromeOS Preferences."""
-
- # Defined in src/chrome/browser/chromeos/login/user_manager.cc
- k_logged_in_users = 'LoggedInUsers'
- k_user_images = 'UserImages'
- k_image_path_node_name = 'path'
-
- def testAllUserImage(self):
- """Verify changing all available default user images in Change picture."""
-
- logged_in_user = constants.CREDENTIALS['$default'][0]
- for i in range(19):
- image = {
- "index": i,
- "path": ""
- }
- user_images = {}
- user_images[logged_in_user] = image
- self.SetLocalStatePrefs(ChromeosPrefsTest.k_user_images, user_images)
- self.RestartBrowser(clear_profile=False)
- current_user_images = self.GetLocalStatePrefsInfo().Prefs(
- ChromeosPrefsTest.k_user_images)
- current_image = current_user_images.get(logged_in_user)
- self.assertEqual(image, current_image,
- msg='Default user image was not set in preferences.')
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_security.py b/chrome/test/functional/chromeos_security.py
deleted file mode 100755
index b541451..0000000
--- a/chrome/test/functional/chromeos_security.py
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import os
-
-import pyauto_functional
-import pyauto
-
-
-class ChromeosSecurity(pyauto.PyUITest):
- """Security tests for chrome on ChromeOS.
-
- Requires ChromeOS to be logged in.
- """
-
- def ExtraChromeFlags(self):
- """Override default list of extra flags typically used with automation.
-
- See the default flags used with automation in pyauto.py.
- Chrome flags for this test should be as close to reality as possible.
- """
- return [
- '--homepage=about:blank',
- ]
-
- def testCannotViewLocalFiles(self):
- """Verify that local files cannot be accessed from the browser."""
- urls_and_titles = {
- 'file:///': 'Index of /',
- 'file:///etc/': 'Index of /etc/',
- self.GetFileURLForDataPath('title2.html'): 'Title Of Awesomeness',
- }
- for url, title in urls_and_titles.iteritems():
- self.NavigateToURL(url)
- self.assertNotEqual(title, self.GetActiveTabTitle(),
- msg='Could access local file %s.' % url)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_time.py b/chrome/test/functional/chromeos_time.py
deleted file mode 100755
index 4cd42e4..0000000
--- a/chrome/test/functional/chromeos_time.py
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import logging
-import sys
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-
-sys.path.append('/usr/local') # To make autotest libs importable.
-from autotest.cros import cros_ui
-from autotest.cros import ownership
-
-
-class ChromeosTime(pyauto.PyUITest):
- """Tests for the ChromeOS status area clock and timezone settings."""
-
- def setUp(self):
- cros_ui.fake_ownership()
- pyauto.PyUITest.setUp(self)
- self._initial_timezone = self.GetTimeInfo()['timezone']
-
- def tearDown(self):
- self.SetTimezone(self._initial_timezone)
- pyauto.PyUITest.tearDown(self)
- ownership.clear_ownership()
-
- def testTimeInfo(self):
- """Print the the display time, date, and timezone."""
- logging.debug(self.GetTimeInfo())
-
- def testSetTimezone(self):
- """Sanity test to make sure setting the timezone works."""
- self.SetTimezone('America/Los_Angeles')
- pacific_time = self.GetTimeInfo()['display_time']
- self.SetTimezone('America/New_York')
- eastern_time = self.GetTimeInfo()['display_time']
-
- self.assertNotEqual(pacific_time, eastern_time,
- 'Time zone changed but display time did not.')
-
- def _IsTimezoneEditable(self):
- """Check if the timezone is editable.
-
- It will navigate to the system settings page and verify that the
- timezone settings drop down is not disabled.
-
- Returns:
- True, if timezone dropdown is enabled
- False, otherwise
- """
- self.NavigateToURL('chrome://settings-frame')
- ret = self.ExecuteJavascript("""
- var disabled = true;
- var timezone = document.getElementById('timezone-select');
- if (timezone)
- disabled = timezone.disabled;
- domAutomationController.send(disabled.toString());
- """)
- return ret == 'false'
-
- def testTimezoneIsEditable(self):
- """Test that the timezone is always editable."""
- # This test only makes sense if we are not running as the owner.
- self.assertFalse(self.GetLoginInfo()['is_owner'])
- editable = self._IsTimezoneEditable()
- self.assertTrue(editable, msg='Timezone is not editable when not owner.')
-
- def _SetTimezoneInUI(self, timezone):
- self.NavigateToURL('chrome://settings-frame/settings')
- self.ExecuteJavascript("""
- var selectElement = document.getElementById('timezone-select');
- selectElement.value = "%s";
- var event = document.createEvent("HTMLEvents");
- event.initEvent("change", true, true);
- selectElement.dispatchEvent(event);
- domAutomationController.send("");
- """ % timezone)
-
- def testSetTimezoneUI(self):
- """Test that the timezone UI changes internal settings.
-
- Set the Timezone on the settings page. Check the internal timezone
- afterwards. Timezones should be always editable."""
-
- for timezone in ['America/Barbados', 'Europe/Helsinki']:
- self._SetTimezoneInUI(timezone)
- self.assertTrue(self.WaitUntil(lambda: self.GetTimeInfo()['timezone'],
- expect_retval=timezone),
- 'Timezone not changed as expected.');
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_volume.py b/chrome/test/functional/chromeos_volume.py
deleted file mode 100755
index 52b8f0e..0000000
--- a/chrome/test/functional/chromeos_volume.py
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import logging
-import os
-import subprocess
-import sys
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-
-sys.path.append('/usr/local') # To make autotest libs importable.
-from autotest.cros import cros_ui
-from autotest.cros import cryptohome
-
-
-class ChromeosVolume(pyauto.PyUITest):
- """Test case for volume levels.
-
- Test volume and mute changes with different state like, login,
- lock, logout, etc...
- """
-
- def setUp(self):
- # We want a clean session_manager instance for every run,
- # so restart ui now.
- cros_ui.stop(allow_fail=True)
- cryptohome.remove_all_vaults()
- cros_ui.start(wait_for_login_prompt=False)
- pyauto.PyUITest.setUp(self)
- self._initial_volume_info = self.GetVolumeInfo()
-
- def tearDown(self):
- self.SetVolume(self._initial_volume_info['volume'])
- self.SetMute(self._initial_volume_info['is_mute'])
- pyauto.PyUITest.tearDown(self)
-
- def ShouldAutoLogin(self):
- return False
-
- def _Login(self):
- """Perform login"""
- credentials = self.GetPrivateInfo()['test_google_account']
- self.Login(credentials['username'], credentials['password'])
- logging.info('Logged in as %s' % credentials['username'])
- login_info = self.GetLoginInfo()
- self.assertTrue(login_info['is_logged_in'], msg='Login failed.')
-
- def testDefaultVolume(self):
- """Test the default volume settings"""
- self._Login()
- board_name = self.ChromeOSBoard()
- default_volume = self.GetPrivateInfo()['default_volume']
- assert default_volume.get(board_name), \
- 'No volume settings available for %s.' % board_name
- expected = {u'volume': default_volume[board_name],
- u'is_mute': default_volume['is_mute']}
- volume = self.GetVolumeInfo()
- self.assertEqual(volume.get('is_mute'), expected.get('is_mute'))
- self.assertAlmostEqual(volume.get('volume'), expected.get('volume'),
- msg='Volume settings are set to %s, not matching with default '
- 'volume settings %s.' % (volume, expected))
-
- def testLoginLogoutVolume(self):
- """Test that volume settings are preserved after login and logout"""
- before_login = self.GetVolumeInfo()
- self._Login()
- after_login = self.GetVolumeInfo()
- self.assertEqual(before_login, after_login,
- msg='Before login : %s and after login : %s, volume states are not '
- 'matching' % (before_login, after_login))
- self.Logout()
- after_logout = self.GetVolumeInfo()
- self.assertEqual(after_login, after_logout,
- msg='Before logout : %s and after logout : %s, volume states are not '
- 'matching' % (after_login, after_logout))
-
- def testLoginLockoutVolume(self):
- """Test that volume changes on the lock screen, are preserved"""
- lock_volume = {u'volume': 50.000000000000014, u'is_mute': True}
- self._Login()
- login_vol = self.GetVolumeInfo()
- self.LockScreen()
- self.SetVolume(lock_volume['volume'])
- self.SetMute(lock_volume['is_mute'])
- self.UnlockScreen(self.GetPrivateInfo()['test_google_account']['password'])
- after_login = self.GetVolumeInfo()
- self.assertEqual(lock_volume, after_login,
- msg='Locking screen volume changes are not preserved')
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromoting/__init__.py b/chrome/test/functional/chromoting/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/chrome/test/functional/chromoting/__init__.py
+++ /dev/null
diff --git a/chrome/test/functional/chromoting/auth.py b/chrome/test/functional/chromoting/auth.py
deleted file mode 100755
index 283b339..0000000
--- a/chrome/test/functional/chromoting/auth.py
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Chromoting authentication related test cases."""
-
-import chromoting_base
-import pyauto
-
-
-class ChromotingAuth(chromoting_base.ChromotingBase):
- """Chromoting authentication related test cases."""
-
- def setUp(self):
- """Set up for auth test."""
- pyauto.PyUITest.setUp(self)
-
- webapp = self.InstallExtension(self.GetWebappPath())
- self.host.LaunchApp(webapp)
- self.account = self.GetPrivateInfo()['test_chromoting_account']
-
- def testDenyAllowAccess(self):
- """Denies access and then allows access."""
- self.host.ContinueAuth()
- self.host.SignIn(self.account['username'], self.account['password'])
- self.host.DenyAccess()
- self.host.ContinueAuth()
- self.host.AllowAccess()
-
- def testSignOutAndSignBackIn(self):
- """Signs out from chromoting and signs back in."""
- self.host.ContinueAuth()
- self.host.SignIn(self.account['username'], self.account['password'])
- self.host.AllowAccess()
- self.host.SignOut()
- self.host.ContinueAuth()
- self.host.AllowAccess()
-
-
-if __name__ == '__main__':
- chromoting_base.Main()
diff --git a/chrome/test/functional/chromoting/chromoting_base.py b/chrome/test/functional/chromoting/chromoting_base.py
deleted file mode 100644
index b7dafb6..0000000
--- a/chrome/test/functional/chromoting/chromoting_base.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright (c) 2012 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.
-
-"""Common imports, setup, etc for chromoting tests."""
-
-import os
-
-
-def _SetupPaths():
- """Add chrome/test/functional to sys.path for importing pyauto_functional"""
- functional_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
- os.sys.path.append(functional_dir)
-
-_SetupPaths()
-
-
-import pyauto_functional # Must come before chromoting and pyauto.
-from pyauto_functional import Main
-import pyauto
-import chromotinglib
-
-
-class ChromotingBase(chromotinglib.ChromotingMixIn, pyauto.PyUITest):
- """Chromoting pyauto test base class.
-
- The following member variables can be used in the child classes:
- client_local: True if the client is on the same machines as host
- host: The chromoting host side, instance of ChromotingBase
- client: The chromoting client side, intance of ChromotingBase
- client_tab_index: The tab index to the chromoting client tab
- """
- def __init__(self, methodName):
- pyauto.PyUITest.__init__(self, methodName)
-
- self.client_local = (self.remote == None)
- self.host = self
- self.client = self if self.client_local else self.remote
- self.client_tab_index = 2 if self.client_local else 1
-
- def ExtraChromeFlags(self):
- """Add extra flags for chromoting testing.
-
- Add --allow-nacl-socket-api to connect chromoting successfully.
- """
- extra_chrome_flags = ['--allow-nacl-socket-api=*']
- return pyauto.PyUITest.ExtraChromeFlags(self) + extra_chrome_flags
diff --git a/chrome/test/functional/chromoting/it2me_basic.py b/chrome/test/functional/chromoting/it2me_basic.py
deleted file mode 100755
index 2661e52..0000000
--- a/chrome/test/functional/chromoting/it2me_basic.py
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Basic tests for Chromoting it2me."""
-
-import chromoting_base
-import pyauto
-
-
-class IT2MeBasic(chromoting_base.ChromotingBase):
- """Drives it2me basic test cases."""
-
- def setUp(self):
- """Set up for it2me basic test."""
- # Disable test on vista and xp until the failure is figured
- if self.IsWinVista() or self.IsWinXP():
- return
-
- pyauto.PyUITest.setUp(self)
-
- webapp = self.InstallExtension(self.GetWebappPath())
- self.LaunchApp(webapp)
- self.Authenticate()
-
- if self.client_local:
- self.client.LaunchApp(webapp)
-
- def testIT2MeBasic(self):
- """Verify that we can start and disconnect a Chromoting it2me session."""
- # Disable test on vista and xp until the failure is figured
- if self.IsWinVista() or self.IsWinXP():
- return
-
- access_code = self.host.Share()
- self.assertTrue(access_code,
- msg='Host attempted to share, but it failed. '
- 'No access code was found.')
-
- self.client.Connect(access_code, self.client_tab_index)
-
- self.host.CancelShare()
- self.client.Disconnect(self.client_tab_index)
-
-
-if __name__ == '__main__':
- chromoting_base.Main()
diff --git a/chrome/test/functional/chromoting/me2me_connect.py b/chrome/test/functional/chromoting/me2me_connect.py
deleted file mode 100755
index 5f6b980..0000000
--- a/chrome/test/functional/chromoting/me2me_connect.py
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Chromoting me2me connect/disconnect related test cases."""
-
-import chromoting_base
-import pyauto
-
-
-class Me2MeConnect(chromoting_base.ChromotingBase):
- """Drives me2me connect test cases."""
-
- def setUp(self):
- """Set up for me2me connect test."""
- # Disable test on vista and xp until the failure is figured
- if self.IsWinVista() or self.IsWinXP():
- return
-
- pyauto.PyUITest.setUp(self)
-
- self.InstallHostDaemon()
- webapp = self.InstallExtension(self.GetWebappPath())
- self.host.LaunchApp(webapp)
- self.host.Authenticate()
- self.host.StartMe2Me()
- self.host.CleanupHostList()
- self.host.EnableConnectionsInstalled()
- self.client.LaunchApp(webapp)
-
- def tearDown(self):
- """Mainly uninstalls the host daemon."""
- # Disable test on vista and xp until the failure is figured
- if self.IsWinVista() or self.IsWinXP():
- return
-
- self.host.DisableConnections()
- self.UninstallHostDaemon()
-
- pyauto.PyUITest.tearDown(self)
-
-
- def testMe2MeConnectDisconnectReconnectDisconnect(self):
- """Connects, disconnects, reconnects and disconnects"""
- # Disable test on vista and xp until the failure is figured
- if self.IsWinVista() or self.IsWinXP():
- return
-
- self.client.ConnectMe2Me('111111', 'IN_SESSION',
- self.client_tab_index)
- self.client.DisconnectMe2Me(False, self.client_tab_index)
- self.client.ReconnectMe2Me('111111', self.client_tab_index)
- self.client.DisconnectMe2Me(True, self.client_tab_index)
-
- def testMe2MeConnectWithWrongPin(self):
- """Connects and disconnects."""
- # Disable test on vista and xp until the failure is figured
- if self.IsWinVista() or self.IsWinXP():
- return
-
- self.client.ConnectMe2Me('222222', 'CLIENT_CONNECT_FAILED_ME2ME',
- self.client_tab_index)
- self.client.ReconnectMe2Me('111111', self.client_tab_index)
- self.client.DisconnectMe2Me(True, self.client_tab_index)
-
- def testMe2MeChangePin(self):
- """Changes pin, connects with new pin and then disconnects."""
- # Disable test on vista and xp until the failure is figured
- if self.IsWinVista() or self.IsWinXP():
- return
-
- self.host.ChangePin('222222')
- self.client.ConnectMe2Me('222222', 'IN_SESSION',
- self.client_tab_index)
- self.client.DisconnectMe2Me(True, self.client_tab_index)
-
- def testMe2MeChangeName(self):
- """Changes host name, connects and then disconnects."""
- # Disable test on vista and xp until the failure is figured
- if self.IsWinVista() or self.IsWinXP():
- return
-
- self.client.ChangeName("Changed")
- self.client.ConnectMe2Me('111111', 'IN_SESSION',
- self.client_tab_index)
- self.client.DisconnectMe2Me(True, self.client_tab_index)
-
-
-if __name__ == '__main__':
- chromoting_base.Main()
diff --git a/chrome/test/functional/chromoting/me2me_enable.py b/chrome/test/functional/chromoting/me2me_enable.py
deleted file mode 100755
index 283f8f6..0000000
--- a/chrome/test/functional/chromoting/me2me_enable.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Chromoting me2me enable/disable related test cases."""
-
-import chromoting_base
-import pyauto
-
-
-class Me2MeEnable(chromoting_base.ChromotingBase):
- """Drives the me2me enable test cases."""
-
- def setUp(self):
- """Set up for me2me enable test."""
- # Disable test on vista and xp until the failure is figured
- if self.IsWinVista() or self.IsWinXP():
- return
-
- pyauto.PyUITest.setUp(self)
-
- self.InstallHostDaemon()
- webapp = self.InstallExtension(self.GetWebappPath())
- self.host.LaunchApp(webapp)
- self.host.Authenticate()
- self.host.StartMe2Me()
-
- def tearDown(self):
- """Mainly uninstalls the host daemon."""
- # Disable test on vista and xp until the failure is figured
- if self.IsWinVista() or self.IsWinXP():
- return
-
- self.UninstallHostDaemon()
-
- pyauto.PyUITest.tearDown(self)
-
- def testMe2MeEnableDisable(self):
- """Enables/disables remote connections.
-
- This test also exercises different pin conditions.
- """
- # Disable test on vista and xp until the failure is figured
- if self.IsWinVista() or self.IsWinXP():
- return
-
- self.host.EnableConnectionsInstalled(True)
- self.host.DisableConnections()
-
-
-if __name__ == '__main__':
- chromoting_base.Main()
diff --git a/chrome/test/functional/codesign.py b/chrome/test/functional/codesign.py
deleted file mode 100755
index e942a4b..0000000
--- a/chrome/test/functional/codesign.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import commands
-import glob
-import logging
-import os
-import sys
-import unittest
-
-import pyauto_functional # Must import before pyauto
-import pyauto
-
-class CodesignTest(pyauto.PyUITest):
- """Test if the build is code signed"""
-
- def testCodeSign(self):
- """Check the app for codesign and bail out if it's non-branded."""
- browser_info = self.GetBrowserInfo()
-
- # bail out if not a branded build
- if browser_info['properties']['branding'] != 'Google Chrome':
- return
-
- # TODO: Add functionality for other operating systems (see crbug.com/47902)
- if self.IsMac():
- self._MacCodeSign(browser_info)
-
- def _MacCodeSign(self, browser_info):
- valid_text = 'valid on disk'
- app_name = 'Google Chrome.app'
-
- # Codesign of the app @ xcodebuild/Release/Google Chrome.app/
- app_path = browser_info['child_process_path']
- app_path = app_path[:app_path.find(app_name)]
- app_path = app_path + app_name
- self.assertTrue(valid_text in self._checkCodeSign(app_path))
-
- # Codesign of the frameWork
- framework_path = glob.glob(os.path.join(app_path, 'Contents', 'Versions',
- '*.*.*.*'))[0]
- framework_path = os.path.join(framework_path,
- 'Google Chrome Framework.framework')
- self.assertTrue(valid_text in self._checkCodeSign(framework_path))
-
- def _checkCodeSign(self, file_path):
- """Return the output of the codesign"""
- return commands.getoutput('codesign -vvv "%s"' % file_path)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/crash_reporter.py b/chrome/test/functional/crash_reporter.py
deleted file mode 100755
index 0e58bd1..0000000
--- a/chrome/test/functional/crash_reporter.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import glob
-import os
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-import pyauto_utils
-
-
-class CrashReporterTest(pyauto.PyUITest):
- """TestCase for Crash Reporter."""
-
- def testRendererCrash(self):
- """Verify renderer's crash reporting.
-
- Attempts to crash, and then checks that crash dumps get generated. Does
- not actually test crash reports on the server.
- """
- # Bail out if not a branded build
- properties = self.GetBrowserInfo()['properties']
- if properties['branding'] != 'Google Chrome':
- return
-
- # Make sure Chrome minidumps are enabled on Chrome OS
- if self.IsChromeOS():
- minidumps_file = '/mnt/stateful_partition/etc/enable_chromium_minidumps'
- assert os.path.exists(minidumps_file), 'Chrome minidumps are not enabled.'
-
- breakpad_folder = properties['DIR_CRASH_DUMPS']
- self.assertTrue(breakpad_folder, 'Cannot figure crash dir')
-
- unused = pyauto_utils.ExistingPathReplacer(path=breakpad_folder)
- # If the temp dir was created as root on chromeos, make sure chronos can
- # write to it
- if self.IsChromeOS() and os.geteuid() == 0:
- os.chown(breakpad_folder, 1000, 1000)
- self.NavigateToURL('about:crash') # Trigger renderer crash
- dmp_files = glob.glob(os.path.join(breakpad_folder, '*.dmp'))
- self.assertEqual(1, len(dmp_files))
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/execute_javascript.py b/chrome/test/functional/execute_javascript.py
deleted file mode 100755
index 212ff44..0000000
--- a/chrome/test/functional/execute_javascript.py
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import os
-import sys
-import unittest
-
-import pyauto_functional
-from pyauto import PyUITest
-
-
-class ExecuteJavascriptTest(PyUITest):
- def _GetExtensionInfoById(self, extensions, id):
- for x in extensions:
- if x['id'] == id:
- return x
- return None
-
- def testExecuteJavascript(self):
- self.NavigateToURL(self.GetFileURLForDataPath(
- 'frame_dom_access', 'frame_dom_access.html'))
-
- v = self.ExecuteJavascript('window.domAutomationController.send(' +
- 'document.getElementById("myinput").nodeName)')
- self.assertEqual(v, 'INPUT')
-
- def testGetDOMValue(self):
- self.NavigateToURL(self.GetFileURLForDataPath(
- 'frame_dom_access', 'frame_dom_access.html'))
-
- v = self.GetDOMValue('document.getElementById("myinput").nodeName')
- self.assertEqual(v, 'INPUT')
-
- def testExecuteJavascriptInExtension(self):
- """Test we can inject JavaScript into an extension."""
- dir_path = os.path.abspath(
- os.path.join(self.DataDir(), 'extensions', 'js_injection_background'))
- ext_id = self.InstallExtension(dir_path)
-
- # Verify extension is enabled.
- extension = self._GetExtensionInfoById(self.GetExtensionsInfo(), ext_id)
- self.assertTrue(extension['is_enabled'],
- msg='Extension was disabled by default')
-
- # Get the background page's view.
- background_view = self.WaitUntilExtensionViewLoaded(
- view_type='EXTENSION_BACKGROUND_PAGE')
- self.assertTrue(background_view,
- msg='problematic background view: views = %s.' %
- self.GetBrowserInfo()['extension_views'])
-
- # Get values from background page's DOM
- v = self.ExecuteJavascriptInRenderView(
- 'window.domAutomationController.send('
- 'document.getElementById("myinput").nodeName)', background_view)
- self.assertEqual(v, 'INPUT',
- msg='Incorrect value returned (v = %s).' % v)
- v = self.ExecuteJavascriptInRenderView(
- 'window.domAutomationController.send(bool_var)', background_view)
- self.assertEqual(v, True, msg='Incorrect value returned (v = %s).' % v)
- v = self.ExecuteJavascriptInRenderView(
- 'window.domAutomationController.send(int_var)', background_view)
- self.assertEqual(v, 42, msg='Incorrect value returned (v = %s).' % v)
- v = self.ExecuteJavascriptInRenderView(
- 'window.domAutomationController.send(str_var)', background_view)
- self.assertEqual(v, 'foo', msg='Incorrect value returned (v = %s).' % v)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/extensions.py b/chrome/test/functional/extensions.py
deleted file mode 100755
index 62f206f..0000000
--- a/chrome/test/functional/extensions.py
+++ /dev/null
@@ -1,346 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-"""
-This module is a simple qa tool that installs extensions and tests whether the
-browser crashes while visiting a list of urls.
-
-Usage: python extensions.py -v
-
-Note: This assumes that there is a directory of extensions called
-'extensions-tool' and that there is a file of newline-separated urls to visit
-called 'urls.txt' in the data directory.
-"""
-
-import glob
-import logging
-import os
-import sys
-
-import pyauto_functional # must be imported before pyauto
-import pyauto
-
-
-class ExtensionsPage(object):
- """Access options in extensions page (chrome://extensions-frame)."""
-
- _URL = 'chrome://extensions-frame'
-
- def __init__(self, driver):
- self._driver = driver
- self._driver.get(ExtensionsPage._URL)
-
- def CheckExtensionVisible(self, ext_id):
- """Returns True if |ext_id| exists on page."""
- return len(self._driver.find_elements_by_id(ext_id)) == 1
-
- def SetEnabled(self, ext_id, enabled):
- """Clicks on 'Enabled' checkbox for specified extension.
-
- Args:
- ext_id: Extension ID to be enabled or disabled.
- enabled: Boolean indicating whether |ext_id| is to be enabled or disabled.
- """
- checkbox = self._driver.find_element_by_xpath(
- '//*[@id="%s"]//*[@class="enable-controls"]//*[@type="checkbox"]' %
- ext_id)
- if checkbox != enabled:
- checkbox.click()
- # Reload page to ensure that the UI is recreated.
- self._driver.get(ExtensionsPage._URL)
-
- def SetAllowInIncognito(self, ext_id, allowed):
- """Clicks on 'Allow in incognito' checkbox for specified extension.
-
- Args:
- ext_id: Extension ID to be enabled or disabled.
- allowed: Boolean indicating whether |ext_id| is to be allowed or
- disallowed in incognito.
- """
- checkbox = self._driver.find_element_by_xpath(
- '//*[@id="%s"]//*[@class="incognito-control"]//*[@type="checkbox"]' %
- ext_id)
- if checkbox.is_selected() != allowed:
- checkbox.click()
- # Reload page to ensure that the UI is recreated.
- self._driver.get(ExtensionsPage._URL)
-
- def SetAllowAccessFileURLs(self, ext_id, allowed):
- """Clicks on 'Allow access to file URLs' checkbox for specified extension.
-
- Args:
- ext_id: Extension ID to be enabled or disabled.
- allowed: Boolean indicating whether |ext_id| is to be allowed access to
- file URLs.
- """
- checkbox = self._driver.find_element_by_xpath(
- '//*[@id="%s"]//*[@class="file-access-control"]//*[@type="checkbox"]' %
- ext_id)
- if checkbox.is_selected() != allowed:
- checkbox.click()
-
-
-class ExtensionsTest(pyauto.PyUITest):
- """Test of extensions."""
-
- def Debug(self):
- """Test method for experimentation.
-
- This method is not run automatically.
- """
- while True:
- raw_input('Interact with the browser and hit <enter> to dump history.')
- print '*' * 20
- self.pprint(self.GetExtensionsInfo())
-
- def _GetInstalledExtensionIds(self):
- return [extension['id'] for extension in self.GetExtensionsInfo()]
-
- def _ReturnCrashingExtensions(self, extensions, group_size, top_urls):
- """Returns the group of extensions that crashes (if any).
-
- Install the given extensions in groups of group_size and return the
- group of extensions that crashes (if any).
-
- Args:
- extensions: A list of extensions to install.
- group_size: The number of extensions to install at one time.
- top_urls: The list of top urls to visit.
-
- Returns:
- The extensions in the crashing group or None if there is no crash.
- """
- curr_extension = 0
- num_extensions = len(extensions)
- self.RestartBrowser()
- orig_extension_ids = self._GetInstalledExtensionIds()
-
- while curr_extension < num_extensions:
- logging.debug('New group of %d extensions.', group_size)
- group_end = curr_extension + group_size
- for extension in extensions[curr_extension:group_end]:
- logging.debug('Installing extension: %s', extension)
- self.InstallExtension(extension)
-
- for url in top_urls:
- self.NavigateToURL(url)
-
- def _LogAndReturnCrashing():
- crashing_extensions = extensions[curr_extension:group_end]
- logging.debug('Crashing extensions: %s', crashing_extensions)
- return crashing_extensions
-
- # If the browser has crashed, return the extensions in the failing group.
- try:
- num_browser_windows = self.GetBrowserWindowCount()
- except:
- return _LogAndReturnCrashing()
- else:
- if not num_browser_windows:
- return _LogAndReturnCrashing()
- else:
- # Uninstall all extensions that aren't installed by default.
- new_extension_ids = [id for id in self._GetInstalledExtensionIds()
- if id not in orig_extension_ids]
- for extension_id in new_extension_ids:
- self.UninstallExtensionById(extension_id)
-
- curr_extension = group_end
-
- # None of the extensions crashed.
- return None
-
- def _GetExtensionInfoById(self, extensions, id):
- for x in extensions:
- if x['id'] == id:
- return x
- return None
-
- def ExtensionCrashes(self):
- """Add top extensions; confirm browser stays up when visiting top urls."""
- # TODO: provide a way in pyauto to pass args to a test - take these as args
- extensions_dir = os.path.join(self.DataDir(), 'extensions-tool')
- urls_file = os.path.join(self.DataDir(), 'urls.txt')
-
- error_msg = 'The dir "%s" must exist' % os.path.abspath(extensions_dir)
- assert os.path.exists(extensions_dir), error_msg
- error_msg = 'The file "%s" must exist' % os.path.abspath(urls_file)
- assert os.path.exists(urls_file), error_msg
-
- num_urls_to_visit = 100
- extensions_group_size = 20
-
- top_urls = [l.rstrip() for l in
- open(urls_file).readlines()[:num_urls_to_visit]]
-
- failed_extensions = glob.glob(os.path.join(extensions_dir, '*.crx'))
- group_size = extensions_group_size
-
- while (group_size and failed_extensions):
- failed_extensions = self._ReturnCrashingExtensions(
- failed_extensions, group_size, top_urls)
- group_size = group_size // 2
-
- self.assertFalse(failed_extensions,
- 'Extension(s) in failing group: %s' % failed_extensions)
-
- def _InstallExtensionCheckDefaults(self, crx_file):
- """Installs extension at extensions/|crx_file| and checks default status.
-
- Checks that the installed extension is enabled and not allowed in incognito.
-
- Args:
- crx_file: Relative path from self.DataDir()/extensions to .crx extension
- to be installed.
-
- Returns:
- The extension ID.
- """
- crx_file_path = os.path.abspath(
- os.path.join(self.DataDir(), 'extensions', crx_file))
- ext_id = self.InstallExtension(crx_file_path)
- extension = self._GetExtensionInfoById(self.GetExtensionsInfo(), ext_id)
- self.assertTrue(extension['is_enabled'],
- msg='Extension was not enabled on installation')
- self.assertFalse(extension['allowed_in_incognito'],
- msg='Extension was allowed in incognito on installation.')
-
- return ext_id
-
- def _ExtensionValue(self, ext_id, key):
- """Returns the value of |key| for |ext_id|.
-
- Args:
- ext_id: The extension ID.
- key: The key for which the extensions info value is required.
-
- Returns:
- The value of extensions info |key| for |ext_id|.
- """
- return self._GetExtensionInfoById(self.GetExtensionsInfo(), ext_id)[key]
-
- def _FileAccess(self, ext_id):
- """Returns the value of newAllowFileAccess for |ext_id|.
-
- Args:
- ext_id: The extension ID.
-
- Returns:
- The value of extensions settings newAllowFileAccess for |ext_id|.
- """
- extension_settings = self.GetPrefsInfo().Prefs()['extensions']['settings']
- return extension_settings[ext_id]['newAllowFileAccess']
-
- def testGetExtensionPermissions(self):
- """Ensures we can retrieve the host/api permissions for an extension.
-
- This test assumes that the 'Bookmark Manager' extension exists in a fresh
- profile.
- """
- extensions_info = self.GetExtensionsInfo()
- bm_exts = [x for x in extensions_info if x['name'] == 'Bookmark Manager']
- self.assertTrue(bm_exts,
- msg='Could not find info for the Bookmark Manager '
- 'extension.')
- ext = bm_exts[0]
-
- permissions_host = ext['host_permissions']
- self.assertTrue(len(permissions_host) == 2 and
- 'chrome://favicon/*' in permissions_host and
- 'chrome://resources/*' in permissions_host,
- msg='Unexpected host permissions information.')
-
- permissions_api = ext['api_permissions']
- print permissions_api
- self.assertTrue(len(permissions_api) == 5 and
- 'bookmarks' in permissions_api and
- 'bookmarkManagerPrivate' in permissions_api and
- 'metricsPrivate' in permissions_api and
- 'systemPrivate' in permissions_api and
- 'tabs' in permissions_api,
- msg='Unexpected API permissions information.')
-
- def testDisableEnableExtension(self):
- """Tests that an extension can be disabled and enabled with the UI."""
- ext_id = self._InstallExtensionCheckDefaults('good.crx')
-
- # Disable extension.
- driver = self.NewWebDriver()
- ext_page = ExtensionsPage(driver)
- self.WaitUntil(ext_page.CheckExtensionVisible, args=[ext_id])
- ext_page.SetEnabled(ext_id, False)
- self.WaitUntil(self._ExtensionValue, args=[ext_id, 'is_enabled'],
- expect_retval=False)
- self.assertFalse(self._ExtensionValue(ext_id, 'is_enabled'),
- msg='Extension did not get disabled.')
-
- # Enable extension.
- self.WaitUntil(ext_page.CheckExtensionVisible, args=[ext_id])
- ext_page.SetEnabled(ext_id, True)
- self.WaitUntil(self._ExtensionValue, args=[ext_id, 'is_enabled'],
- expect_retval=True)
- self.assertTrue(self._ExtensionValue(ext_id, 'is_enabled'),
- msg='Extension did not get enabled.')
-
- def testAllowIncognitoExtension(self):
- """Tests allowing and disallowing an extension in incognito mode."""
- ext_id = self._InstallExtensionCheckDefaults('good.crx')
-
- # Allow in incognito.
- driver = self.NewWebDriver()
- ext_page = ExtensionsPage(driver)
- self.WaitUntil(ext_page.CheckExtensionVisible, args=[ext_id])
- ext_page.SetAllowInIncognito(ext_id, True)
-
- # Check extension now allowed in incognito.
- self.WaitUntil(self._ExtensionValue, args=[ext_id, 'allowed_in_incognito'],
- expect_retval=True)
- self.assertTrue(self._ExtensionValue(ext_id, 'allowed_in_incognito'),
- msg='Extension did not get allowed in incognito.')
-
- # Disallow in incognito.
- self.WaitUntil(ext_page.CheckExtensionVisible, args=[ext_id])
- ext_page.SetAllowInIncognito(ext_id, False)
-
- # Check extension now disallowed in incognito.
- self.WaitUntil(self._ExtensionValue, args=[ext_id, 'allowed_in_incognito'],
- expect_retval=False)
- self.assertFalse(self._ExtensionValue(ext_id, 'allowed_in_incognito'),
- msg='Extension did not get disallowed in incognito.')
-
- def testAllowAccessFileURLs(self):
- """Tests disallowing and allowing and extension access to file URLs."""
- ext_id = self._InstallExtensionCheckDefaults(os.path.join('permissions',
- 'files'))
-
- # Check extension allowed access to file URLs by default.
- extension_settings = self.GetPrefsInfo().Prefs()['extensions']['settings']
- self.assertTrue(extension_settings[ext_id]['newAllowFileAccess'],
- msg='Extension was not allowed access to file URLs on '
- 'installation')
-
- # Disallow access to file URLs.
- driver = self.NewWebDriver()
- ext_page = ExtensionsPage(driver)
- self.WaitUntil(ext_page.CheckExtensionVisible, args=[ext_id])
- ext_page.SetAllowAccessFileURLs(ext_id, False)
-
- # Check that extension does not have access to file URLs.
- self.WaitUntil(self._FileAccess, args=[ext_id], expect_retval=False)
- self.assertFalse(self._FileAccess(ext_id),
- msg='Extension did not have access to file URLs denied.')
-
- # Allow access to file URLs.
- self.WaitUntil(ext_page.CheckExtensionVisible, args=[ext_id])
- ext_page.SetAllowAccessFileURLs(ext_id, True)
-
- # Check that extension now has access to file URLs.
- self.WaitUntil(self._FileAccess, args=[ext_id], expect_retval=True)
- self.assertTrue(self._FileAccess(ext_id),
- msg='Extension did not have access to file URLs granted.')
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/fullscreen_mouselock.py b/chrome/test/functional/fullscreen_mouselock.py
deleted file mode 100755
index 6cb5b97..0000000
--- a/chrome/test/functional/fullscreen_mouselock.py
+++ /dev/null
@@ -1,618 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import logging
-import os
-import re
-import shutil
-import time
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-import test_utils
-from selenium.webdriver.common.action_chains import ActionChains
-from selenium.common.exceptions import WebDriverException
-from selenium.webdriver.common.keys import Keys
-from webdriver_pages import settings
-
-
-class FullscreenMouselockTest(pyauto.PyUITest):
- """TestCase for Fullscreen and Mouse Lock."""
-
- def setUp(self):
- pyauto.PyUITest.setUp(self)
- self._driver = self.NewWebDriver()
- # Get the hostname pattern (e.g. http://127.0.0.1:57622).
- self._hostname_pattern = (
- re.sub('/files/$', '', self.GetHttpURLForDataPath('')))
-
- def Debug(self):
- """Test method for experimentation.
-
- This method will not run automatically.
- """
- page = settings.ContentSettingsPage.FromNavigation(self._driver)
- import pdb
- pdb.set_trace()
-
- def ExtraChromeFlags(self):
- """Ensures Chrome is launched with custom flags.
-
- Returns:
- A list of extra flags to pass to Chrome when it is launched.
- """
- # Extra flag needed by scroll performance tests.
- return super(FullscreenMouselockTest,
- self).ExtraChromeFlags() + ['--enable-pointer-lock']
-
- def testFullScreenMouseLockHooks(self):
- """Verify fullscreen and mouse lock automation hooks work."""
- self.NavigateToURL(self.GetHttpURLForDataPath(
- 'fullscreen_mouselock', 'fullscreen_mouselock.html'))
-
- # Starting off we shouldn't be fullscreen
- self.assertFalse(self.IsFullscreenForBrowser())
- self.assertFalse(self.IsFullscreenForTab())
-
- # Go fullscreen
- self._driver.find_element_by_id('enterFullscreen').click()
- self.assertTrue(self.WaitUntil(self.IsFullscreenForTab))
-
- # Bubble should be up prompting to allow fullscreen
- self.assertTrue(self.IsFullscreenBubbleDisplayed())
- self.assertTrue(self.IsFullscreenBubbleDisplayingButtons())
- self.assertTrue(self.IsFullscreenPermissionRequested())
-
- # Accept bubble, it should go away.
- self.AcceptCurrentFullscreenOrMouseLockRequest()
- self.assertTrue(self.WaitUntil(
- lambda: not self.IsFullscreenBubbleDisplayingButtons()))
-
- # Try to lock mouse, it won't lock yet but permision will be requested.
- self.assertFalse(self.IsMouseLocked())
- self._driver.find_element_by_id('lockMouse1').click()
- self.assertTrue(self.WaitUntil(self.IsMouseLockPermissionRequested))
- self.assertFalse(self.IsMouseLocked())
-
- # Deny mouse lock.
- self.DenyCurrentFullscreenOrMouseLockRequest()
- self.assertTrue(self.WaitUntil(
- lambda: not self.IsFullscreenBubbleDisplayingButtons()))
- self.assertFalse(self.IsMouseLocked())
-
- # Try mouse lock again, and accept it.
- self._driver.find_element_by_id('lockMouse1').click()
- self.assertTrue(self.WaitUntil(self.IsMouseLockPermissionRequested))
- self.AcceptCurrentFullscreenOrMouseLockRequest()
- self.assertTrue(self.WaitUntil(self.IsMouseLocked))
-
- # The following doesn't work - as sending the key to the input field isn't
- # picked up by the browser. :( Need an alternative way.
- #
- # # Ideally we wouldn't target a specific element, we'd just send keys to
- # # whatever the current keyboard focus was.
- # keys_target = driver.find_element_by_id('sendKeysTarget')
- #
- # # ESC key should exit fullscreen and mouse lock.
- #
- # print "# ESC key should exit fullscreen and mouse lock."
- # keys_target.send_keys(Keys.ESCAPE)
- # self.assertTrue(self.WaitUntil(lambda: not self.IsFullscreenForBrowser()))
- # self.assertTrue(self.WaitUntil(lambda: not self.IsFullscreenForTab()))
- # self.assertTrue(self.WaitUntil(lambda: not self.IsMouseLocked()))
- #
- # # Check we can go browser fullscreen
- # print "# Check we can go browser fullscreen"
- # keys_target.send_keys(Keys.F11)
- # self.assertTrue(self.WaitUntil(self.IsFullscreenForBrowser))
-
- def _LaunchFSAndExpectPrompt(self, button_action='enterFullscreen'):
- """Helper function to launch fullscreen and expect a prompt.
-
- Fullscreen is initiated and a bubble prompt appears asking to allow or
- cancel from fullscreen mode. The actual fullscreen mode doesn't take place
- until after approving the prompt.
-
- If the helper is not successful then the test will fail.
-
- Args:
- button_action: The button id to click to initiate an action. Default is to
- click enterFullscreen.
- """
- self.NavigateToURL(self.GetHttpURLForDataPath(
- 'fullscreen_mouselock', 'fullscreen_mouselock.html'))
- # Should not be in fullscreen mode during initial launch.
- self.assertFalse(self.IsFullscreenForBrowser())
- self.assertFalse(self.IsFullscreenForTab())
- # Go into fullscreen mode.
- self._driver.find_element_by_id(button_action).click()
- self.assertTrue(self.WaitUntil(self.IsFullscreenForTab))
- # Bubble should display prompting to allow fullscreen.
- self.assertTrue(self.IsFullscreenPermissionRequested())
-
- def _InitiateBrowserFullscreen(self):
- """Helper function that initiates browser fullscreen."""
- self.NavigateToURL(self.GetHttpURLForDataPath(
- 'fullscreen_mouselock', 'fullscreen_mouselock.html'))
- # Should not be in fullscreen mode during initial launch.
- self.assertFalse(self.IsFullscreenForBrowser())
- self.assertFalse(self.IsFullscreenForTab())
- # Initiate browser fullscreen.
- self.ApplyAccelerator(pyauto.IDC_FULLSCREEN)
- self.assertTrue(self.WaitUntil(self.IsFullscreenForBrowser))
- self.assertTrue(self.WaitUntil(lambda: not self.IsFullscreenForTab()))
- self.assertTrue(self.WaitUntil(lambda: not self.IsMouseLocked()))
-
- def _InitiateTabFullscreen(self):
- """Helper function that initiates tab fullscreen."""
- self.NavigateToURL(self.GetHttpURLForDataPath(
- 'fullscreen_mouselock', 'fullscreen_mouselock.html'))
- # Initiate tab fullscreen.
- self._driver.find_element_by_id('enterFullscreen').click()
- self.assertTrue(self.WaitUntil(self.IsFullscreenForTab))
-
- def _AcceptFullscreenOrMouseLockRequest(self):
- """Helper function to accept fullscreen or mouse lock request."""
- self.AcceptCurrentFullscreenOrMouseLockRequest()
- self.assertTrue(self.WaitUntil(
- lambda: not self.IsFullscreenBubbleDisplayingButtons()))
-
- def _EnableFullscreenAndMouseLockMode(self):
- """Helper function to enable fullscreen and mouse lock mode."""
- self._LaunchFSAndExpectPrompt(button_action='enterFullscreenAndLockMouse1')
- # Allow fullscreen.
- self.AcceptCurrentFullscreenOrMouseLockRequest()
- # The wait is needed due to crbug.com/123396. Should be able to click the
- # fullscreen and mouselock button and be both accepted in a single action.
- self.assertTrue(self.WaitUntil(self.IsMouseLockPermissionRequested))
- # Allow mouse lock.
- self.AcceptCurrentFullscreenOrMouseLockRequest()
- self.assertTrue(self.WaitUntil(self.IsMouseLocked))
-
- def _EnableMouseLockMode(self, button_action='lockMouse1'):
- """Helper function to enable mouse lock mode.
-
- Args:
- button_action: The button id to click to initiate an action. Default is to
- click lockMouse1.
- """
- self._driver.find_element_by_id(button_action).click()
- self.assertTrue(self.WaitUntil(self.IsMouseLockPermissionRequested))
- self.AcceptCurrentFullscreenOrMouseLockRequest()
- self.assertTrue(self.IsMouseLocked())
-
- def _EnableAndReturnLockMouseResult(self):
- """Helper function to enable and return mouse lock result."""
- self.NavigateToURL(self.GetHttpURLForDataPath(
- 'fullscreen_mouselock', 'fullscreen_mouselock.html'))
- self._driver.find_element_by_id('lockMouse2').click()
- self.assertTrue(
- self.WaitUntil(self.IsMouseLockPermissionRequested))
- self.AcceptCurrentFullscreenOrMouseLockRequest()
- # Waits until lock_result gets 'success' or 'failure'.
- return self._driver.execute_script('return lock_result')
-
- def _ClickAnchorLink(self):
- """Clicks the anchor link until it's successfully clicked.
-
- Clicks on the anchor link and compares the js |clicked_elem_ID| variabled
- with the anchor id. Returns True if the link is clicked.
- """
- element_id = 'anchor'
- # Catch WebDriverException: u'Element is not clickable at point (185.5,
- # 669.5). Instead another element would receive the click.
- try:
- self._driver.find_element_by_id(element_id).click()
- except WebDriverException:
- return False
- return self._driver.execute_script('return clicked_elem_ID') == element_id
-
- def testPrefsForFullscreenAllowed(self):
- """Verify prefs when fullscreen is allowed."""
- self._LaunchFSAndExpectPrompt()
- self._AcceptFullscreenOrMouseLockRequest()
- content_settings = (
- self.GetPrefsInfo().Prefs()['profile']['content_settings'])
- self.assertEqual(
- {self._hostname_pattern + ',*': {'fullscreen': 1}}, # Allow hostname.
- content_settings['pattern_pairs'],
- msg='Saved hostname pattern does not match expected pattern.')
-
- def testPrefsForFullscreenExit(self):
- """Verify prefs is empty when exit fullscreen mode before allowing."""
- self._LaunchFSAndExpectPrompt()
- self._driver.find_element_by_id('exitFullscreen').click()
- # Verify exit from fullscreen mode.
- self.assertTrue(self.WaitUntil(lambda: not self.IsFullscreenForTab()))
- content_settings = (
- self.GetPrefsInfo().Prefs()['profile']['content_settings'])
- self.assertEqual(
- {}, content_settings['pattern_pairs'],
- msg='Patterns saved when there should be none.')
-
- def testPatternsForFSAndML(self):
- """Verify hostname pattern and behavior for allowed mouse cursor lock.
-
- To lock the mouse, the browser needs to be in fullscreen mode.
- """
- self._EnableFullscreenAndMouseLockMode()
- self._EnableMouseLockMode()
- expected_pattern = (
- {self._hostname_pattern + ',*': {'fullscreen': 1, 'mouselock': 1}})
- content_settings = (
- self.GetPrefsInfo().Prefs()['profile']['content_settings'])
- self.assertEqual(
- expected_pattern, content_settings['pattern_pairs'],
- msg='Saved hostname and behavior patterns do not match expected.')
-
- def testPatternsForAllowMouseLock(self):
- """Verify hostname pattern and behavior for allowed mouse cursor lock.
-
- Enable fullscreen mode and enable mouse lock separately.
- """
- self._LaunchFSAndExpectPrompt()
- self.AcceptCurrentFullscreenOrMouseLockRequest()
- self._EnableMouseLockMode()
- expected_pattern = (
- {self._hostname_pattern + ',*': {'fullscreen': 1, 'mouselock': 1}})
- content_settings = (
- self.GetPrefsInfo().Prefs()['profile']['content_settings'])
- self.assertEqual(
- expected_pattern, content_settings['pattern_pairs'],
- msg='Saved hostname and behavior patterns do not match expected.')
-
- def testNoMouseLockRequest(self):
- """Verify mouse lock request does not appear.
-
- When allowing all sites to disable the mouse cursor, the mouse lock request
- bubble should not show. The mouse cursor should be automatically disabled
- when clicking on a disable mouse button.
- """
- # Allow all sites to disable mouse cursor.
- self.SetPrefs(pyauto.kDefaultContentSettings, {u'mouselock': 1})
- self._LaunchFSAndExpectPrompt()
- # Allow for fullscreen mode.
- self._AcceptFullscreenOrMouseLockRequest()
- self._driver.set_script_timeout(2)
- # Receive callback status (success or failure) from javascript that the
- # click has registered and the mouse lock status has changed.
- lock_result = self._driver.execute_async_script(
- 'lockMouse1(arguments[arguments.length - 1])')
- self.assertEqual(lock_result, 'success', msg='Mouse lock unsuccessful.')
- self.assertTrue(self.WaitUntil(
- lambda: not self.IsMouseLockPermissionRequested()))
- self.assertTrue(self.IsMouseLocked())
-
- def testUnableToLockMouse(self):
- """Verify mouse lock is disabled.
-
- When not allowing any site to disable the mouse cursor, the mouse lock
- request bubble should not show and the mouse cursor should not be disabled.
- """
- # Do not allow any site to disable mouse cursor.
- self.SetPrefs(pyauto.kDefaultContentSettings, {u'mouselock': 2})
- self._LaunchFSAndExpectPrompt()
- # Allow for fullscreen mode.
- self._AcceptFullscreenOrMouseLockRequest()
- self._driver.set_script_timeout(2)
- # Receive callback status (success or failure) from javascript that the
- # click has registered and the mouse lock status has changed.
- lock_result = self._driver.execute_async_script(
- 'lockMouse1(arguments[arguments.length - 1])')
- self.assertEqual(lock_result, 'failure', msg='Mouse locked unexpectedly.')
- self.assertTrue(self.WaitUntil(
- lambda: not self.IsMouseLockPermissionRequested()))
- self.assertTrue(self.WaitUntil(lambda: not self.IsMouseLocked()))
-
- def testEnterTabFSWhileInBrowserFS(self):
- """Verify able to enter into tab fullscreen while in browser fullscreen."""
- self._InitiateBrowserFullscreen()
- # Initiate tab fullscreen.
- self._driver.find_element_by_id('enterFullscreen').click()
- self.assertTrue(self.WaitUntil(lambda: self.IsFullscreenForTab()))
- self.assertTrue(self.WaitUntil(lambda: not self.IsMouseLocked()))
-
- def testMouseLockInBrowserFS(self):
- """Verify mouse lock in browser fullscreen requires allow prompt."""
- self._InitiateBrowserFullscreen()
- self._driver.set_script_timeout(2)
- self._driver.execute_script('lockMouse1AndSetLockResult()')
- # Bubble should display prompting to allow mouselock.
- self.assertTrue(self.WaitUntil(self.IsMouseLockPermissionRequested))
- self.AcceptCurrentFullscreenOrMouseLockRequest()
- # Waits until lock_result gets 'success' or 'failure'.
- lock_result = self._driver.execute_script('return lock_result')
- self.assertEqual(lock_result, 'success',
- msg='Mouse was not locked in browser fullscreen.')
-
- def testNoMouseLockWhenCancelFS(self):
- """Verify mouse lock breaks when canceling tab fullscreen.
-
- This test uses javascript to initiate exit of tab fullscreen after mouse
- lock success callback.
- """
- self._LaunchFSAndExpectPrompt()
- self._driver.set_script_timeout(2)
- lock_result = self._driver.execute_script('lockMouse1AndSetLockResult()')
- self.assertTrue(
- self.WaitUntil(lambda: self.IsMouseLockPermissionRequested()))
- self.AcceptCurrentFullscreenOrMouseLockRequest()
- self.assertTrue(self.WaitUntil(self.IsMouseLocked))
- # Waits until lock_result gets 'success' or 'failure'.
- lock_result = self._driver.execute_script('return lock_result')
- self.assertEqual(
- lock_result, 'success', msg='Mouse is not locked.')
- self._driver.execute_script('document.webkitCancelFullScreen()')
- self.assertTrue(self.WaitUntil(lambda: not self.IsFullscreenForTab()),
- msg='Tab is still in fullscreen.')
- self.assertTrue(self.WaitUntil(lambda: not self.IsMouseLocked()),
- msg='Mouse is still locked after exiting fullscreen.')
-
- def testNoTabFSExitWhenJSExitMouseLock(self):
- """Verify tab fullscreen does not exit when javascript init mouse lock exit.
-
- This test uses javascript to initiate exit of mouse lock after mouse
- lock success callback.
- """
- self._LaunchFSAndExpectPrompt()
- self._EnableMouseLockMode()
- self._driver.execute_script('navigator.webkitPointer.unlock()')
- self.WaitUntil(lambda: not self.IsMouseLocked())
- self.assertTrue(self.IsFullscreenForTab(), msg='Tab fullscreen was lost.')
-
- def testMouseLockExitWhenAlertDialogShow(self):
- """Verify mouse lock breaks when alert dialog appears."""
- self._LaunchFSAndExpectPrompt()
- self._EnableMouseLockMode()
- # Need to catch the exception here since the alert dialog raises
- # a WebDriverException due to a modal dialog.
- from selenium.common.exceptions import WebDriverException
- try:
- self._driver.execute_script('alert("A modal dialog")')
- except WebDriverException:
- pass
-
- self.assertTrue(self.WaitUntil(lambda: self.IsFullscreenForTab()),
- msg='Tab fullscreen was lost.')
- self.assertTrue(self.WaitUntil(lambda: not self.IsMouseLocked()),
- msg='Mouse is still locked')
-
- def testMouseLockExitWhenBrowserLoseFocus(self):
- """Verify mouse lock breaks when browser loses focus.
-
- Mouse lock breaks when the focus is placed on another new window.
- """
- self._LaunchFSAndExpectPrompt()
- self.AcceptCurrentFullscreenOrMouseLockRequest()
- # Open a new window to shift focus away.
- self.OpenNewBrowserWindow(True)
- self.assertTrue(self.WaitUntil(lambda: self.IsFullscreenForTab()))
- self.assertTrue(self.WaitUntil(lambda: not self.IsMouseLocked()),
- msg='Mouse lock did not break when browser lost focus.')
-
- def testMouseLockLostOnReload(self):
- """Verify mouse lock is lost on page reload."""
- self.NavigateToURL(self.GetHttpURLForDataPath(
- 'fullscreen_mouselock', 'fullscreen_mouselock.html'))
- self._EnableMouseLockMode()
- self.ReloadActiveTab()
- self.assertTrue(self.WaitUntil(lambda: not self.IsMouseLocked()),
- msg='Mouse lock did not break when page is reloaded.')
-
- def testNoMLBubbleWhenTabLoseFocus(self):
- """Verify mouse lock bubble goes away when tab loses focus."""
- self.NavigateToURL(self.GetHttpURLForDataPath(
- 'fullscreen_mouselock', 'fullscreen_mouselock.html'))
- self._driver.find_element_by_id('lockMouse1').click()
- self.assertTrue(self.WaitUntil(self.IsMouseLockPermissionRequested))
- self.AppendTab(pyauto.GURL('chrome://newtab'))
- self.assertTrue(self.WaitUntil(
- lambda: not self.IsFullscreenBubbleDisplayingButtons()),
- msg='Mouse lock bubble did not clear when tab lost focus.')
-
- def testTabFSExitWhenNavBackToPrevPage(self):
- """Verify tab fullscreen exit when navigating back to previous page.
-
- This test navigates to a new page while in tab fullscreen mode by using
- GoBack() to navigate to the previous google.html page.
- """
- self.NavigateToURL(self.GetHttpURLForDataPath('google', 'google.html'))
- self._InitiateTabFullscreen()
- self.TabGoBack()
- self.assertFalse(
- self.IsFullscreenForTab(),
- msg='Tab fullscreen did not exit when navigating to a new page.')
-
- def testTabFSExitWhenNavToNewPage(self):
- """Verify tab fullscreen exit when navigating to a new website.
-
- This test navigates to a new website while in tab fullscreen.
- """
- self._InitiateTabFullscreen()
- self.NavigateToURL(self.GetHttpURLForDataPath('google', 'google.html'))
- self.assertFalse(
- self.IsFullscreenForTab(),
- msg='Tab fullscreen did not exit when navigating to a new website.')
-
- def testTabFSDoesNotExitForAnchorLinks(self):
- """Verify tab fullscreen does not exit for anchor links.
-
- Tab fullscreen should not exit when following a link to the same page such
- as example.html#anchor.
- """
- self._InitiateTabFullscreen()
- self.assertTrue(self.WaitUntil(self._ClickAnchorLink))
- self.assertTrue(
- self.WaitUntil(self.IsFullscreenForTab),
- msg='Tab fullscreen should not exit when clicking on an anchor link.')
-
- def testMLExitWhenNavBackToPrevPage(self):
- """Verify mouse lock exit when navigating back to previous page.
-
- This test navigates to a new page while mouse lock is activated by using
- GoBack() to navigate to the previous google.html page.
- """
- self.NavigateToURL(self.GetHttpURLForDataPath('google', 'google.html'))
- lock_result = self._EnableAndReturnLockMouseResult()
- self.assertEqual(
- lock_result, 'success', msg='Mouse is not locked.')
- self.TabGoBack()
- self.assertFalse(
- self.IsMouseLocked(),
- msg='Mouse lock did not exit when navigating to the prev page.')
-
- def testMLExitWhenNavToNewPage(self):
- """Verify mouse lock exit when navigating to a new website."""
- lock_result = self._EnableAndReturnLockMouseResult()
- self.assertEqual(
- lock_result, 'success', msg='Mouse is not locked.')
- self.NavigateToURL(self.GetHttpURLForDataPath('google', 'google.html'))
- self.assertFalse(
- self.IsMouseLocked(),
- msg='Mouse lock did not exit when navigating to a new website.')
-
- def testMLDoesNotExitForAnchorLinks(self):
- """Verify mouse lock does not exit for anchor links.
-
- Mouse lock should not exist when following a link to the same page such as
- example.html#anchor.
- """
- lock_result = self._EnableAndReturnLockMouseResult()
- self.assertEqual(
- lock_result, 'success', msg='Mouse is not locked.')
- ActionChains(self._driver).move_to_element(
- self._driver.find_element_by_id('anchor')).click().perform()
- self.assertTrue(self.WaitUntil(self.IsMouseLocked),
- msg='Mouse lock broke when clicking on an anchor link.')
-
- def ExitTabFSToBrowserFS(self):
- """Verify exiting tab fullscreen leaves browser in browser fullscreen.
-
- This test is semi-automated.
-
- The browser initiates browser fullscreen, then initiates tab fullscreen. The
- test verifies that existing tab fullscreen by simulating ESC key press or
- clicking the js function to exitFullscreen() will exit the tab fullscreen
- leaving browser fullscreen intact.
- """
- self._InitiateBrowserFullscreen()
- # Initiate tab fullscreen.
- self._driver.find_element_by_id('enterFullscreen').click()
- self.assertTrue(self.WaitUntil(lambda: self.IsFullscreenForTab()))
- # Require manual intervention to send ESC key due to crbug.com/123930.
- # TODO(dyu): Update to a full test once associated bug is fixed.
- logging.info('Press ESC key to exit tab fullscreen.')
- time.sleep(5)
- self.assertTrue(self.WaitUntil(lambda: not self.IsFullscreenForTab()))
- self.assertTrue(self.WaitUntil(lambda: self.IsFullscreenForBrowser()),
- msg='Not in browser fullscreen mode.')
-
- self._driver.find_element_by_id('enterFullscreen').click()
- self.assertTrue(self.WaitUntil(lambda: self.IsFullscreenForTab()))
- # Exit tab fullscreen by clicking button exitFullscreen().
- self._driver.find_element_by_id('exitFullscreen').click()
- self.assertTrue(self.WaitUntil(lambda: not self.IsFullscreenForTab()))
- self.assertTrue(self.WaitUntil(lambda: self.IsFullscreenForBrowser()),
- msg='Not in browser fullscreen mode.')
-
- def F11KeyExitsTabAndBrowserFS(self):
- """Verify existing tab fullscreen exits all fullscreen modes.
-
- This test is semi-automated.
-
- The browser initiates browser fullscreen, then initiates tab fullscreen. The
- test verifies that existing tab fullscreen by simulating F11 key press or
- CMD + SHIFT + F keys on the Mac will exit the tab fullscreen and the
- browser fullscreen.
- """
- self._InitiateBrowserFullscreen()
- # Initiate tab fullscreen.
- self._driver.find_element_by_id('enterFullscreen').click()
- self.assertTrue(self.WaitUntil(lambda: self.IsFullscreenForTab()))
- # Require manual intervention to send F11 key due to crbug.com/123930.
- # TODO(dyu): Update to a full test once associated bug is fixed.
- logging.info('Press F11 key to exit tab fullscreen.')
- time.sleep(5)
- self.assertTrue(self.WaitUntil(lambda: not self.IsFullscreenForTab()))
- self.assertTrue(self.WaitUntil(lambda: not self.IsFullscreenForBrowser()),
- msg='Browser is in fullscreen mode.')
-
- def SearchForTextOutsideOfContainer(self):
- """Verify text outside of container is not visible when fullscreen.
-
- This test is semi-automated.
-
- Verify this test manually until there is a way to find text on screen
- without using FindInPage().
-
- The text that is outside of the fullscreen container should only be visible
- when fullscreen is off. The text should not be visible while in fullscreen
- mode.
- """
- self.NavigateToURL(self.GetHttpURLForDataPath(
- 'fullscreen_mouselock', 'fullscreen_mouselock.html'))
- # Should not be in fullscreen mode during initial launch.
- self.assertFalse(self.IsFullscreenForBrowser())
- self.assertFalse(self.IsFullscreenForTab())
- self.assertTrue(
- self.WaitUntil(lambda: self.FindInPage(
- 'This text is outside of the container')['match_count'],
- expect_retval=1))
- # Go into fullscreen mode.
- self._driver.find_element_by_id('enterFullscreen').click()
- self.assertTrue(self.WaitUntil(self.IsFullscreenForTab))
- time.sleep(5)
- # TODO(dyu): find a way to verify on screen text instead of using
- # FindInPage() which searches for text in the HTML.
-
- def SameMouseLockMovement(self):
- """Verify the correct feel of mouse movement data when mouse is locked.
-
- This test is semi-automated.
-
- This test loads the same web page in two different tabs while in mouse lock
- mode. Each tab loads the web page from a different URL (e.g. by loading it
- from a localhost server and a file url). The test verifies
- that the mouse lock movements work the same in both
- tabs.
- """
- url1 = self.GetHttpURLForDataPath(
- 'fullscreen_mouselock', 'fullscreen_mouselock.html')
- url2 = self.GetFileURLForDataPath(
- 'fullscreen_mouselock', 'fullscreen_mouselock.html')
- tab2 = 'f1-4'
- self.NavigateToURL(url1)
- self.RunCommand(pyauto.IDC_NEW_TAB) # Open new tab.
- self.NavigateToURL(url2, 0, 1)
- self._driver.switch_to_window(tab2)
- self._EnableMouseLockMode() # Lock mouse in tab 2.
- raw_input('Manually move the mouse cursor on the page in tab 2. Shift+Tab \
- into tab 1, click on lockMouse1() button, and move the mouse \
- cursor on the page in tab 1. Verify mouse movement is smooth.')
-
- def MouseEventsIndependentOfExitBubble(self):
- """Verify mouse events are independent of the exit FS exit bubble for ML.
-
- Mouse movement events should work immediately when mouse lock is activated.
- The events should not be blocked waiting for the exit instruction bubble to
- clear.
- """
- self.NavigateToURL(self.GetHttpURLForDataPath(
- 'fullscreen_mouselock', 'fullscreen_mouselock.html'))
- # Should not be in fullscreen mode during initial launch.
- self.assertFalse(self.IsFullscreenForBrowser())
- self.assertFalse(self.IsFullscreenForTab())
- # Go into fullscreen mode.
- self._driver.find_element_by_id('enterFullscreen').click()
- self.assertTrue(self.WaitUntil(self.IsFullscreenForTab))
- self._EnableMouseLockMode()
- raw_input(
- '1. Move the mouse, see movement data being received by the page.\
- 2. Press ESC key.\
- 3. Lock the mouse without going fullscreen. Click lockMouse1() button.\
- Verify: The mouse movement events should work immediately.')
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/gpu.py b/chrome/test/functional/gpu.py
deleted file mode 100755
index 3f88ed2..0000000
--- a/chrome/test/functional/gpu.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import logging
-import os
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-
-
-class GpuTest(pyauto.PyUITest):
- """GPU Tests Runner."""
-
- def _GetGpuPID(self):
- """Fetch the pid of the GPU process."""
- child_processes = self.GetBrowserInfo()['child_processes']
- for x in child_processes:
- if x['type'] == 'GPU':
- return x['pid']
- return None
-
- def _IsHardwareAccelerated(self, feature):
- """Check if gpu is enabled in the machine before running any tests."""
- self.NavigateToURL('about:gpu')
- def IsFeatureStatusLoaded():
- """Returns whether the feature status UI has been loaded.
-
- The about:gpu page fetches status for features asynchronously, so use
- this to check if the fetch is done.
- """
- js = """
- var list = document.querySelector(".feature-status-list");
- domAutomationController.send(list.hasChildNodes() ? "done" : "");
- """
- return self.ExecuteJavascript(js)
- self.assertTrue(self.WaitUntil(IsFeatureStatusLoaded, 10))
- search = feature + ': Hardware accelerated'
- find_result = self.FindInPage(search)['match_count']
- if find_result:
- # about:gpu page starts a gpu process. Restart the browser to clear
- # the state. We could kill the gpu process, but navigating to a page
- # after killing the gpu can lead to flakiness.
- # See crbug.com/93423.
- self.RestartBrowser()
- return True
- else:
- logging.warn('Hardware acceleration not available')
- return False
-
- def _VerifyGPUProcessOnPage(self, url):
- url = self.GetFileURLForDataPath('pyauto_private', 'gpu', url)
- self.NavigateToURL(url)
- self.assertTrue(self.WaitUntil(
- lambda: self._GetGpuPID() is not None), msg='No process for GPU')
-
- def testSingleGpuProcess(self):
- """Verify there's only one gpu process shared across all uses."""
- self.assertTrue(self._IsHardwareAccelerated('WebGL'))
- url = self.GetFileURLForDataPath('pyauto_private',
- 'gpu', 'WebGLField.html')
- self.AppendTab(pyauto.GURL(url))
- # Open a new window.
- self.OpenNewBrowserWindow(True)
- self.NavigateToURL(url, 1, 0)
- # Open a new incognito window.
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
- self.NavigateToURL(url, 1, 0)
- # Verify there's only 1 gpu process.
- gpu_process_count = 0
- for x in self.GetBrowserInfo()['child_processes']:
- if x['type'] == 'GPU':
- gpu_process_count += 1
- self.assertEqual(1, gpu_process_count)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/gtalk/__init__.py b/chrome/test/functional/gtalk/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/chrome/test/functional/gtalk/__init__.py
+++ /dev/null
diff --git a/chrome/test/functional/gtalk/gtalk_base_test.py b/chrome/test/functional/gtalk/gtalk_base_test.py
deleted file mode 100644
index b1dd2e5..0000000
--- a/chrome/test/functional/gtalk/gtalk_base_test.py
+++ /dev/null
@@ -1,348 +0,0 @@
-# Copyright (c) 2012 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.
-
-"""Base GTalk tests.
-
-This module contains a set of common utilities for querying
-and manipulating the Google Talk Chrome Extension.
-"""
-
-import logging
-import re
-import os
-
-import pyauto_gtalk
-import pyauto
-import pyauto_errors
-
-
-class GTalkBaseTest(pyauto.PyUITest):
- """Base test class for testing GTalk."""
-
- _injected_js = None
-
- def Prompt(self, text):
- """Pause execution with debug output.
-
- Args:
- text: The debug output.
- """
- text = str(text)
- raw_input('--------------------> ' + text)
-
- def InstallGTalkExtension(self, gtalk_version):
- """Download and install the GTalk extension."""
- extension_path = os.path.abspath(
- os.path.join(self.DataDir(), 'extensions', 'gtalk',
- gtalk_version + '.crx'))
- self.assertTrue(
- os.path.exists(extension_path),
- msg='Failed to find GTalk extension: ' + extension_path)
-
- extension = self.GetGTalkExtensionInfo()
- if extension:
- logging.info('Extension already installed. Skipping install...\n')
- return
-
- self.InstallExtension(extension_path, False)
- extension = self.GetGTalkExtensionInfo()
- self.assertTrue(extension, msg='Failed to install GTalk extension.')
- self.assertTrue(extension['is_enabled'], msg='GTalk extension is disabled.')
-
- def UninstallGTalkExtension(self):
- """Uninstall the GTalk extension (if present)"""
- extension = self.GetGTalkExtensionInfo()
- if extension:
- self.UninstallExtensionById(extension['id'])
-
- def GetGTalkExtensionInfo(self):
- """Get the data object about the GTalk extension."""
- extensions = [x for x in self.GetExtensionsInfo()
- if x['name'] == 'Chat for Google']
- return extensions[0] if len(extensions) == 1 else None
-
- def RunInMole(self, js, mole_index=0):
- """Execute javascript in a chat mole.
-
- Args:
- js: The javascript to run.
- mole_index: The index of the mole in which to run the JS.
-
- Returns:
- The resulting value from executing the javascript.
- """
- return self._RunInRenderView(self.GetMoleInfo(mole_index), js,
- '//iframe[1]')
-
- def RunInAllMoles(self, js):
- """Execute javascript in all chat moles.
-
- Args:
- js: The javascript to run.
- """
- moles = self.GetMolesInfo()
- for mole in moles:
- self._RunInRenderView(mole, js, '//iframe[1]')
-
- def RunInRoster(self, js):
- """Execute javascript in the chat roster.
-
- Args:
- js: The javascript to run.
-
- Returns:
- The resulting value from executing the javascript.
- """
- return self._RunInRenderView(self.GetViewerInfo(), js,
- '//iframe[1]\n//iframe[1]')
-
- def RunInLoginPage(self, js, xpath=''):
- """Execute javascript in the gaia login popup.
-
- Args:
- js: The javascript to run.
- xpath: The xpath to the frame in which to execute the javascript.
-
- Returns:
- The resulting value from executing the javascript.
- """
- return self._RunInTab(self.GetLoginPageInfo(), js, xpath)
-
- def RunInViewer(self, js, xpath=''):
- """Execute javascript in the GTalk viewer window.
-
- Args:
- js: The javascript to run.
- xpath: The xpath to the frame in which to execute the javascript.
-
- Returns:
- The resulting value from executing the javascript.
- """
- return self._RunInRenderView(self.GetViewerInfo(), js, xpath)
-
- def RunInBackground(self, js, xpath=''):
- """Execute javascript in the GTalk viewer window.
-
- Args:
- js: The javascript to run.
- xpath: The xpath to the frame in which to execute the javascript.
-
- Returns:
- The resulting value from executing the javascript.
- """
- background_view = self.GetBackgroundInfo()
- return self._RunInRenderView(background_view['view'], js, xpath)
-
- def GetMoleInfo(self, mole_index=0):
- """Get the data object about a given chat mole.
-
- Args:
- mole_index: The index of the mole to retrieve.
-
- Returns:
- Data object describing mole.
- """
- extension = self.GetGTalkExtensionInfo()
- return self._GetExtensionViewInfo(
- 'chrome-extension://%s/panel.html' % extension['id'],
- mole_index)
-
- def GetMolesInfo(self):
- """Get the data objects for all of the chat moles.
-
- Returns:
- Set of data objects describing moles.
- """
- extension = self.GetGTalkExtensionInfo()
- return self._GetMatchingExtensionViews(
- 'chrome-extension://%s/panel.html' % extension['id'])
-
- def GetViewerInfo(self):
- """Get the data object about the GTalk viewer dialog."""
- extension = self.GetGTalkExtensionInfo()
- return self._GetExtensionViewInfo(
- 'chrome-extension://%s/viewer.html' % extension['id'])
-
- def GetLoginPageInfo(self):
- """Get the data object about the gaia login popup."""
- return self._GetTabInfo('https://accounts.google.com/ServiceLogin?')
-
- def GetBackgroundInfo(self):
- """Get the data object about the GTalk background page."""
- extension_views = self.GetBrowserInfo()['extension_views']
- for extension_view in extension_views:
- if 'Google Talk' in extension_view['name'] and \
- 'EXTENSION_BACKGROUND_PAGE' == extension_view['view_type']:
- return extension_view
- return None
-
- def WaitUntilResult(self, result, func, msg):
- """Loop func until a condition matches is satified.
-
- Args:
- result: Value of func() at which to stop.
- func: Function to run at each iteration.
- msg: Error to print upon timing out.
- """
- assert callable(func)
- self.assertTrue(self.WaitUntil(
- lambda: func(), expect_retval=result), msg=msg)
-
- def WaitUntilCondition(self, func, matches, msg):
- """Loop func until condition matches is satified.
-
- Args:
- func: Function to run at each iteration.
- matches: Funtion to evalute output and determine whether to stop.
- msg: Error to print upon timing out.
- """
- assert callable(func)
- assert callable(matches)
- self.assertTrue(self.WaitUntil(
- lambda: matches(func())), msg=msg)
-
- def _WrapJs(self, statement):
- """Wrap the javascript to be executed.
-
- Args:
- statement: The piece of javascript to wrap.
-
- Returns:
- The wrapped javascript.
- """
- return """
- window.domAutomationController.send(
- (function(){
- %s
- try{return %s}
- catch(e){return "JS_ERROR: " + e}})())
- """ % (self._GetInjectedJs(), statement)
-
- def _RunInTab(self, tab, js, xpath=''):
- """Execute javascript in a given tab.
-
- Args:
- tab: The data object for the Chrome window tab returned by
- _GetTabInfo.
- js: The javascript to run.
- xpath: The xpath to the frame in which to execute the javascript.
-
- Returns:
- The resulting value from executing the javascript.
- """
- if not tab:
- logging.debug('Tab not found: %s' % tab)
- return False
- logging.info('Run in tab: %s' % js)
-
- value = self.ExecuteJavascript(
- self._WrapJs(js),
- tab_index = tab['index'],
- windex = tab['windex'],
- frame_xpath = xpath)
- self._LogRun(js, value)
- return value
-
- def _RunInRenderView(self, view, js, xpath=''):
- """Execute javascript in a given render view.
-
- Args:
- view: The data object for the Chrome render view returned by
- _GetExtensionViewInfo.
- js: The javascript to run.
- xpath: The xpath to the frame in which to execute the javascript.
-
- Returns:
- The resulting value from executing the javascript.
- """
- if not view:
- logging.debug('View not found: %s' % view)
- return False
- logging.info('Run in view: %s' % js)
-
- value = self.ExecuteJavascriptInRenderView(
- self._WrapJs(js),
- view,
- frame_xpath = xpath)
- self._LogRun(js, value)
- return value
-
- def _LogRun(self, js, value):
- """Log a particular run.
-
- Args:
- js: The javascript statement executed.
- value: The return value for the execution.
- """
- # works around UnicodeEncodeError: 'ascii' codec can't encode...
- out = value
- if not isinstance(value, basestring):
- out = str(value)
- out = re.sub('\s', ';', out[:300])
- logging.info(js + ' ===> ' + out.encode('utf-8'))
-
- def _GetTabInfo(self, url_query, index=0):
- """Get the data object for a given tab.
-
- Args:
- url_query: The substring of the URL to search for.
- index: The index within the list of matches to return.
-
- Returns:
- The data object for the tab.
- """
- windows = self.GetBrowserInfo()['windows']
- i = 0
- for win in windows:
- for tab in win['tabs']:
- if tab['url'] and url_query in tab['url']:
- # Store reference to windex used in _RunInTab.
- tab['windex'] = win['index']
- if i == index:
- return tab
- i = i + 1
- return None
-
- def _GetExtensionViewInfo(self, url_query, index=0):
- """Get the data object for a given extension view.
-
- Args:
- url_query: The substring of the URL to search for.
- index: The index within the list of matches to return.
-
- Returns:
- The data object for the tab.
- """
-
- candidate_views = self._GetMatchingExtensionViews(url_query)
- if len(candidate_views) > index:
- return candidate_views[index]
- return None
-
- def _GetMatchingExtensionViews(self, url_query):
- """Gets the data objects for the extension views matching the url_query.
-
- Args:
- url_query: The substring of the URL to search for.
-
- Returns:
- An array of matching data objects.
- """
- extension_views = self.GetBrowserInfo()['extension_views']
- candidate_views = list()
- for extension_view in extension_views:
- if extension_view['url'] and url_query in extension_view['url']:
- candidate_views.append(extension_view['view'])
-
- # No guarantee on view order, so sort the views to get the correct one for
- # a given index.
- candidate_views.sort()
- return candidate_views
-
- def _GetInjectedJs(self):
- """Get the javascript to inject in the execution environment."""
- if self._injected_js is None:
- self._injected_js = open(
- os.path.join(os.path.dirname(__file__), 'jsutils.js')).read()
- return self._injected_js
diff --git a/chrome/test/functional/gtalk/jsutils.js b/chrome/test/functional/gtalk/jsutils.js
deleted file mode 100644
index 721a2db..0000000
--- a/chrome/test/functional/gtalk/jsutils.js
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright (c) 2012 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.
-
-/**
- * @fileoverview JS utilities automatically injected by GTalk PyAuto tests.
- */
-
-/**
- * Key codes to use with KeyboardEvent.
- */
-$KEYS = {
- ENTER: 13,
- ESC: 27
-};
-
-/**
- * The first Chrome extension view with a URL containing the query.
- */
-$VIEW = function(query) {
- var views = chrome.extension.getViews();
- for (var i = 0; i < views.length; i++) {
- var url = views[i].location.href;
- if (url && url.indexOf(query) >= 0) {
- return views[i];
- }
- }
- return null;
-};
-
-/**
- * The body element of the given window.
- */
-$BODY = function(opt_window) {
- return (opt_window || window).document.body;
-};
-
-/**
- * Find the ancestor of the given element with a particular tag name.
- */
-$FindByTagName = function(element, tag, index) {
- var tagElements = element.getElementsByTagName(tag);
- if (index < tagElements.length) {
- return tagElements[index];
- }
- return null;
-};
-
-/**
- * Find the first ancestor of the given element containing the given text.
- */
-$FindByText = function(baseElement, text) {
- var allElements = baseElement.getElementsByTagName('*');
- for (var i = 0; i < allElements.length; i++) {
- var element = allElements[i];
- if (element.innerText && element.innerText.indexOf(text) >= 0) {
- var child = $FindByText(element, text);
- return child != null ? child : element;
- }
- }
- return null;
-};
-
-/**
- * Simulate a click on a given element.
- */
-$Click = function(element) {
- var mouseEvent = element.ownerDocument.createEvent('MouseEvent');
- mouseEvent.initMouseEvent('click', true, true, window,
- 1, 0, 0, 0, 0, false, false, false, false, 0, null);
- element.dispatchEvent(mouseEvent);
- return true;
-};
-
-/**
- * Simulate typing text on a given element.
- */
-$Type = function(element, text) {
- var keyEvent = element.ownerDocument.createEvent('TextEvent');
- keyEvent.initTextEvent('textInput', true, true, window, text);
- element.dispatchEvent(keyEvent);
- return true;
-};
-
-/**
- * Simulate pressing a certain key on a given element.
- */
-$Press = function(baseElement, keycode, opt_ctrlKey, opt_shiftKey,
- opt_altKey, opt_metaKey) {
- var sendKeyEvent = function(element, eventType) {
- // Unfortuantely, using the typical KeyboardEvent and initKeyboardEvent
- // fails in Chrome due to a webkit bug:
- // https://bugs.webkit.org/show_bug.cgi?id=16735
- // We employ a workaround of synthesizing a raw 'Event' suggested here:
- // http://code.google.com/p/selenium/issues/detail?id=567
- var keyEvent = element.ownerDocument.createEvent('Events');
- keyEvent.ctrlKey = Boolean(opt_ctrlKey);
- keyEvent.shiftKey = Boolean(opt_shiftKey);
- keyEvent.altKey = Boolean(opt_altKey);
- keyEvent.metaKey = Boolean(opt_metaKey);
- keyEvent.initEvent(eventType, true, true);
- keyEvent.keyCode = keycode;
- element.dispatchEvent(keyEvent);
- }
- sendKeyEvent(baseElement, 'keydown');
- sendKeyEvent(baseElement, 'keypress');
- sendKeyEvent(baseElement, 'keyup');
- return true;
-};
diff --git a/chrome/test/functional/gtalk/pyauto_gtalk.py b/chrome/test/functional/gtalk/pyauto_gtalk.py
deleted file mode 100755
index 1a54221..0000000
--- a/chrome/test/functional/gtalk/pyauto_gtalk.py
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Setup for GTalk Pyauto tests."""
-
-import os
-import sys
-
-
-def _SetupPaths():
- """Setting path to find pyauto_functional.py."""
- gtalk_dir = os.path.abspath(os.path.dirname(__file__))
- sys.path.append(gtalk_dir)
- sys.path.append(os.path.normpath(os.path.join(gtalk_dir, os.pardir)))
-
-_SetupPaths()
-
-
-from pyauto_functional import Main
-
-
-if __name__ == '__main__':
- Main()
diff --git a/chrome/test/functional/gtalk/test_basic.py b/chrome/test/functional/gtalk/test_basic.py
deleted file mode 100755
index e9f96f3..0000000
--- a/chrome/test/functional/gtalk/test_basic.py
+++ /dev/null
@@ -1,312 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Basic sanity tests for the GTalk extension.
-
-This module contains the basic set of sanity tests run on the
-GTalk extension.
-"""
-
-import logging
-import sys
-import time
-import traceback
-import urllib2
-import os
-
-import gtalk_base_test
-import pyauto_gtalk # must preceed pyauto
-import pyauto
-
-
-class BasicTest(gtalk_base_test.GTalkBaseTest):
- """Test for Google Talk Chrome Extension."""
-
- def _OpenRoster(self, gtalk_version):
- """Download Talk extension and open the roster."""
-
- self.InstallGTalkExtension(gtalk_version)
-
- # Wait for the background view to load.
- extension = self.GetGTalkExtensionInfo()
- background_view = self.WaitUntilExtensionViewLoaded(
- extension_id=extension['id'],
- view_type='EXTENSION_BACKGROUND_PAGE')
- self.assertTrue(background_view,
- msg='Failed to get background view: views = %s.' %
- self.GetBrowserInfo()['extension_views'])
-
- # Click browser action icon
- self.TriggerBrowserActionById(extension['id'])
-
- # Wait for viewer window to open.
- self.assertTrue(
- self.WaitUntil(self.GetViewerInfo),
- msg='Timed out waiting for viewer.html to open.')
-
- # Wait for the sign-in iframe to load.
- self.WaitUntilCondition(
- lambda: self.RunInViewer(
- 'window.document.getElementsByTagName("iframe") != null && '
- 'window.document.getElementsByTagName("iframe").length > 0') and
- self.RunInViewer('window.location.href',
- '//iframe[1]'),
- lambda url: url and '/qsignin' in url,
- msg='Timed out waiting for /qsignin page.')
-
-
- def _SignIn(self, gtalk_version):
- """Download the extension, open the roster, and sign in"""
- # Open the roster.
- self._OpenRoster(gtalk_version)
-
- # Wait for /qsignin's BODY.
- self.WaitUntilResult(True,
- lambda: self.RunInViewer(
- 'Boolean($BODY())', '//iframe[1]'),
- msg='Timed out waiting for document.body in /qsignin page.')
-
- # Wait for the "Sign In" link.
- self.WaitUntilResult(True,
- lambda: self.RunInViewer(
- 'Boolean($FindByText($BODY(), "Sign In"))', '//iframe[1]'),
- msg='Timed out waiting for "Sign In" link in DOM.')
-
- # Click the "Sign In" link.
- self.assertTrue(self.RunInViewer(
- '$Click($FindByText($BODY(), "Sign In"))', '//iframe[1]'))
-
- # Wait for the login page to open.
- self.assertTrue(self.WaitUntil(self.GetLoginPageInfo),
- msg='Timed out waiting for login page to open.')
-
- # Wait for the login page's form element.
- self.WaitUntilResult(True,
- lambda: self.RunInLoginPage('Boolean(document.forms[0])'),
- msg='Timed out waiting for document.forms[0].')
-
- # Fill and submit the login form.
- credentials = self.GetPrivateInfo()['test_google_account']
-
- self.RunInLoginPage(
- 'document.forms[0].Email.value="' + credentials['username'] + '"')
- self.RunInLoginPage(
- 'document.forms[0].Passwd.value="' + credentials['password'] + '"')
- self.RunInLoginPage('document.forms[0].submit() || true')
-
- def RunBasicFunctionalityTest(self, gtalk_version):
- """Run tests for basic functionality in GTalk."""
-
- # Install the extension, open the viewer, and sign in.
- self._SignIn(gtalk_version)
-
- # Wait for the roster container iframe.
- self.WaitUntilResult(True,
- lambda: self.RunInViewer(
- 'window.document.getElementById("popoutRoster") != null'),
- msg='Timed out waiting for roster container iframe.')
-
- self.WaitUntilResult(True,
- lambda: self.RunInViewer('Boolean(window.frames[0])', '//iframe[1]'),
- msg='Timed out waiting for roster iframe.')
-
- # Wait for the roster iframe to load.
- self.WaitUntilCondition(
- lambda: self.RunInRoster('window.location.href'),
- lambda url: url and '/frame' in url,
- msg='Timed out waiting for /frame in url.')
-
- self.WaitUntilResult(True,
- lambda: self.RunInRoster(
- 'Boolean($FindByText($BODY(), "Send a message to..."))'),
- msg='Timed out waiting for "Send a message to..." label in roster DOM.')
-
- # Wait for "chatpinger@appspot.com" to appear in the roster.
- self.WaitUntilResult(True,
- lambda: self.RunInRoster(
- 'Boolean($FindByText($BODY(), "chatpinger@appspot.com"))'),
- msg='Timed out waiting for chatpinger@appspot.com in roster DOM.')
-
- # Works around for issue where mole doesn't open when clicked too quickly.
- time.sleep(1)
-
- # Click "chatpinger@appspot.com" to open a chat mole.
- self.RunInRoster('$Click($FindByText($BODY(), "chatpinger@appspot.com"))')
-
- # Wait until ready to check whether mole is open(temporary work around).
- time.sleep(1)
-
- # Wait for chat mole to open.
- self.assertTrue(self.WaitUntil(self.GetMoleInfo),
- msg='Timed out waiting for mole window to open.')
-
- self.WaitUntilResult(True,
- lambda: self.RunInViewer(
- 'window.document.getElementsByTagName("iframe") != null'),
- msg='Timed out waiting for iframes to load.')
-
- # Wait for chat mole to load.
- self.WaitUntilResult(True,
- lambda: self.RunInMole('Boolean(window.location.href)'),
- msg='Timed out waiting for mole window location.')
-
- # Wait for the chat mole's input textarea to load.
- self.WaitUntilResult(True,
- lambda: self.RunInMole(
- 'Boolean($FindByTagName($BODY(), "textarea", 0))'),
- msg='Timed out waiting for mole textarea.')
-
- # Type /ping in the mole's input widget.
- self.assertTrue(self.RunInMole(
- '$Type($FindByTagName($BODY(), "textarea", 0), "/ping")'),
- msg='Error typing in mole textarea.')
-
- # Type ENTER in the mole's input widget.
- self.assertTrue(self.RunInMole(
- '$Press($FindByTagName($BODY(),"textarea",0), $KEYS.ENTER)'),
- msg='Error sending ENTER in mole textarea.')
-
- # Wait for chat input to clear.
- self.WaitUntilResult(True,
- lambda: self.RunInMole(
- 'Boolean($FindByTagName($BODY(),"textarea",0).value=="")'),
- msg='Timed out waiting for textarea to clear after ENTER.')
-
- # Wait for /ping to appear in the chat history.
- self.WaitUntilCondition(
- lambda: self.RunInMole('window.document.body.innerHTML'),
- lambda html: html and '/ping' in html,
- msg='Timed out waiting for /ping to appear in mole DOM.')
-
- # Wait for the echo "Ping!" to appear in the chat history.
- self.WaitUntilCondition(
- lambda: self.RunInMole('window.document.body.innerHTML'),
- lambda html: html and 'Ping!' in html,
- msg='Timed out waiting for "Ping!" reply to appear in mole DOM.')
-
- # Request a ping in 7 seconds.
- self.assertTrue(self.RunInMole(
- '$Type($FindByTagName($BODY(),"textarea",0), "/ping 7")'),
- msg='Error typing "ping /7" in mole textarea.')
-
- # Press Enter in chat input.
- self.assertTrue(self.RunInMole(
- '$Press($FindByTagName($BODY(),"textarea",0), $KEYS.ENTER)'),
- msg='Error sending ENTER after "ping /7" in mole textarea.')
-
- # Briefly show mole for visual examination.
- # Also works around issue where extension may show the first
- # Ping! notification before closing the mole.
- time.sleep(2)
-
- # Press escape to close the mole.
- self.assertTrue(self.RunInMole(
- '$Press($FindByTagName($BODY(),"textarea",0), $KEYS.ESC)'),
- msg='Error sending ESC after "ping /7" in mole textarea.')
-
- # Wait for the mole to close.
- self.assertTrue(self.WaitUntil(
- lambda: not(bool(self.GetMoleInfo()))),
- msg='Timed out waiting for chatpinger mole to close.')
-
- # Ensure "chatpinger2@appspot.com" is in the roster.
- self.WaitUntilResult(True,
- lambda: self.RunInRoster(
- 'Boolean($FindByText($BODY(), "chatpinger2@appspot.com"))'),
- msg='Timed out waiting for chatpinger2@appspot.com in roster DOM.')
-
- # Click "chatpinger2@appspot.com" in the roster.
- self.RunInRoster('$Click($FindByText($BODY(), "chatpinger2@appspot.com"))')
-
- self.WaitUntilResult(True,
- lambda: self.RunInViewer(
- 'window.document.getElementsByTagName("iframe") != null'),
- msg='Timed out waiting for iframes to load.')
-
- # Wait for a second chat mole to open.
- time.sleep(1)
- self.assertTrue(self.WaitUntil(lambda: bool(self.GetMoleInfo(1))),
- msg='Timed out waiting for second mole window to open.')
-
- # Wait for mole content to load
- self.WaitUntilCondition(
- lambda: self.RunInMole('window.document.body.innerHTML', 1),
- lambda html: html and 'Ping!' in html,
- msg='Timed out waiting for Ping! to appear in mole DOM.')
-
- # Disable the extension.
- extension = self.GetGTalkExtensionInfo()
- self.SetExtensionStateById(extension['id'], enable=False,
- allow_in_incognito=False)
- extension = self.GetGTalkExtensionInfo()
- self.assertFalse(extension['is_enabled'])
-
- # Verify all moles + windows are closed.
- self.assertTrue(self.WaitUntil(lambda: not(bool(self.GetViewerInfo()))),
- msg='Timed out waiting for viewer.html to close after disabling.')
- self.assertTrue(self.WaitUntil(lambda: not(bool(self.GetMoleInfo()))),
- msg='Timed out waiting for first mole to close after disabling.')
- self.assertTrue(self.WaitUntil(lambda: not(bool(self.GetMoleInfo(1)))),
- msg='Timed out waiting for second mole to close after disabling.')
-
- def _GetCurrentGtalkVersion(self):
- """Read current gtalk extension version from file."""
- return self._GetGtalkVersion('current_version')
-
- def _GetRCGtalkVersion(self):
- """Read RC gtalk extension version from file"""
- return self._GetGtalkVersion('rc_version')
-
- def _GetGtalkVersion(self, version_type):
- """Read gtalk version from file"""
- version_path = os.path.abspath(
- os.path.join(self.DataDir(), 'extensions',
- 'gtalk', version_type))
- self.assertTrue(
- os.path.exists(version_path),
- msg='Failed to find version ' + version_path)
- with open(version_path) as version_file:
- return version_file.read()
-
- def _TestBasicFunctionality(self, version):
- """Run tests for basic functionality in GTalk with retries."""
-
- # Since this test goes against prod servers, we'll retry to mitigate
- # flakiness due to network issues.
- RETRIES = 5
- for tries in range(RETRIES):
- logging.info('Calling RunBasicFunctionalityTest on %s. Try #%s/%s'
- % (version, tries + 1, RETRIES))
- try:
- self.RunBasicFunctionalityTest(version)
- logging.info('RunBasicFunctionalityTest on %s succeeded. Tries: %s'
- % (version, tries + 1))
- break
- except Exception as e:
- logging.info("\n*** ERROR in RunBasicFunctionalityTest ***")
- exc_type, exc_value, exc_traceback = sys.exc_info()
- traceback.print_exception(exc_type, exc_value, exc_traceback)
- logging.info("\n")
- if tries < RETRIES - 1:
- self.NavigateToURL('http://accounts.google.com/Logout')
- logging.info('Closing all moles.')
- self.RunInAllMoles(
- '$Press($FindByTagName($BODY(),"textarea",0), $KEYS.ESC)')
- logging.info('Retrying...')
- else:
- raise
-
- def testCurrentVersion(self):
- """Run basic functionality test on current version of gtalk extension"""
- version = self._GetCurrentGtalkVersion()
- self._TestBasicFunctionality(version)
-
- def testRCVersion(self):
- """Run basic functionality test on RC version of gtalk extension"""
- version = self._GetRCGtalkVersion()
- self._TestBasicFunctionality(version)
-
-if __name__ == '__main__':
- pyauto_gtalk.Main()
diff --git a/chrome/test/functional/infobars.py b/chrome/test/functional/infobars.py
deleted file mode 100755
index 3d896a2..0000000
--- a/chrome/test/functional/infobars.py
+++ /dev/null
@@ -1,322 +0,0 @@
-#!/usr/bin/env python
-# 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.
-
-import logging
-import os
-import re
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-import test_utils
-
-
-class InfobarTest(pyauto.PyUITest):
- """TestCase for Infobars."""
-
- def Debug(self):
- """Test method for experimentation.
-
- This method will not run automatically.
- To run:
- python chrome/test/functional/infobars.py infobars.InfobarTest.Debug
- """
- while True:
- raw_input('Hit <enter> to dump info.. ')
- info = self.GetBrowserInfo()
- for window in info['windows']:
- for tab in window['tabs']:
- print 'Window', window['index'], 'tab', tab['index']
- self.pprint(tab['infobars'])
-
- def setUp(self):
- pyauto.PyUITest.setUp(self)
- self._flash_plugin_type = 'Plug-in'
- if self.GetBrowserInfo()['properties']['branding'] == 'Google Chrome':
- self._flash_plugin_type = 'Pepper Plugin'
- # Forcibly trigger all plugins to get registered. crbug.com/94123
- # Sometimes flash files loaded too quickly after firing browser
- # ends up getting downloaded, which seems to indicate that the plugin
- # hasn't been registered yet.
- self.GetPluginsInfo()
-
- def _GetTabInfo(self, windex=0, tab_index=0):
- """Helper to return info for the given tab in the given window.
-
- Defaults to first tab in first window.
- """
- return self.GetBrowserInfo()['windows'][windex]['tabs'][tab_index]
-
- def testPluginCrashInfobar(self):
- """Verify the "plugin crashed" infobar."""
- flash_url = self.GetFileURLForContentDataPath('plugin', 'flash.swf')
- # Trigger flash plugin
- self.NavigateToURL(flash_url)
- child_processes = self.GetBrowserInfo()['child_processes']
- flash = [x for x in child_processes if
- x['type'] == self._flash_plugin_type and
- x['name'] == 'Shockwave Flash'][0]
- self.assertTrue(flash)
- logging.info('Killing flash plugin. pid %d' % flash['pid'])
- self.Kill(flash['pid'])
- self.assertTrue(self.WaitForInfobarCount(1))
- crash_infobar = self._GetTabInfo()['infobars']
- self.assertTrue(crash_infobar)
- self.assertEqual(1, len(crash_infobar))
- self.assertTrue('crashed' in crash_infobar[0]['text'])
- self.assertEqual('confirm_infobar', crash_infobar[0]['type'])
- # Dismiss the infobar
- self.PerformActionOnInfobar('dismiss', infobar_index=0)
- self.assertFalse(self._GetTabInfo()['infobars'])
-
- def _VerifyGeolocationInfobar(self, windex, tab_index):
- """Verify geolocation infobar properties.
-
- Assumes that geolocation infobar is showing up in the given tab in the
- given window.
- """
- # TODO(dyu): Remove this helper function when a function to identify
- # infobar_type and index of the type is implemented.
- tab_info = self._GetTabInfo(windex, tab_index)
- geolocation_infobar = tab_info['infobars']
- self.assertTrue(geolocation_infobar)
- self.assertEqual(1, len(geolocation_infobar))
- self.assertEqual('Learn more', geolocation_infobar[0]['link_text'])
- self.assertEqual(2, len(geolocation_infobar[0]['buttons']))
- self.assertEqual('Allow', geolocation_infobar[0]['buttons'][0])
- self.assertEqual('Deny', geolocation_infobar[0]['buttons'][1])
-
- def testGeolocationInfobar(self):
- """Verify geoLocation infobar."""
- url = self.GetHttpURLForDataPath('geolocation', 'geolocation_on_load.html')
- self.NavigateToURL(url)
- self.assertTrue(self.WaitForInfobarCount(1))
- self._VerifyGeolocationInfobar(windex=0, tab_index=0)
- # Accept, and verify that the infobar went away
- self.PerformActionOnInfobar('accept', infobar_index=0)
- self.assertFalse(self._GetTabInfo()['infobars'])
-
- def testGeolocationInfobarInMultipleTabsAndWindows(self):
- """Verify GeoLocation inforbar in multiple tabs."""
- url = self.GetFileURLForDataPath( # triggers geolocation
- 'geolocation', 'geolocation_on_load.html')
- for tab_index in range(1, 2):
- self.AppendTab(pyauto.GURL(url))
- self.assertTrue(
- self.WaitForInfobarCount(1, windex=0, tab_index=tab_index))
- self._VerifyGeolocationInfobar(windex=0, tab_index=tab_index)
- # Try in a new window
- self.OpenNewBrowserWindow(True)
- self.NavigateToURL(url, 1, 0)
- self.assertTrue(self.WaitForInfobarCount(1, windex=1, tab_index=0))
- self._VerifyGeolocationInfobar(windex=1, tab_index=0)
- # Incognito window
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
- self.NavigateToURL(url, 2, 0)
- self.assertTrue(self.WaitForInfobarCount(1, windex=2, tab_index=0))
- self._VerifyGeolocationInfobar(windex=2, tab_index=0)
-
- def _GetFlashCrashInfobarCount(self, windex=0, tab_index=0):
- """Returns the count of 'Shockwave Flash has crashed' infobars."""
- browser_window = self.GetBrowserInfo()['windows'][windex]
- infobars = browser_window['tabs'][tab_index]['infobars']
- flash_crash_infobar_count = 0
- for infobar in infobars:
- if (('text' in infobar) and
- infobar['text'].startswith('Shockwave Flash has crashed')):
- flash_crash_infobar_count += 1
- return flash_crash_infobar_count
-
- def testPluginCrashForMultiTabs(self):
- """Verify plugin crash infobar shows up only on the tabs using plugin."""
- non_flash_url = self.GetFileURLForDataPath('english_page.html')
- flash_url = self.GetFileURLForContentDataPath('plugin', 'FlashSpin.swf')
- # False = Non flash url, True = Flash url
- # We have set of these values to compare a flash page and a non-flash page
- urls_type = [False, True, False, True, False]
- for _ in range(2):
- self.AppendTab(pyauto.GURL(flash_url))
- self.AppendTab(pyauto.GURL(non_flash_url))
- # Killing flash process
- child_processes = self.GetBrowserInfo()['child_processes']
- flash = [x for x in child_processes if
- x['type'] == self._flash_plugin_type and
- x['name'] == 'Shockwave Flash'][0]
- self.assertTrue(flash)
- self.Kill(flash['pid'])
- # Crash plugin infobar should show up in the second tab of this window
- # so passing window and tab argument in the wait for an infobar.
- self.assertTrue(self.WaitForInfobarCount(1, windex=0, tab_index=1))
- for i in range(len(urls_type)):
- # Verify that if page doesn't have flash plugin,
- # it should not have infobar popped-up
- self.ActivateTab(i)
- if not urls_type[i]:
- self.assertEqual(
- self._GetFlashCrashInfobarCount(0, i), 0,
- msg='Did not expect crash infobar in tab at index %d' % i)
- elif urls_type[i]:
- self.assertEqual(
- self._GetFlashCrashInfobarCount(0, i), 1,
- msg='Expected crash infobar in tab at index %d' % i)
- infobar = self.GetBrowserInfo()['windows'][0]['tabs'][i]['infobars']
- self.assertEqual(infobar[0]['type'], 'confirm_infobar')
- self.assertEqual(len(infobar), 1)
-
-
-class OneClickInfobarTest(pyauto.PyUITest):
- """Tests for one-click sign in infobar."""
-
- BLOCK_COOKIE_PATTERN = {'https://accounts.google.com/': {'cookies': 2}}
- OC_INFOBAR_TYPE = 'oneclicklogin_infobar'
- PW_INFOBAR_TYPE = 'password_infobar'
- URL = 'https://www.google.com/accounts/ServiceLogin'
- URL_LOGIN = 'https://www.google.com/accounts/Login'
- URL_LOGOUT = 'https://www.google.com/accounts/Logout'
-
- def setUp(self):
- pyauto.PyUITest.setUp(self)
- self._driver = self.NewWebDriver()
-
- def _LogIntoGoogleAccount(self, tab_index=0, windex=0):
- """Log into Google account.
-
- Args:
- tab_index: The tab index, default is 0.
- windex: The window index, default is 0.
- """
- creds = self.GetPrivateInfo()['test_google_account']
- username = creds['username']
- password = creds['password']
- test_utils.GoogleAccountsLogin(self, username, password, tab_index, windex)
- # TODO(dyu): Use WaitUntilNavigationCompletes after investigating
- # crbug.com/124877
- self.WaitUntil(
- lambda: self.GetDOMValue('document.readyState'),
- expect_retval='complete')
-
- def _PerformActionOnInfobar(self, action):
- """Perform an action on the infobar: accept, cancel, or dismiss.
-
- The one-click sign in infobar must show in the first tab of the first
- window. If action is 'accept' then the account is synced. If the action is
- 'cancel' then the infobar should be dismissed and never shown again. The
- account will not be synced. If the action is 'dismiss' then the infobar will
- shown again after the next login.
-
- Args:
- action: The action to perform on the infobar.
- """
- infobar_index = test_utils.WaitForInfobarTypeAndGetIndex(
- self, self.OC_INFOBAR_TYPE)
- self.PerformActionOnInfobar(action, infobar_index)
-
- def _DisplayOneClickInfobar(self, tab_index=0, windex=0):
- """One-click sign in infobar appears after logging into google account.
-
- Args:
- tab_index: The tab index, default is 0.
- windex: The window index, default is 0.
- """
- self._LogIntoGoogleAccount(tab_index=tab_index, windex=windex)
- self.assertTrue(self.WaitUntil(
- lambda: test_utils.GetInfobarIndexByType(
- self, self.OC_INFOBAR_TYPE,
- tab_index=tab_index, windex=windex) is not None),
- msg='The one-click login infobar did not appear.')
-
- def testDisplayOneClickInfobar(self):
- """Verify one-click infobar appears after login into google account.
-
- One-click infobar should appear after signing into a google account
- for the first time using a clean profile.
- """
- self._DisplayOneClickInfobar()
-
- def testNoOneClickInfobarAfterCancel(self):
- """Verify one-click infobar does not appear again after clicking cancel.
-
- The one-click infobar should not display again after logging into an
- account and selecting to reject sync the first time. The test covers
- restarting the browser with the same profile and verifying the one-click
- infobar does not show after login.
-
- This test also verifies that the password infobar displays.
- """
- self._DisplayOneClickInfobar()
- self._PerformActionOnInfobar(action='cancel') # Click 'No thanks' button.
- self.NavigateToURL(self.URL_LOGOUT)
- self._LogIntoGoogleAccount()
- test_utils.WaitForInfobarTypeAndGetIndex(self, self.PW_INFOBAR_TYPE)
- test_utils.AssertInfobarTypeDoesNotAppear(self, self.OC_INFOBAR_TYPE)
- # Restart browser with the same profile.
- self.RestartBrowser(clear_profile=False)
- self.NavigateToURL(self.URL_LOGOUT)
- self._LogIntoGoogleAccount()
- test_utils.AssertInfobarTypeDoesNotAppear(self, self.OC_INFOBAR_TYPE)
-
- def testDisplayOneClickInfobarAfterDismiss(self):
- """Verify one-click infobar appears again after clicking dismiss button.
-
- The one-click infobar should display again after logging into an
- account and clicking to dismiss the infobar the first time.
-
- This test also verifies that the password infobar does not display.
- The one-click infobar should supersede the password infobar.
- """
- self._DisplayOneClickInfobar()
- self._PerformActionOnInfobar(action='dismiss') # Click 'x' button.
- self.NavigateToURL(self.URL_LOGOUT)
- self._LogIntoGoogleAccount()
- test_utils.WaitForInfobarTypeAndGetIndex(self, self.OC_INFOBAR_TYPE)
- test_utils.AssertInfobarTypeDoesNotAppear(self, self.PW_INFOBAR_TYPE)
-
- def _OpenSecondProfile(self):
- """Create a second profile."""
- self.OpenNewBrowserWindowWithNewProfile()
- self.assertEqual(2, len(self.GetMultiProfileInfo()['profiles']),
- msg='The second profile was not created.')
-
- def testDisplayOneClickInfobarPerProfile(self):
- """Verify one-click infobar appears for each profile after sign-in."""
- # Default profile.
- self._DisplayOneClickInfobar()
- self._OpenSecondProfile()
- self._DisplayOneClickInfobar(windex=1)
-
- def testNoOneClickInfobarWhenCookiesBlocked(self):
- """Verify one-click infobar does not show when cookies are blocked.
-
- One-click sign in should not be enabled if cookies are blocked for Google
- accounts domain.
-
- This test verifies the following bug: crbug.com/117841
- """
- # Block cookies for Google accounts domain.
- self.SetPrefs(pyauto.kContentSettingsPatternPairs,
- self.BLOCK_COOKIE_PATTERN)
- self._LogIntoGoogleAccount()
- test_utils.AssertInfobarTypeDoesNotAppear(self, self.OC_INFOBAR_TYPE)
-
- def testOneClickInfobarShownWhenWinLoseFocus(self):
- """Verify one-click infobar still shows when window loses focus.
-
- This test verifies the following bug: crbug.com/121739
- """
- self._LogIntoGoogleAccount()
- test_utils.WaitForInfobarTypeAndGetIndex(self, self.OC_INFOBAR_TYPE)
- # Open new window to shift focus away.
- self.OpenNewBrowserWindow(True)
- test_utils.GetInfobarIndexByType(self, self.OC_INFOBAR_TYPE)
-
- def testNoOneClickInfobarInIncognito(self):
- """Verify that one-click infobar does not show up in incognito mode."""
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
- self._LogIntoGoogleAccount(windex=1)
- test_utils.AssertInfobarTypeDoesNotAppear(
- self, self.OC_INFOBAR_TYPE, windex=1)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/ispy/OWNERS b/chrome/test/functional/ispy/OWNERS
deleted file mode 100644
index 7fa81ec..0000000
--- a/chrome/test/functional/ispy/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-craigdh@chromium.org
-frankf@chromium.org
diff --git a/chrome/test/functional/ispy/__init__.py b/chrome/test/functional/ispy/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/chrome/test/functional/ispy/__init__.py
+++ /dev/null
diff --git a/chrome/test/functional/ispy/app.yaml b/chrome/test/functional/ispy/app.yaml
deleted file mode 100644
index 869464f..0000000
--- a/chrome/test/functional/ispy/app.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-application: google.com:ispy
-version: 1
-runtime: python27
-api_version: 1
-threadsafe: True
-
-handlers:
-- url: /.*
- script: server.app.application
-
-libraries:
-- name: webapp2
- version: latest
-- name: jinja2
- version: latest
-- name: PIL
- version: latest
diff --git a/chrome/test/functional/ispy/client/__init__.py b/chrome/test/functional/ispy/client/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/chrome/test/functional/ispy/client/__init__.py
+++ /dev/null
diff --git a/chrome/test/functional/ispy/client/boto_bucket.py b/chrome/test/functional/ispy/client/boto_bucket.py
deleted file mode 100644
index 5ea9c97..0000000
--- a/chrome/test/functional/ispy/client/boto_bucket.py
+++ /dev/null
@@ -1,88 +0,0 @@
-# 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.
-
-"""Implementation of CloudBucket using Google Cloud Storage as the backend."""
-import os
-import sys
-
-# boto requires depot_tools/third_party be in the path. Use
-# src/tools/find_depot_tools.py to add this directory.
-sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir,
- os.pardir, os.pardir, os.pardir, 'tools'))
-import find_depot_tools
-DEPOT_TOOLS_PATH = find_depot_tools.add_depot_tools_to_path()
-sys.path.append(os.path.join(os.path.abspath(DEPOT_TOOLS_PATH), 'third_party'))
-import boto
-
-from ..common import cloud_bucket
-
-
-class BotoCloudBucket(cloud_bucket.BaseCloudBucket):
- """Interfaces with GS using the boto library."""
-
- def __init__(self, key, secret, bucket_name):
- """Initializes the bucket with a key, secret, and bucket_name.
-
- Args:
- key: the API key to access GS.
- secret: the API secret to access GS.
- bucket_name: the name of the bucket to connect to.
- """
- uri = boto.storage_uri('', 'gs')
- conn = uri.connect(key, secret)
- self.bucket = conn.get_bucket(bucket_name)
-
- def _GetKey(self, path):
- key = boto.gs.key.Key(self.bucket)
- key.key = path
- return key
-
- # override
- def UploadFile(self, path, contents, content_type):
- key = self._GetKey(path)
- key.set_metadata('Content-Type', content_type)
- key.set_contents_from_string(contents)
- # Open permissions for the appengine account to read/write.
- key.add_email_grant('FULL_CONTROL',
- 'ispy.google.com@appspot.gserviceaccount.com')
-
- # override
- def DownloadFile(self, path):
- key = self._GetKey(path)
- if key.exists():
- return key.get_contents_as_string()
- else:
- raise cloud_bucket.FileNotFoundError
-
- # override
- def UpdateFile(self, path, contents):
- key = self._GetKey(path)
- if key.exists():
- key.set_contents_from_string(contents)
- else:
- raise cloud_bucket.FileNotFoundError
-
- # override
- def RemoveFile(self, path):
- key = self._GetKey(path)
- key.delete()
-
- # override
- def FileExists(self, path):
- key = self._GetKey(path)
- return key.exists()
-
- # override
- def GetImageURL(self, path):
- key = self._GetKey(path)
- if key.exists():
- # Corrects a bug in boto that incorrectly generates a url
- # to a resource in Google Cloud Storage.
- return key.generate_url(3600).replace('AWSAccessKeyId', 'GoogleAccessId')
- else:
- raise cloud_bucket.FileNotFoundError(path)
-
- # override
- def GetAllPaths(self, prefix):
- return (key.key for key in self.bucket.get_all_keys(prefix=prefix))
diff --git a/chrome/test/functional/ispy/client/dom.py b/chrome/test/functional/ispy/client/dom.py
deleted file mode 100644
index facac13..0000000
--- a/chrome/test/functional/ispy/client/dom.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright 2014 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.
-
-
-def GetScriptToWaitForUnchangingDOM():
- """Gets Javascript that waits until the DOM is stable for 5 seconds.
-
- Times out if the DOM is not stable within 30 seconds.
-
- Returns:
- Javascript as a string.
- """
- return """
- var target = document.body;
- var callback = arguments[arguments.length - 1]
-
- var timeout_id = setTimeout(function() {
- callback()
- }, 5000);
-
- var observer = new MutationObserver(function(mutations) {
- clearTimeout(timeout_id);
- timeout_id = setTimeout(function() {
- callback();
- }, 5000);
- }).observe(target, {attributes: true, childList: true,
- characterData: true, subtree: true});
- """
diff --git a/chrome/test/functional/ispy/client/wait_on_ajax.js b/chrome/test/functional/ispy/client/wait_on_ajax.js
deleted file mode 100644
index da1fce9..0000000
--- a/chrome/test/functional/ispy/client/wait_on_ajax.js
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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.
-
-var target = document.body;
-var callback = arguments[arguments.length - 1]
-
-var timeout_id = setTimeout(function() {
- callback()
-}, 5000);
-
-var observer = new MutationObserver(function(mutations) {
- clearTimeout(timeout_id);
- timeout_id = setTimeout(function() {
- callback();
- }, 5000);
-}).observe(target, {attributes: true, childList: true,
- characterData: true, subtree: true});
diff --git a/chrome/test/functional/ispy/common/__init__.py b/chrome/test/functional/ispy/common/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/chrome/test/functional/ispy/common/__init__.py
+++ /dev/null
diff --git a/chrome/test/functional/ispy/common/cloud_bucket.py b/chrome/test/functional/ispy/common/cloud_bucket.py
deleted file mode 100644
index 39134c9..0000000
--- a/chrome/test/functional/ispy/common/cloud_bucket.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# 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.
-
-"""Abstract injector class for GS requests."""
-
-
-class FileNotFoundError(Exception):
- """Thrown by a subclass of CloudBucket when a file is not found."""
- pass
-
-
-class BaseCloudBucket(object):
- """An abstract base class for working with GS."""
-
- def UploadFile(self, path, contents, content_type):
- """Uploads a file to GS.
-
- Args:
- path: where in GS to upload the file.
- contents: the contents of the file to be uploaded.
- content_type: the MIME Content-Type of the file.
- """
- raise NotImplementedError
-
- def DownloadFile(self, path):
- """Downsloads a file from GS.
-
- Args:
- path: the location in GS to download the file from.
-
- Returns:
- String contents of the file downloaded.
-
- Raises:
- bucket_injector.NotFoundException: if the file is not found.
- """
- raise NotImplementedError
-
- def UpdateFile(self, path, contents):
- """Uploads a file to GS.
-
- Args:
- path: location of the file in GS to update.
- contents: the contents of the file to be updated.
- """
- raise NotImplementedError
-
- def RemoveFile(self, path):
- """Removes a file from GS.
-
- Args:
- path: the location in GS to download the file from.
- """
- raise NotImplementedError
-
- def FileExists(self, path):
- """Checks if a file exists in GS.
-
- Args:
- path: the location in GS of the file.
-
- Returns:
- boolean representing whether the file exists in GS.
- """
- raise NotImplementedError
-
- def GetImageURL(self, path):
- """Gets a URL to an item in GS from its path.
-
- Args:
- path: the location in GS of a file.
-
- Returns:
- an url to a file in GS.
-
- Raises:
- bucket_injector.NotFoundException: if the file is not found.
- """
- raise NotImplementedError
-
- def GetAllPaths(self, prefix):
- """Gets paths to files in GS that start with a prefix.
-
- Args:
- prefix: the prefix to filter files in GS.
-
- Returns:
- a generator of paths to files in GS.
- """
- raise NotImplementedError
diff --git a/chrome/test/functional/ispy/common/constants.py b/chrome/test/functional/ispy/common/constants.py
deleted file mode 100644
index a8b1956..0000000
--- a/chrome/test/functional/ispy/common/constants.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# 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.
-
-"""Constants for I-Spy."""
-
-BUCKET = 'ispy-bucket'
diff --git a/chrome/test/functional/ispy/common/image_tools.py b/chrome/test/functional/ispy/common/image_tools.py
deleted file mode 100644
index aaa0748..0000000
--- a/chrome/test/functional/ispy/common/image_tools.py
+++ /dev/null
@@ -1,322 +0,0 @@
-# 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.
-
-"""Utilities for performing pixel-by-pixel image comparision."""
-
-import itertools
-import StringIO
-from PIL import Image
-
-
-def _AreTheSameSize(images):
- """Returns whether a set of images are the size size.
-
- Args:
- images: a list of images to compare.
-
- Returns:
- boolean.
-
- Raises:
- Exception: One image or fewer is passed in.
- """
- if len(images) > 1:
- return all(images[0].size == img.size for img in images[1:])
- else:
- raise Exception('No images passed in.')
-
-
-def _GetDifferenceWithMask(image1, image2, mask=None,
- masked_color=(225, 225, 225, 255),
- same_color=(255, 255, 255, 255),
- different_color=(210, 0, 0, 255)):
- """Returns an image representing the difference between the two images.
-
- This function computes the difference between two images taking into
- account a mask if it is provided. The final three arguments represent
- the coloration of the generated image.
-
- Args:
- image1: the first image to compare.
- image2: the second image to compare.
- mask: an optional mask image consisting of only black and white pixels
- where white pixels indicate the portion of the image to be masked out.
- masked_color: the color of a masked section in the resulting image.
- same_color: the color of an unmasked section that is the same.
- between images 1 and 2 in the resulting image.
- different_color: the color of an unmasked section that is different
- between images 1 and 2 in the resulting image.
-
- Returns:
- A 2-tuple with an image representing the unmasked difference between the
- two input images and the number of different pixels.
-
- Raises:
- Exception: if image1, image2, and mask are not the same size.
- """
- image_mask = mask
- if not mask:
- image_mask = Image.new('RGBA', image1.size, (0, 0, 0, 255))
- if not _AreTheSameSize([image1, image2, image_mask]):
- raise Exception('images and mask must be the same size.')
- image_diff = Image.new('RGBA', image1.size, (0, 0, 0, 255))
- data = []
- diff_pixels = 0
- for m, px1, px2 in itertools.izip(image_mask.getdata(),
- image1.getdata(),
- image2.getdata()):
- if m == (255, 255, 255, 255):
- data.append(masked_color)
- elif px1 == px2:
- data.append(same_color)
- else:
- data.append(different_color)
- diff_pixels += 1
-
- image_diff.putdata(data)
- return (image_diff, diff_pixels)
-
-
-def CreateMask(images):
- """Computes a mask for a set of images.
-
- Returns a difference mask that is computed from the images
- which are passed in. The mask will have a white pixel
- anywhere that the input images differ and a black pixel
- everywhere else.
-
- Args:
- images: list of images to compute the mask from.
-
- Returns:
- an image of only black and white pixels where white pixels represent
- areas in the input images that have differences.
-
- Raises:
- Exception: if the images passed in are not of the same size.
- Exception: if fewer than one image is passed in.
- """
- if not images:
- raise Exception('mask must be created from one or more images.')
- mask = Image.new('RGBA', images[0].size, (0, 0, 0, 255))
- image = images[0]
- for other_image in images[1:]:
- mask = _GetDifferenceWithMask(
- image,
- other_image,
- mask,
- masked_color=(255, 255, 255, 255),
- same_color=(0, 0, 0, 255),
- different_color=(255, 255, 255, 255))[0]
- return mask
-
-
-def AddMasks(masks):
- """Combines a list of mask images into one mask image.
-
- Args:
- masks: a list of mask-images.
-
- Returns:
- a new mask that represents the sum of the masked
- regions of the passed in list of mask-images.
-
- Raises:
- Exception: if masks is an empty list, or if masks are not the same size.
- """
- if not masks:
- raise Exception('masks must be a list containing at least one image.')
- if len(masks) > 1 and not _AreTheSameSize(masks):
- raise Exception('masks in list must be of the same size.')
- white = (255, 255, 255, 255)
- black = (0, 0, 0, 255)
- masks_data = [mask.getdata() for mask in masks]
- image = Image.new('RGBA', masks[0].size, black)
- image.putdata([white if white in px_set else black
- for px_set in itertools.izip(*masks_data)])
- return image
-
-
-def ConvertDiffToMask(diff):
- """Converts a Diff image into a Mask image.
-
- Args:
- diff: the diff image to convert.
-
- Returns:
- a new mask image where everything that was masked or different in the diff
- is now masked.
- """
- white = (255, 255, 255, 255)
- black = (0, 0, 0, 255)
- diff_data = diff.getdata()
- image = Image.new('RGBA', diff.size, black)
- image.putdata([black if px == white else white for px in diff_data])
- return image
-
-
-def VisualizeImageDifferences(image1, image2, mask=None):
- """Returns an image repesenting the unmasked differences between two images.
-
- Iterates through the pixel values of two images and an optional
- mask. If the pixel values are the same, or the pixel is masked,
- (0,0,0) is stored for that pixel. Otherwise, (255,255,255) is stored.
- This ultimately produces an image where unmasked differences between
- the two images are white pixels, and everything else is black.
-
- Args:
- image1: an RGB image
- image2: another RGB image of the same size as image1.
- mask: an optional RGB image consisting of only white and black pixels
- where the white pixels represent the parts of the images to be masked
- out.
-
- Returns:
- A 2-tuple with an image representing the unmasked difference between the
- two input images and the number of different pixels.
-
- Raises:
- Exception: if the two images and optional mask are different sizes.
- """
- return _GetDifferenceWithMask(image1, image2, mask)
-
-
-def InflateMask(image, passes):
- """A function that adds layers of pixels around the white edges of a mask.
-
- This function evaluates a 'frontier' of valid pixels indices. Initially,
- this frontier contains all indices in the image. However, with each pass
- only the pixels' indices which were added to the mask by inflation
- are added to the next pass's frontier. This gives the algorithm a
- large upfront cost that scales negligably when the number of passes
- is increased.
-
- Args:
- image: the RGBA PIL.Image mask to inflate.
- passes: the number of passes to inflate the image by.
-
- Returns:
- A RGBA PIL.Image.
- """
- inflated = Image.new('RGBA', image.size)
- new_dataset = list(image.getdata())
- old_dataset = list(image.getdata())
-
- frontier = set(range(len(old_dataset)))
- new_frontier = set()
-
- l = [-1, 1]
-
- def _ShadeHorizontal(index, px):
- col = index % image.size[0]
- if px == (255, 255, 255, 255):
- for x in l:
- if 0 <= col + x < image.size[0]:
- if old_dataset[index + x] != (255, 255, 255, 255):
- new_frontier.add(index + x)
- new_dataset[index + x] = (255, 255, 255, 255)
-
- def _ShadeVertical(index, px):
- row = index / image.size[0]
- if px == (255, 255, 255, 255):
- for x in l:
- if 0 <= row + x < image.size[1]:
- if old_dataset[index + image.size[0] * x] != (255, 255, 255, 255):
- new_frontier.add(index + image.size[0] * x)
- new_dataset[index + image.size[0] * x] = (255, 255, 255, 255)
-
- for _ in range(passes):
- for index in frontier:
- _ShadeHorizontal(index, old_dataset[index])
- _ShadeVertical(index, old_dataset[index])
- old_dataset, new_dataset = new_dataset, new_dataset
- frontier, new_frontier = new_frontier, set()
- inflated.putdata(new_dataset)
- return inflated
-
-
-def TotalDifferentPixels(image1, image2, mask=None):
- """Computes the number of different pixels between two images.
-
- Args:
- image1: the first RGB image to be compared.
- image2: the second RGB image to be compared.
- mask: an optional RGB image of only black and white pixels
- where white pixels indicate the parts of the image to be masked out.
-
- Returns:
- the number of differing pixels between the images.
-
- Raises:
- Exception: if the images to be compared and the mask are not the same size.
- """
- image_mask = mask
- if not mask:
- image_mask = Image.new('RGBA', image1.size, (0, 0, 0, 255))
- if _AreTheSameSize([image1, image2, image_mask]):
- total_diff = 0
- for px1, px2, m in itertools.izip(image1.getdata(),
- image2.getdata(),
- image_mask.getdata()):
- if m == (255, 255, 255, 255):
- continue
- elif px1 != px2:
- total_diff += 1
- else:
- continue
- return total_diff
- else:
- raise Exception('images and mask must be the same size')
-
-
-def SameImage(image1, image2, mask=None):
- """Returns a boolean representing whether the images are the same.
-
- Returns a boolean indicating whether two images are similar
- enough to be considered the same. Essentially wraps the
- TotalDifferentPixels function.
-
-
- Args:
- image1: an RGB image to compare.
- image2: an RGB image to compare.
- mask: an optional image of only black and white pixels
- where white pixels are masked out
-
- Returns:
- True if the images are similar, False otherwise.
-
- Raises:
- Exception: if the images (and mask) are different sizes.
- """
- different_pixels = TotalDifferentPixels(image1, image2, mask)
- return different_pixels == 0
-
-
-def EncodePNG(image):
- """Returns the PNG file-contents of the image.
-
- Args:
- image: an RGB image to be encoded.
-
- Returns:
- a base64 encoded string representing the image.
- """
- f = StringIO.StringIO()
- image.save(f, 'PNG')
- encoded_image = f.getvalue()
- f.close()
- return encoded_image
-
-
-def DecodePNG(png):
- """Returns a RGB image from PNG file-contents.
-
- Args:
- encoded_image: PNG file-contents of an RGB image.
-
- Returns:
- an RGB image
- """
- return Image.open(StringIO.StringIO(png))
diff --git a/chrome/test/functional/ispy/common/image_tools_unittest.py b/chrome/test/functional/ispy/common/image_tools_unittest.py
deleted file mode 100644
index 017c172..0000000
--- a/chrome/test/functional/ispy/common/image_tools_unittest.py
+++ /dev/null
@@ -1,183 +0,0 @@
-# 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.
-
-import unittest
-import sys
-import os
-from PIL import Image
-
-import image_tools
-
-
-def _GenImage(size, color):
- return Image.new('RGBA', size, color)
-
-
-def _AllPixelsOfColor(image, color):
- return not any(px != color for px in image.getdata())
-
-
-class ImageToolsTest(unittest.TestCase):
-
- def setUp(self):
- self.black25 = _GenImage((25, 25), (0, 0, 0, 255))
- self.black50 = _GenImage((50, 50), (0, 0, 0, 255))
- self.white25 = _GenImage((25, 25), (255, 255, 255, 255))
- self.white50 = _GenImage((50, 50), (255, 255, 255, 255))
-
- def testAreTheSameSize(self):
- self.assertTrue(image_tools._AreTheSameSize([self.black25, self.black25]))
- self.assertTrue(image_tools._AreTheSameSize([self.white25, self.white25]))
- self.assertTrue(image_tools._AreTheSameSize([self.black50, self.black50]))
- self.assertTrue(image_tools._AreTheSameSize([self.white50, self.white50]))
- self.assertTrue(image_tools._AreTheSameSize([self.black25, self.white25]))
- self.assertTrue(image_tools._AreTheSameSize([self.black50, self.white50]))
-
- self.assertFalse(image_tools._AreTheSameSize([self.black50, self.black25]))
- self.assertFalse(image_tools._AreTheSameSize([self.white50, self.white25]))
- self.assertFalse(image_tools._AreTheSameSize([self.black25, self.white50]))
- self.assertFalse(image_tools._AreTheSameSize([self.black50, self.white25]))
-
- self.assertRaises(Exception, image_tools._AreTheSameSize, [])
- self.assertRaises(Exception, image_tools._AreTheSameSize, [self.black50])
-
- def testGetDifferenceWithMask(self):
- self.assertTrue(_AllPixelsOfColor(image_tools._GetDifferenceWithMask(
- self.black25, self.black25)[0], (255, 255, 255, 255)))
- self.assertTrue(_AllPixelsOfColor(image_tools._GetDifferenceWithMask(
- self.white25, self.black25)[0], (210, 0, 0, 255)))
- self.assertTrue(_AllPixelsOfColor(image_tools._GetDifferenceWithMask(
- self.black25, self.black25, mask=self.black25)[0],
- (255, 255, 255, 255)))
- self.assertTrue(_AllPixelsOfColor(image_tools._GetDifferenceWithMask(
- self.black25, self.black25, mask=self.white25)[0],
- (225, 225, 225, 255)))
- self.assertTrue(_AllPixelsOfColor(image_tools._GetDifferenceWithMask(
- self.black25, self.white25, mask=self.black25)[0],
- (210, 0, 0, 255)))
- self.assertTrue(_AllPixelsOfColor(image_tools._GetDifferenceWithMask(
- self.black25, self.white25, mask=self.white25)[0],
- (225, 225, 225, 255)))
- self.assertRaises(Exception, image_tools._GetDifferenceWithMask,
- self.white25,
- self.black50)
- self.assertRaises(Exception, image_tools._GetDifferenceWithMask,
- self.white25,
- self.white25,
- mask=self.black50)
-
- def testCreateMask(self):
- m1 = image_tools.CreateMask([self.black25, self.white25])
- self.assertTrue(_AllPixelsOfColor(m1, (255, 255, 255, 255)))
- m2 = image_tools.CreateMask([self.black25, self.black25])
- self.assertTrue(_AllPixelsOfColor(m2, (0, 0, 0, 255)))
- m3 = image_tools.CreateMask([self.white25, self.white25])
- self.assertTrue(_AllPixelsOfColor(m3, (0, 0, 0, 255)))
-
- def testAddMasks(self):
- m1 = image_tools.CreateMask([self.black25, self.white25])
- m2 = image_tools.CreateMask([self.black25, self.black25])
- m3 = image_tools.CreateMask([self.black50, self.black50])
- self.assertTrue(_AllPixelsOfColor(image_tools.AddMasks([m1]),
- (255, 255, 255, 255)))
- self.assertTrue(_AllPixelsOfColor(image_tools.AddMasks([m2]),
- (0, 0, 0, 255)))
- self.assertTrue(_AllPixelsOfColor(image_tools.AddMasks([m1, m2]),
- (255, 255, 255, 255)))
- self.assertTrue(_AllPixelsOfColor(image_tools.AddMasks([m1, m1]),
- (255, 255, 255, 255)))
- self.assertTrue(_AllPixelsOfColor(image_tools.AddMasks([m2, m2]),
- (0, 0, 0, 255)))
- self.assertTrue(_AllPixelsOfColor(image_tools.AddMasks([m3]),
- (0, 0, 0, 255)))
- self.assertRaises(Exception, image_tools.AddMasks, [])
- self.assertRaises(Exception, image_tools.AddMasks, [m1, m3])
-
- def testTotalDifferentPixels(self):
- self.assertEquals(image_tools.TotalDifferentPixels(self.white25,
- self.white25),
- 0)
- self.assertEquals(image_tools.TotalDifferentPixels(self.black25,
- self.black25),
- 0)
- self.assertEquals(image_tools.TotalDifferentPixels(self.white25,
- self.black25),
- 25*25)
- self.assertEquals(image_tools.TotalDifferentPixels(self.white25,
- self.black25,
- mask=self.white25),
- 0)
- self.assertEquals(image_tools.TotalDifferentPixels(self.white25,
- self.white25,
- mask=self.white25),
- 0)
- self.assertEquals(image_tools.TotalDifferentPixels(self.white25,
- self.black25,
- mask=self.black25),
- 25*25)
- self.assertEquals(image_tools.TotalDifferentPixels(self.white25,
- self.white25,
- mask=self.black25),
- 0)
- self.assertRaises(Exception, image_tools.TotalDifferentPixels,
- self.white25, self.white50)
- self.assertRaises(Exception, image_tools.TotalDifferentPixels,
- self.white25, self.white25, mask=self.white50)
-
- def testSameImage(self):
- self.assertTrue(image_tools.SameImage(self.white25, self.white25))
- self.assertFalse(image_tools.SameImage(self.white25, self.black25))
-
- self.assertTrue(image_tools.SameImage(self.white25, self.black25,
- mask=self.white25))
- self.assertFalse(image_tools.SameImage(self.white25, self.black25,
- mask=self.black25))
- self.assertTrue(image_tools.SameImage(self.black25, self.black25))
- self.assertTrue(image_tools.SameImage(self.black25, self.black25,
- mask=self.white25))
- self.assertTrue(image_tools.SameImage(self.white25, self.white25,
- mask=self.white25))
- self.assertRaises(Exception, image_tools.SameImage,
- self.white25, self.white50)
- self.assertRaises(Exception, image_tools.SameImage,
- self.white25, self.white25,
- mask=self.white50)
-
- def testInflateMask(self):
- cross_image = Image.new('RGBA', (3, 3))
- white_image = Image.new('RGBA', (3, 3))
- dot_image = Image.new('RGBA', (3, 3))
- b = (0, 0, 0, 255)
- w = (255, 255, 255, 255)
- dot_image.putdata([b, b, b,
- b, w, b,
- b, b, b])
- cross_image.putdata([b, w, b,
- w, w, w,
- b, w, b])
- white_image.putdata([w, w, w,
- w, w, w,
- w, w, w])
- self.assertEquals(list(image_tools.InflateMask(dot_image, 1).getdata()),
- list(cross_image.getdata()))
- self.assertEquals(list(image_tools.InflateMask(dot_image, 0).getdata()),
- list(dot_image.getdata()))
- self.assertEquals(list(image_tools.InflateMask(dot_image, 2).getdata()),
- list(white_image.getdata()))
- self.assertEquals(list(image_tools.InflateMask(dot_image, 3).getdata()),
- list(white_image.getdata()))
- self.assertEquals(list(image_tools.InflateMask(self.black25, 1).getdata()),
- list(self.black25.getdata()))
-
- def testPNGEncodeDecode(self):
- self.assertTrue(_AllPixelsOfColor(
- image_tools.DecodePNG(
- image_tools.EncodePNG(self.white25)), (255, 255, 255, 255)))
- self.assertTrue(_AllPixelsOfColor(
- image_tools.DecodePNG(
- image_tools.EncodePNG(self.black25)), (0, 0, 0, 255)))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/chrome/test/functional/ispy/common/ispy_utils.py b/chrome/test/functional/ispy/common/ispy_utils.py
deleted file mode 100644
index a138f07..0000000
--- a/chrome/test/functional/ispy/common/ispy_utils.py
+++ /dev/null
@@ -1,304 +0,0 @@
-# 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.
-
-"""Internal utilities for managing I-Spy test results in Google Cloud Storage.
-
-See the ispy.ispy_api module for the external API.
-"""
-
-import collections
-import itertools
-import json
-import os
-import sys
-
-import image_tools
-
-
-_INVALID_EXPECTATION_CHARS = ['/', '\\', ' ', '"', '\'']
-
-
-def IsValidExpectationName(expectation_name):
- return not any(c in _INVALID_EXPECTATION_CHARS for c in expectation_name)
-
-
-def GetExpectationPath(expectation, file_name=''):
- """Get the path to a test file in the given test run and expectation.
-
- Args:
- expectation: name of the expectation.
- file_name: name of the file.
-
- Returns:
- the path as a string relative to the bucket.
- """
- return 'expectations/%s/%s' % (expectation, 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.
- expectation: name of the expectation.
- file_name: name of the file.
-
- Returns:
- the path as a string relative to the bucket.
- """
- return GetTestRunPath(test_run, '%s/%s' % (expectation, file_name))
-
-
-def GetTestRunPath(test_run, file_name=''):
- """Get the path to a the given test run.
-
- Args:
- test_run: name of the test run.
- file_name: name of the file.
-
- Returns:
- the path as a string relative to the bucket.
- """
- return 'failures/%s/%s' % (test_run, file_name)
-
-
-class ISpyUtils(object):
- """Utility functions for working with an I-Spy google storage bucket."""
-
- def __init__(self, cloud_bucket):
- """Initialize with a cloud bucket instance to supply GS functionality.
-
- Args:
- cloud_bucket: An object implementing the cloud_bucket.BaseCloudBucket
- interface.
- """
- self.cloud_bucket = cloud_bucket
-
- def UploadImage(self, full_path, image):
- """Uploads an image to a location in GS.
-
- Args:
- full_path: the path to the file in GS including the file extension.
- image: a RGB PIL.Image to be uploaded.
- """
- self.cloud_bucket.UploadFile(
- full_path, image_tools.EncodePNG(image), 'image/png')
-
- def DownloadImage(self, full_path):
- """Downloads an image from a location in GS.
-
- Args:
- full_path: the path to the file in GS including the file extension.
-
- Returns:
- The downloaded RGB PIL.Image.
-
- Raises:
- cloud_bucket.NotFoundError: if the path to the image is not valid.
- """
- return image_tools.DecodePNG(self.cloud_bucket.DownloadFile(full_path))
-
- def UpdateImage(self, full_path, image):
- """Updates an existing image in GS, preserving permissions and metadata.
-
- Args:
- full_path: the path to the file in GS including the file extension.
- image: a RGB PIL.Image.
- """
- self.cloud_bucket.UpdateFile(full_path, image_tools.EncodePNG(image))
-
- def GenerateExpectation(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 expectation.
-
- Args:
- expectation: name for this expectation, any existing expectation with the
- name will be replaced.
- images: a list of RGB encoded PIL.Images
-
- Raises:
- ValueError: if the expectation name is invalid.
- """
- if not IsValidExpectationName(expectation):
- raise ValueError("Expectation name contains an illegal character: %s." %
- str(_INVALID_EXPECTATION_CHARS))
-
- mask = image_tools.InflateMask(image_tools.CreateMask(images), 7)
- self.UploadImage(
- GetExpectationPath(expectation, 'expected.png'), images[0])
- self.UploadImage(GetExpectationPath(expectation, 'mask.png'), mask)
-
- def PerformComparison(self, test_run, expectation, actual):
- """Runs an image comparison, and uploads discrepancies to GS.
-
- Args:
- test_run: the name of the test_run.
- 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 expectation is not found.
- ValueError: if the expectation name is invalid.
- """
- if not IsValidExpectationName(expectation):
- raise ValueError("Expectation name contains an illegal character: %s." %
- str(_INVALID_EXPECTATION_CHARS))
-
- expectation_tuple = self.GetExpectation(expectation)
- if not image_tools.SameImage(
- actual, expectation_tuple.expected, mask=expectation_tuple.mask):
- self.UploadImage(
- GetFailurePath(test_run, expectation, 'actual.png'), actual)
- diff, diff_pxls = image_tools.VisualizeImageDifferences(
- expectation_tuple.expected, actual, mask=expectation_tuple.mask)
- self.UploadImage(GetFailurePath(test_run, expectation, 'diff.png'), diff)
- self.cloud_bucket.UploadFile(
- 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 GetExpectation(self, expectation):
- """Returns the given expectation from GS.
-
- Args:
- expectation: the name of the expectation to get.
-
- Returns:
- A named tuple: 'Expectation', containing two images: expected and mask.
-
- Raises:
- cloud_bucket.NotFoundError: if the test is not found in GS.
- """
- Expectation = collections.namedtuple('Expectation', ['expected', 'mask'])
- return Expectation(self.DownloadImage(GetExpectationPath(expectation,
- 'expected.png')),
- self.DownloadImage(GetExpectationPath(expectation,
- 'mask.png')))
-
- def ExpectationExists(self, expectation):
- """Returns whether the given expectation exists in GS.
-
- Args:
- expectation: the name of the expectation to check.
-
- Returns:
- A boolean indicating whether the test exists.
- """
- expected_image_exists = self.cloud_bucket.FileExists(
- GetExpectationPath(expectation, 'expected.png'))
- mask_image_exists = self.cloud_bucket.FileExists(
- GetExpectationPath(expectation, 'mask.png'))
- return expected_image_exists and mask_image_exists
-
- 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.
- 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, expectation, 'actual.png'))
- test_exists = self.ExpectationExists(expectation)
- info_exists = self.cloud_bucket.FileExists(
- GetFailurePath(test_run, expectation, 'info.txt'))
- return test_exists and actual_image_exists and info_exists
-
- def RemoveExpectation(self, expectation):
- """Removes an expectation and all associated failures with that test.
-
- Args:
- expectation: the name of the expectation to remove.
- """
- test_paths = self.cloud_bucket.GetAllPaths(
- GetExpectationPath(expectation))
- for path in test_paths:
- self.cloud_bucket.RemoveFile(path)
-
- def GenerateExpectationPinkOut(self, expectation, images, pint_out, rgb):
- """Uploads an ispy-test to GS with the pink_out workaround.
-
- Args:
- 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.
-
- Raises:
- ValueError: if expectation name is invalid.
- """
- if not IsValidExpectationName(expectation):
- raise ValueError("Expectation name contains an illegal character: %s." %
- str(_INVALID_EXPECTATION_CHARS))
-
- # convert the pink_out into a mask
- black = (0, 0, 0, 255)
- white = (255, 255, 255, 255)
- pink_out.putdata(
- [black if px == (rgb[0], rgb[1], rgb[2], 255) else white
- for px in pink_out.getdata()])
- mask = image_tools.CreateMask(images)
- mask = image_tools.InflateMask(image_tools.CreateMask(images), 7)
- combined_mask = image_tools.AddMasks([mask, pink_out])
- self.UploadImage(GetExpectationPath(expectation, 'expected.png'), images[0])
- self.UploadImage(GetExpectationPath(expectation, 'mask.png'), combined_mask)
-
- def RemoveFailure(self, test_run, expectation):
- """Removes a failure from GS.
-
- Args:
- test_run: the name of the test_run.
- expectation: the expectation on which the failure to be removed occured.
- """
- failure_paths = self.cloud_bucket.GetAllPaths(
- GetFailurePath(test_run, expectation))
- for path in failure_paths:
- self.cloud_bucket.RemoveFile(path)
-
- 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.
- expectation: the name of the expectation the result corresponds to.
-
- Returns:
- A named tuple: Failure containing three images: expected, diff, and
- actual.
-
- Raises:
- cloud_bucket.NotFoundError: if the result is not found in GS.
- """
- expected = self.DownloadImage(
- GetExpectationPath(expectation, 'expected.png'))
- actual = self.DownloadImage(
- GetFailurePath(test_run, expectation, 'actual.png'))
- diff = self.DownloadImage(
- GetFailurePath(test_run, expectation, 'diff.png'))
- info = json.loads(self.cloud_bucket.DownloadFile(
- GetFailurePath(test_run, expectation, 'info.txt')))
- Failure = collections.namedtuple(
- 'Failure', ['expected', 'diff', 'actual', 'info'])
- return Failure(expected, diff, actual, info)
-
- def GetAllPaths(self, prefix):
- """Gets urls to all files in GS whose path starts with a given prefix.
-
- Args:
- prefix: the prefix to filter files in GS by.
-
- Returns:
- a list containing urls to all objects that started with
- the prefix.
- """
- return self.cloud_bucket.GetAllPaths(prefix)
-
diff --git a/chrome/test/functional/ispy/common/ispy_utils_unittest.py b/chrome/test/functional/ispy/common/ispy_utils_unittest.py
deleted file mode 100644
index 2b55c2c..0000000
--- a/chrome/test/functional/ispy/common/ispy_utils_unittest.py
+++ /dev/null
@@ -1,207 +0,0 @@
-# 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.
-
-import os
-from PIL import Image
-import sys
-import unittest
-
-import cloud_bucket
-import image_tools
-import ispy_utils
-import mock_cloud_bucket
-
-
-class ISpyUtilsUnitTest(unittest.TestCase):
-
- def setUp(self):
- # Set up structures that will be reused throughout testing.
- self.bucket = mock_cloud_bucket.MockCloudBucket()
- self.ispy_utils = ispy_utils.ISpyUtils(self.bucket)
- self.white = Image.new('RGBA', (25, 25), (255, 255, 255, 255))
- self.red = Image.new('RGBA', (25, 25), (255, 0, 0, 255))
- self.black = Image.new('RGBA', (25, 25), (0, 0, 0, 255))
- self.masked = Image.new('RGBA', (25, 25), (210, 0, 0, 255))
-
- def testUploadImage(self):
- self.bucket.Reset()
- # Upload some images to the datastore.
- self.ispy_utils.UploadImage('path/to/white.png', self.white)
- self.ispy_utils.UploadImage('path/to/black.png', self.black)
- self.ispy_utils.UploadImage('path/to/red.png', self.red)
- # Confirm that the images actually got uploaded.
- self.assertEquals(self.bucket.datastore['path/to/white.png'],
- image_tools.EncodePNG(self.white))
- self.assertEquals(self.bucket.datastore['path/to/black.png'],
- image_tools.EncodePNG(self.black))
- self.assertEquals(self.bucket.datastore['path/to/red.png'],
- image_tools.EncodePNG(self.red))
-
- def testDownloadImage(self):
- self.bucket.Reset()
- # Upload some images to the datastore.
- self.ispy_utils.UploadImage('path/to/white.png', self.white)
- self.ispy_utils.UploadImage('path/to/black.png', self.black)
- self.ispy_utils.UploadImage('path/to/red.png', self.red)
- # Check that the DownloadImage function gets the correct images.
- self.assertEquals(
- image_tools.EncodePNG(
- self.ispy_utils.DownloadImage('path/to/white.png')),
- image_tools.EncodePNG(self.white))
- self.assertEquals(
- image_tools.EncodePNG(
- self.ispy_utils.DownloadImage('path/to/black.png')),
- image_tools.EncodePNG(self.black))
- self.assertEquals(
- image_tools.EncodePNG(
- self.ispy_utils.DownloadImage('path/to/red.png')),
- image_tools.EncodePNG(self.red))
- # Check that the DownloadImage function throws an error for a
- # nonexistant image.
- self.assertRaises(cloud_bucket.FileNotFoundError,
- self.ispy_utils.DownloadImage,
- 'path/to/yellow.png')
-
- def testUpdateImage(self):
- self.bucket.Reset()
- # Upload some images to the datastore.
- self.ispy_utils.UploadImage('path/to/image.png', self.white)
- self.assertEquals(self.bucket.datastore['path/to/image.png'],
- image_tools.EncodePNG(self.white))
- self.ispy_utils.UpdateImage('path/to/image.png', self.black)
- # Confirm that the image actually got updated.
- self.assertEquals(self.bucket.datastore['path/to/image.png'],
- image_tools.EncodePNG(self.black))
-
- def testGenerateExpectation(self):
- self.bucket.Reset()
- # Upload some tests to the datastore.
- self.ispy_utils.GenerateExpectation('test', [self.white, self.black])
- self.ispy_utils.GenerateExpectation('test1', [self.black, self.black])
- self.ispy_utils.GenerateExpectation('test2', [self.black])
- # Confirm that the tests were successfully uploaded.
- 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))
- self.assertEquals(self.bucket.datastore[
- ispy_utils.GetExpectationPath('test2', 'expected.png')],
- image_tools.EncodePNG(self.black))
- self.assertEquals(self.bucket.datastore[
- ispy_utils.GetExpectationPath('test2', 'mask.png')],
- image_tools.EncodePNG(self.black))
-
- def testPerformComparison(self):
- self.bucket.Reset()
- self.ispy_utils.GenerateExpectation('test1', [self.red, self.red])
- self.ispy_utils.PerformComparison('test', 'test1', self.black)
- self.assertEquals(self.bucket.datastore[
- ispy_utils.GetFailurePath('test', 'test1', 'actual.png')],
- image_tools.EncodePNG(self.black))
- self.ispy_utils.PerformComparison('test', 'test1', self.red)
- self.assertTrue(self.bucket.datastore.has_key(
- ispy_utils.GetFailurePath('test', 'test1', 'actual.png')))
-
- def testGetExpectation(self):
- self.bucket.Reset()
- # Upload some tests to the datastore
- self.ispy_utils.GenerateExpectation('test1', [self.white, self.black])
- self.ispy_utils.GenerateExpectation('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),
- image_tools.EncodePNG(self.white))
- self.assertEquals(image_tools.EncodePNG(test2.expected),
- image_tools.EncodePNG(self.red))
- self.assertEquals(image_tools.EncodePNG(test2.mask),
- image_tools.EncodePNG(self.white))
- # Check that GetExpectation throws an error for a nonexistant test.
- self.assertRaises(
- cloud_bucket.FileNotFoundError, self.ispy_utils.GetExpectation, 'test3')
-
- def testExpectationExists(self):
- self.bucket.Reset()
- self.ispy_utils.GenerateExpectation('test1', [self.white, self.black])
- self.ispy_utils.GenerateExpectation('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.GenerateExpectation('test1', [self.white, self.white])
- self.ispy_utils.PerformComparison('test', 'test1', self.black)
- self.ispy_utils.PerformComparison('test', 'test1', self.white)
- self.assertTrue(self.ispy_utils.FailureExists('test', 'test1'))
- self.assertFalse(self.ispy_utils.FailureExists('test', 'test2'))
-
- def testRemoveExpectation(self):
- self.bucket.Reset()
- self.ispy_utils.GenerateExpectation('test1', [self.white, self.white])
- self.ispy_utils.GenerateExpectation('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.GenerateExpectation('test1', [self.white, self.white])
- self.ispy_utils.GenerateExpectation('test2', [self.white, self.white])
- self.ispy_utils.PerformComparison('test', 'test1', self.black)
- self.ispy_utils.RemoveFailure('test', 'test1')
- self.assertFalse(self.ispy_utils.FailureExists('test', 'test1'))
- self.assertTrue(self.ispy_utils.ExpectationExists('test1'))
- self.assertFalse(self.ispy_utils.FailureExists('test', 'test2'))
- self.assertTrue(self.ispy_utils.ExpectationExists('test2'))
-
- def testGetFailure(self):
- self.bucket.Reset()
- # Upload a result
- self.ispy_utils.GenerateExpectation('test1', [self.red, self.red])
- self.ispy_utils.PerformComparison('test', 'test1', self.black)
- res = self.ispy_utils.GetFailure('test', 'test1')
- # Check that the function correctly got the result.
- self.assertEquals(image_tools.EncodePNG(res.expected),
- image_tools.EncodePNG(self.red))
- self.assertEquals(image_tools.EncodePNG(res.diff),
- image_tools.EncodePNG(self.masked))
- self.assertEquals(image_tools.EncodePNG(res.actual),
- image_tools.EncodePNG(self.black))
- # Check that the function raises an error when given non-existant results.
- self.assertRaises(cloud_bucket.FileNotFoundError,
- self.ispy_utils.GetFailure, 'test', 'test2')
-
- def testGetAllPaths(self):
- self.bucket.Reset()
- # Upload some tests.
- self.ispy_utils.GenerateExpectation('test1', [self.white, self.black])
- # Check that the function gets all urls matching the prefix.
- self.assertEquals(
- set(self.ispy_utils.GetAllPaths(
- ispy_utils.GetExpectationPath('test1'))),
- set([ispy_utils.GetExpectationPath('test1', 'expected.png'),
- ispy_utils.GetExpectationPath('test1', 'mask.png')]))
- self.assertEquals(
- set(self.ispy_utils.GetAllPaths(
- ispy_utils.GetExpectationPath('test3'))), set())
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/chrome/test/functional/ispy/common/mock_cloud_bucket.py b/chrome/test/functional/ispy/common/mock_cloud_bucket.py
deleted file mode 100644
index 803fd57..0000000
--- a/chrome/test/functional/ispy/common/mock_cloud_bucket.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# 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.
-
-"""Subclass of CloudBucket used for testing."""
-
-import os
-import sys
-
-sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
-import cloud_bucket
-
-
-class MockCloudBucket(cloud_bucket.BaseCloudBucket):
- """Subclass of CloudBucket used for testing."""
-
- def __init__(self):
- """Initializes the MockCloudBucket with its datastore.
-
- Returns:
- An instance of MockCloudBucket.
- """
- self.datastore = {}
-
- def Reset(self):
- """Clears the MockCloudBucket's datastore."""
- self.datastore = {}
-
- # override
- def UploadFile(self, path, contents, content_type):
- self.datastore[path] = contents
-
- # override
- def DownloadFile(self, path):
- if self.datastore.has_key(path):
- return self.datastore[path]
- else:
- raise cloud_bucket.FileNotFoundError
-
- # override
- def UpdateFile(self, path, contents):
- if not self.FileExists(path):
- raise cloud_bucket.FileNotFoundError
- self.UploadFile(path, contents, '')
-
- # override
- def RemoveFile(self, path):
- if self.datastore.has_key(path):
- self.datastore.pop(path)
-
- # override
- def FileExists(self, path):
- return self.datastore.has_key(path)
-
- # override
- def GetImageURL(self, path):
- if self.datastore.has_key(path):
- return path
- else:
- raise cloud_bucket.FileNotFoundError
-
- # override
- def GetAllPaths(self, prefix):
- return (item[0] for item in self.datastore.items()
- if item[0].startswith(prefix))
diff --git a/chrome/test/functional/ispy/ispy_api.py b/chrome/test/functional/ispy/ispy_api.py
deleted file mode 100644
index e297368..0000000
--- a/chrome/test/functional/ispy/ispy_api.py
+++ /dev/null
@@ -1,229 +0,0 @@
-# Copyright 2014 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.
-
-import json
-import logging
-import os
-from distutils.version import LooseVersion
-from PIL import Image
-
-from common import cloud_bucket
-from common import ispy_utils
-
-
-class ISpyApi(object):
- """The public API for interacting with ISpy."""
-
- def __init__(self, cloud_bucket):
- """Initializes the utility class.
-
- Args:
- cloud_bucket: a BaseCloudBucket in which to the version file,
- expectations and results are to be stored.
- """
- self._cloud_bucket = cloud_bucket
- self._ispy = ispy_utils.ISpyUtils(self._cloud_bucket)
- self._rebaselineable_cache = {}
-
- def UpdateExpectationVersion(self, chrome_version, version_file):
- """Updates the most recent expectation version to the Chrome version.
-
- Should be called after generating a new set of expectations.
-
- Args:
- chrome_version: the chrome version as a string of the form "31.0.123.4".
- version_file: path to the version file in the cloud bucket. The version
- file contains a json list of ordered Chrome versions for which
- expectations exist.
- """
- insert_pos = 0
- expectation_versions = []
- try:
- expectation_versions = self._GetExpectationVersionList(version_file)
- if expectation_versions:
- try:
- version = self._GetExpectationVersion(
- chrome_version, expectation_versions)
- if version == chrome_version:
- return
- insert_pos = expectation_versions.index(version)
- except:
- insert_pos = len(expectation_versions)
- except cloud_bucket.FileNotFoundError:
- pass
- expectation_versions.insert(insert_pos, chrome_version)
- logging.info('Updating expectation version...')
- self._cloud_bucket.UploadFile(
- version_file, json.dumps(expectation_versions),
- 'application/json')
-
- def _GetExpectationVersion(self, chrome_version, expectation_versions):
- """Returns the expectation version for the given Chrome version.
-
- Args:
- chrome_version: the chrome version as a string of the form "31.0.123.4".
- expectation_versions: Ordered list of Chrome versions for which
- expectations exist, as stored in the version file.
-
- Returns:
- Expectation version string.
- """
- # Find the closest version that is not greater than the chrome version.
- for version in expectation_versions:
- if LooseVersion(version) <= LooseVersion(chrome_version):
- return version
- raise Exception('No expectation exists for Chrome %s' % chrome_version)
-
- def _GetExpectationVersionList(self, version_file):
- """Gets the list of expectation versions from google storage.
-
- Args:
- version_file: path to the version file in the cloud bucket. The version
- file contains a json list of ordered Chrome versions for which
- expectations exist.
-
- Returns:
- Ordered list of Chrome versions.
- """
- try:
- return json.loads(self._cloud_bucket.DownloadFile(version_file))
- except:
- return []
-
- def _GetExpectationNameWithVersion(self, device_type, expectation,
- chrome_version, version_file):
- """Get the expectation to be used with the current Chrome version.
-
- Args:
- device_type: string identifier for the device type.
- expectation: name for the expectation to generate.
- chrome_version: the chrome version as a string of the form "31.0.123.4".
-
- Returns:
- Version as an integer.
- """
- version = self._GetExpectationVersion(
- chrome_version, self._GetExpectationVersionList(version_file))
- return self._CreateExpectationName(device_type, expectation, version)
-
- def _CreateExpectationName(self, device_type, expectation, version):
- """Create the full expectation name from the expectation and version.
-
- Args:
- device_type: string identifier for the device type, example: mako
- expectation: base name for the expectation, example: google.com
- version: expectation version, example: 31.0.23.1
-
- Returns:
- Full expectation name as a string, example: mako:google.com(31.0.23.1)
- """
- return '%s:%s(%s)' % (device_type, expectation, version)
-
- def GenerateExpectation(self, device_type, expectation, chrome_version,
- version_file, screenshots):
- """Create an expectation for I-Spy.
-
- Args:
- device_type: string identifier for the device type.
- expectation: name for the expectation to generate.
- chrome_version: the chrome version as a string of the form "31.0.123.4".
- screenshots: a list of similar PIL.Images.
- """
- # https://code.google.com/p/chromedriver/issues/detail?id=463
- expectation_with_version = self._CreateExpectationName(
- device_type, expectation, chrome_version)
- if self._ispy.ExpectationExists(expectation_with_version):
- logging.warning(
- 'I-Spy expectation \'%s\' already exists, overwriting.',
- expectation_with_version)
- logging.info('Generating I-Spy expectation...')
- self._ispy.GenerateExpectation(expectation_with_version, screenshots)
-
- def PerformComparison(self, test_run, device_type, expectation,
- chrome_version, version_file, screenshot):
- """Compare a screenshot with the given expectation in I-Spy.
-
- Args:
- test_run: name for the test run.
- device_type: string identifier for the device type.
- expectation: name for the expectation to compare against.
- chrome_version: the chrome version as a string of the form "31.0.123.4".
- screenshot: a PIL.Image to compare.
- """
- # https://code.google.com/p/chromedriver/issues/detail?id=463
- logging.info('Performing I-Spy comparison...')
- self._ispy.PerformComparison(
- test_run,
- self._GetExpectationNameWithVersion(
- device_type, expectation, chrome_version, version_file),
- screenshot)
-
- def CanRebaselineToTestRun(self, test_run):
- """Returns whether the test run has associated expectations.
-
- Returns:
- True if RebaselineToTestRun() can be called for this test run.
- """
- if test_run in self._rebaselineable_cache:
- return True
- return self._cloud_bucket.FileExists(
- ispy_utils.GetTestRunPath(test_run, 'rebaseline.txt'))
-
- def RebaselineToTestRun(self, test_run):
- """Update the version file to use expectations associated with |test_run|.
-
- Args:
- test_run: The name of the test run to rebaseline.
- """
- rebaseline_path = ispy_utils.GetTestRunPath(test_run, 'rebaseline.txt')
- rebaseline_attrib = json.loads(
- self._cloud_bucket.DownloadFile(rebaseline_path))
- self.UpdateExpectationVersion(
- rebaseline_attrib['version'], rebaseline_attrib['version_file'])
- self._cloud_bucket.RemoveFile(rebaseline_path)
-
- def _SetTestRunRebaselineable(self, test_run, chrome_version, version_file):
- """Writes a JSON file containing the data needed to rebaseline.
-
- Args:
- test_run: The name of the test run to add the rebaseline file to.
- chrome_version: the chrome version that can be rebaselined to (must have
- associated Expectations).
- version_file: the path of the version file associated with the test run.
- """
- self._rebaselineable_cache[test_run] = True
- self._cloud_bucket.UploadFile(
- ispy_utils.GetTestRunPath(test_run, 'rebaseline.txt'),
- json.dumps({
- 'version': chrome_version,
- 'version_file': version_file}),
- 'application/json')
-
- def PerformComparisonAndPrepareExpectation(self, test_run, device_type,
- expectation, chrome_version,
- version_file, screenshots):
- """Perform comparison and generate an expectation that can used later.
-
- The test run web UI will have a button to set the Expectations generated for
- this version as the expectation for comparison with later versions.
-
- Args:
- test_run: The name of the test run to add the rebaseline file to.
- device_type: string identifier for the device type.
- chrome_version: the chrome version that can be rebaselined to (must have
- associated Expectations).
- version_file: the path of the version file associated with the test run.
- screenshot: a list of similar PIL.Images.
- """
- if not self.CanRebaselineToTestRun(test_run):
- self._SetTestRunRebaselineable(test_run, chrome_version, version_file)
- expectation_with_version = self._CreateExpectationName(
- device_type, expectation, chrome_version)
- self._ispy.GenerateExpectation(expectation_with_version, screenshots)
- self._ispy.PerformComparison(
- test_run,
- self._GetExpectationNameWithVersion(
- device_type, expectation, chrome_version, version_file),
- screenshots[-1])
-
diff --git a/chrome/test/functional/ispy/ispy_api_unittest.py b/chrome/test/functional/ispy/ispy_api_unittest.py
deleted file mode 100755
index 2e6a476..0000000
--- a/chrome/test/functional/ispy/ispy_api_unittest.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2014 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.
-
-import json
-import unittest
-from PIL import Image
-
-import ispy_api
-from common import cloud_bucket
-from common import mock_cloud_bucket
-
-
-class ISpyApiTest(unittest.TestCase):
- """Unittest for the ISpy API."""
-
- def setUp(self):
- self.cloud_bucket = mock_cloud_bucket.MockCloudBucket()
- self.ispy = ispy_api.ISpyApi(self.cloud_bucket)
- self.white_img = Image.new('RGBA', (10, 10), (255, 255, 255, 255))
- self.black_img = Image.new('RGBA', (10, 10), (0, 0, 0, 255))
-
- def testGenerateExpectationsRunComparison(self):
- self.ispy.GenerateExpectation(
- 'device', 'test', '1.1.1.1', 'versions.json',
- [self.white_img, self.white_img])
- self.ispy.UpdateExpectationVersion('1.1.1.1', 'versions.json')
- self.ispy.PerformComparison(
- 'test1', 'device', 'test', '1.1.1.1', 'versions.json', self.white_img)
- expect_name = self.ispy._CreateExpectationName(
- 'device', 'test', '1.1.1.1')
- self.assertFalse(self.ispy._ispy.FailureExists('test1', expect_name))
- self.ispy.PerformComparison(
- 'test2', 'device', 'test', '1.1.1.1','versions.json', self.black_img)
- self.assertTrue(self.ispy._ispy.FailureExists('test2', expect_name))
-
- def testUpdateExpectationVersion(self):
- self.ispy.UpdateExpectationVersion('1.0.0.0', 'versions.json')
- self.ispy.UpdateExpectationVersion('1.0.4.0', 'versions.json')
- self.ispy.UpdateExpectationVersion('2.1.5.0', 'versions.json')
- self.ispy.UpdateExpectationVersion('1.1.5.0', 'versions.json')
- self.ispy.UpdateExpectationVersion('0.0.0.0', 'versions.json')
- self.ispy.UpdateExpectationVersion('1.1.5.0', 'versions.json')
- self.ispy.UpdateExpectationVersion('0.0.0.1', 'versions.json')
- versions = json.loads(self.cloud_bucket.DownloadFile('versions.json'))
- self.assertEqual(versions,
- ['2.1.5.0', '1.1.5.0', '1.0.4.0', '1.0.0.0', '0.0.0.1', '0.0.0.0'])
-
- def testPerformComparisonAndPrepareExpectation(self):
- self.assertFalse(self.ispy.CanRebaselineToTestRun('test'))
- self.assertRaises(
- cloud_bucket.FileNotFoundError,
- self.ispy.PerformComparisonAndPrepareExpectation,
- 'test', 'device', 'expect', '1.0', 'versions.json',
- [self.white_img, self.white_img])
- self.assertTrue(self.ispy.CanRebaselineToTestRun('test'))
- self.ispy.RebaselineToTestRun('test')
- versions = json.loads(self.cloud_bucket.DownloadFile('versions.json'))
- self.assertEqual(versions, ['1.0'])
- self.ispy.PerformComparisonAndPrepareExpectation(
- 'test1', 'device', 'expect', '1.1', 'versions.json',
- [self.white_img, self.white_img])
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/chrome/test/functional/ispy/server/__init__.py b/chrome/test/functional/ispy/server/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/chrome/test/functional/ispy/server/__init__.py
+++ /dev/null
diff --git a/chrome/test/functional/ispy/server/app.py b/chrome/test/functional/ispy/server/app.py
deleted file mode 100644
index 6e90804..0000000
--- a/chrome/test/functional/ispy/server/app.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# 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.
-
-import os
-import sys
-import webapp2
-
-sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
-import debug_view_handler
-import image_handler
-import main_view_handler
-import rebaseline_handler
-import update_mask_handler
-
-
-application = webapp2.WSGIApplication(
- [('/update_mask', update_mask_handler.UpdateMaskHandler),
- ('/rebaseline', rebaseline_handler.RebaselineHandler),
- ('/debug_view', debug_view_handler.DebugViewHandler),
- ('/image', image_handler.ImageHandler),
- ('/', main_view_handler.MainViewHandler)], debug=True)
diff --git a/chrome/test/functional/ispy/server/debug_view_handler.py b/chrome/test/functional/ispy/server/debug_view_handler.py
deleted file mode 100644
index 96bfe3c..0000000
--- a/chrome/test/functional/ispy/server/debug_view_handler.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# 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.
-
-"""Request handler to display the debug view for a Failure."""
-
-import jinja2
-import os
-import sys
-import webapp2
-
-from common import ispy_utils
-
-import views
-
-JINJA = jinja2.Environment(
- loader=jinja2.FileSystemLoader(os.path.dirname(views.__file__)),
- extensions=['jinja2.ext.autoescape'])
-
-
-class DebugViewHandler(webapp2.RequestHandler):
- """Request handler to display the debug view for a failure."""
-
- def get(self):
- """Handles get requests to the /debug_view page.
-
- GET Parameters:
- test_run: The test run.
- expectation: The expectation name.
- """
- test_run = self.request.get('test_run')
- 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):
- return '/image?file_path=%s' % url
-
- data['expected'] = _ImagePath(expected_path)
- data['actual'] = _ImagePath(actual_path)
- data['test_run'] = test_run
- data['expectation'] = expectation
- template = JINJA.get_template('debug_view.html')
- self.response.write(template.render(data))
diff --git a/chrome/test/functional/ispy/server/gs_bucket.py b/chrome/test/functional/ispy/server/gs_bucket.py
deleted file mode 100644
index a132f05..0000000
--- a/chrome/test/functional/ispy/server/gs_bucket.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# 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.
-
-"""Implementation of CloudBucket using Google Cloud Storage as the backend."""
-import os
-import sys
-
-import cloudstorage
-
-from common import cloud_bucket
-
-
-class GoogleCloudStorageBucket(cloud_bucket.BaseCloudBucket):
- """Subclass of cloud_bucket.CloudBucket with actual GS commands."""
-
- def __init__(self, bucket):
- """Initializes the bucket.
-
- Args:
- bucket: the name of the bucket to connect to.
- """
- self.bucket = '/' + bucket
-
- def _full_path(self, path):
- return self.bucket + '/' + path.lstrip('/')
-
- # override
- def UploadFile(self, path, contents, content_type):
- gs_file = cloudstorage.open(
- self._full_path(path), 'w', content_type=content_type)
- gs_file.write(contents)
- gs_file.close()
-
- # override
- def DownloadFile(self, path):
- try:
- gs_file = cloudstorage.open(self._full_path(path), 'r')
- r = gs_file.read()
- gs_file.close()
- except Exception as e:
- raise Exception('%s: %s' % (self._full_path(path), str(e)))
- return r
-
- # override
- def UpdateFile(self, path, contents):
- if not self.FileExists(path):
- raise cloud_bucket.FileNotFoundError
- gs_file = cloudstorage.open(self._full_path(path), 'w')
- gs_file.write(contents)
- gs_file.close()
-
- # override
- def RemoveFile(self, path):
- cloudstorage.delete(self._full_path(path))
-
- # override
- def FileExists(self, path):
- try:
- cloudstorage.stat(self._full_path(path))
- except cloudstorage.NotFoundError:
- return False
- return True
-
- # override
- def GetImageURL(self, path):
- return '/image?file_path=%s' % path
-
- # override
- def GetAllPaths(self, prefix):
- return (f.filename[len(self.bucket) + 1:] for f in
- cloudstorage.listbucket(self.bucket, prefix=prefix))
diff --git a/chrome/test/functional/ispy/server/image_handler.py b/chrome/test/functional/ispy/server/image_handler.py
deleted file mode 100644
index d1f11f2..0000000
--- a/chrome/test/functional/ispy/server/image_handler.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# 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.
-
-"""Request handler to display an image from Google Cloud Storage."""
-
-import json
-import os
-import sys
-import webapp2
-
-from common import cloud_bucket
-from common import constants
-
-import gs_bucket
-
-
-class ImageHandler(webapp2.RequestHandler):
- """A request handler to avoid the Same-Origin problem in the debug view."""
-
- def get(self):
- """Handles get requests to the ImageHandler.
-
- GET Parameters:
- file_path: A path to an image resource in Google Cloud Storage.
- """
- file_path = self.request.get('file_path')
- if not file_path:
- self.error(404)
- return
- bucket = gs_bucket.GoogleCloudStorageBucket(constants.BUCKET)
- try:
- image = bucket.DownloadFile(file_path)
- except cloud_bucket.FileNotFoundError:
- self.error(404)
- else:
- self.response.headers['Content-Type'] = 'image/png'
- self.response.out.write(image)
diff --git a/chrome/test/functional/ispy/server/main_view_handler.py b/chrome/test/functional/ispy/server/main_view_handler.py
deleted file mode 100644
index 0738a0c..0000000
--- a/chrome/test/functional/ispy/server/main_view_handler.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# 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.
-
-"""Request handler to serve the main_view page."""
-
-import jinja2
-import json
-import os
-import re
-import sys
-import webapp2
-
-import ispy_api
-from common import constants
-from common import ispy_utils
-
-import gs_bucket
-import views
-
-JINJA = jinja2.Environment(
- loader=jinja2.FileSystemLoader(os.path.dirname(views.__file__)),
- extensions=['jinja2.ext.autoescape'])
-
-
-class MainViewHandler(webapp2.RequestHandler):
- """Request handler to serve the main_view page."""
-
- def get(self):
- """Handles a get request to the main_view page.
-
- If the test_run parameter is specified, then a page displaying all of
- the failed runs in the test_run will be shown. Otherwise a view listing
- all of the test_runs available for viewing will be displayed.
- """
- test_run = self.request.get('test_run')
- bucket = gs_bucket.GoogleCloudStorageBucket(constants.BUCKET)
- ispy = ispy_utils.ISpyUtils(bucket)
- # Load the view.
- if test_run:
- self._GetForTestRun(test_run, ispy)
- return
- self._GetAllTestRuns(ispy)
-
- def _GetAllTestRuns(self, ispy):
- """Renders a list view of all of the test_runs available in GS.
-
- Args:
- ispy: An instance of ispy_api.ISpyApi.
- """
- template = JINJA.get_template('list_view.html')
- data = {}
- 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))
-
- def _GetForTestRun(self, test_run, ispy):
- """Renders a sorted list of failure-rows for a given test_run.
-
- This method will produce a list of failure-rows that are sorted
- in descending order by number of different pixels.
-
- Args:
- test_run: The name of the test_run to render failure rows from.
- ispy: An instance of ispy_api.ISpyApi.
- """
- paths = set([path for path in ispy.GetAllPaths('failures/' + test_run)
- if path.endswith('actual.png')])
- can_rebaseline = ispy_api.ISpyApi(
- ispy.cloud_bucket).CanRebaselineToTestRun(test_run)
- rows = [self._CreateRow(test_run, path, ispy) for path in paths]
-
- # Function that sorts by the different_pixels field in the failure-info.
- 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),
- 'test_run': test_run,
- 'can_rebaseline': can_rebaseline}))
-
- def _CreateRow(self, test_run, path, ispy):
- """Creates one failure-row.
-
- This method builds a dictionary with the data necessary to display a
- failure in the main_view html template.
-
- Args:
- test_run: The name of the test_run the failure is in.
- path: A path to the failure's actual.png file.
- ispy: An instance of ispy_api.ISpyApi.
-
- Returns:
- A dictionary with fields necessary to render a failure-row
- in the main_view html template.
- """
- res = {}
- 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['expectation'],
- 'info.txt')))
- 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
- res['expected'] = ispy.cloud_bucket.GetImageURL(expected)
- res['diff'] = ispy.cloud_bucket.GetImageURL(diff)
- res['actual'] = ispy.cloud_bucket.GetImageURL(path)
- return res
diff --git a/chrome/test/functional/ispy/server/rebaseline_handler.py b/chrome/test/functional/ispy/server/rebaseline_handler.py
deleted file mode 100644
index 81bdb4b..0000000
--- a/chrome/test/functional/ispy/server/rebaseline_handler.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright 2014 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.
-
-"""Request Handler that updates the Expectation version."""
-
-import webapp2
-
-import ispy_api
-from common import constants
-
-import gs_bucket
-
-
-class RebaselineHandler(webapp2.RequestHandler):
- """Request handler to allow test mask updates."""
-
- def post(self):
- """Accepts post requests.
-
- Expects a test_run as a parameter and updates the associated version file to
- use the expectations associated with that test run.
- """
- test_run = self.request.get('test_run')
-
- # Fail if test_run parameter is missing.
- if not test_run:
- self.response.headers['Content-Type'] = 'json/application'
- self.response.write(json.dumps(
- {'error': '\'test_run\' must be supplied to rebaseline.'}))
- return
- # Otherwise, set up the utilities.
- bucket = gs_bucket.GoogleCloudStorageBucket(constants.BUCKET)
- ispy = ispy_api.ISpyApi(bucket)
- # Update versions file.
- ispy.RebaselineToTestRun(test_run)
- # 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/update_mask_handler.py b/chrome/test/functional/ispy/server/update_mask_handler.py
deleted file mode 100644
index 10cb964..0000000
--- a/chrome/test/functional/ispy/server/update_mask_handler.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# 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.
-
-"""Request Handler to allow test mask updates."""
-
-import webapp2
-import re
-import sys
-import os
-
-from common import constants
-from common import image_tools
-from common import ispy_utils
-
-import gs_bucket
-
-
-class UpdateMaskHandler(webapp2.RequestHandler):
- """Request handler to allow test mask updates."""
-
- def post(self):
- """Accepts post requests.
-
- This method will accept a post request containing device, site and
- device_id parameters. This method takes the diff of the run
- indicated by it's parameters and adds it to the mask of the run's
- test. It will then delete the run it is applied to and redirect
- to the device list view.
- """
- test_run = self.request.get('test_run')
- expectation = self.request.get('expectation')
-
- # Short-circuit if a parameter is missing.
- if not (test_run and expectation):
- self.response.headers['Content-Type'] = 'json/application'
- self.response.write(json.dumps(
- {'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, expectation):
- self.response.headers['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, expectation)
- # Upload the new mask in place of the original.
- self.ispy.UpdateImage(
- ispy_utils.GetExpectationPath(expectation, 'mask.png'),
- image_tools.ConvertDiffToMask(failure.diff))
- # 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/__init__.py b/chrome/test/functional/ispy/server/views/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/chrome/test/functional/ispy/server/views/__init__.py
+++ /dev/null
diff --git a/chrome/test/functional/ispy/server/views/debug_view.html b/chrome/test/functional/ispy/server/views/debug_view.html
deleted file mode 100644
index 8371280..0000000
--- a/chrome/test/functional/ispy/server/views/debug_view.html
+++ /dev/null
@@ -1,47 +0,0 @@
-<html>
- <head>
- <title>Debug {{ expectation }}</title>
- <script language="javascript">
- var current = 0;
- var toggle_interval = null;
-
- var toggle = function() {
- current = (current + 1) % 2;
- var image = document.getElementById("screenshot");
- image.src = (current ? "{{ actual }}" : "{{ expected }}");
- var title = document.getElementById("text");
- title.textContent = (current ? "Actual" : "Expected");
- }
-
- var setup = function() {
- toggle();
- toggle_interval = window.setInterval(toggle, 1000);
- }
-
- var manualToggle = function() {
- if (toggle_interval != null)
- window.clearInterval(toggle_interval);
- toggle();
- }
-
- var confirmSubmit = function() {
- return confirm("The area in this diff will be ignored in all future comparisions. Are you sure?");
- }
- </script>
- </head>
- <body onload="setup();">
- <div>
- <a href="javascript:void(0)" onclick="manualToggle();">Toggle</a>
- &nbsp;&#8594;&nbsp;
- <span id="text"></span>
- </div>
- <br>
- <form action="/update_mask" method="post" onsubmit="return confirmSubmit();">
- <input type="hidden" name="test_run" value="{{ test_run }}"/>
- <input type="hidden" name="expectation" value="{{ expectation }}"/>
- <input type="submit" value="Ignore similar diffs in the future"/>
- </form>
- <br>
- <img id="screenshot" src=""/>
- </body>
-</html>
diff --git a/chrome/test/functional/ispy/server/views/list_view.html b/chrome/test/functional/ispy/server/views/list_view.html
deleted file mode 100644
index f6b5dc6..0000000
--- a/chrome/test/functional/ispy/server/views/list_view.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-{% autoescape on %}
-<html>
- <head>
- <title>I-Spy Test Runs</title>
- <style>
- #container {
- display: table;
- background-color:#DDD;
- border: 1px solid #AAA;
- width: 400px;
- margin: 5px;
- padding: 5px;
- }
- </style>
- </head>
- <body>
- <h3>Test Runs</h3>
- <div id="container">
- {% for link in links %}
- <div>
- <a href="{{ link[1] }}">{{ link[0] }}</a>
- </div>
- {% endfor %}
- </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
deleted file mode 100644
index d722c6a..0000000
--- a/chrome/test/functional/ispy/server/views/main_view.html
+++ /dev/null
@@ -1,78 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>{{ test_run }} failures</title>
- <style>
- .image {
- max-height: 325px;
- max-width: 325px;
- }
- .cell {
- padding-right: 25px;
- padding-left: 25px;
- float: left;
- width: 20%;
- }
- .imagelink {
- border-width: 0px;
- }
- .info {
- padding-bottom: 25px;
- }
- .row {
- padding-top: 10px;
- padding-bottom: 10px;
- border-bottom: 2px solid #888;
- height: 350px;
- }
- </style>
-
- <script language="javascript">
- var confirmSubmit = function() {
- return confirm("The screenshots generated with this version of chrome will be used as the expected images for future comparisions. Are you sure?");
- }
- </script>
- </head>
- <body>
- <h3>Test Run: {{ test_run }}</h3>
- {% if can_rebaseline %}
- <form action="/rebaseline" method="post" onsubmit="return confirmSubmit();">
- <input type="hidden" name="test_run" value="{{ test_run }}"/>
- <input type="submit" value="Set as LKGR"/>
- </form>
- <br>
- {% endif %}
- {% if not comparisons %}
- <h2>No failures.</h2>
- {% endif %}
- {% for comp in comparisons %}
- <div class="row">
- <div class="cell">
- Diff&nbsp;&nbsp;({{ "%.1f"|format(comp['percent_different']) }}%)<br>
- <a class="imagelink" href="{{ comp['diff'] }}">
- <img class="image" src={{ comp['diff'] }}>
- </a>
- </div>
- <div class="cell">
- Expected<br>
- <a class="imagelink" href="{{ comp['expected'] }}">
- <img class="image" src={{ comp['expected'] }}>
- </a>
- </div>
- <div class="cell">
- Actual<br>
- <a class="imagelink" href="{{ comp['actual'] }}">
- <img class="image" src={{ comp['actual'] }}>
- </a>
- </div>
- <div class="cell">
- <br>
- <div class="info">
- {{ comp['expectation'] }}<br>
- <a href='/debug_view?test_run={{ comp['test_run'] }}&expectation={{ comp['expectation'] }}'>Debug View</a>
- </div>
- </div>
- </div>
- {% endfor %}
- </body>
-</html>
diff --git a/chrome/test/functional/media/OWNERS b/chrome/test/functional/media/OWNERS
deleted file mode 100644
index aa43ab1..0000000
--- a/chrome/test/functional/media/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-dalecurtis@chromium.org
-scherkus@chromium.org
-shadi@chromium.org
diff --git a/chrome/test/functional/media/README b/chrome/test/functional/media/README
deleted file mode 100644
index 36a5c5a..0000000
--- a/chrome/test/functional/media/README
+++ /dev/null
@@ -1,49 +0,0 @@
-HTML5 Media Performance/Functional Test
-=======================================
-
-Description
------------
-This directory contains suites for HTML5 media performance/functional tests.
-
-media_test_runner.py is the main module and it executes a media test
-class (a subclass of MediaTastBase class) with different configuration
-(parameters) which are passed in the form of environment variables
-(e.g., the number of runs). The location of the subclass is passed as
-one of the arguments.
-
-An example invocation is
- python media_test_runner.py -p ./media_perf.py
-
-In this example, media_perf.py will be invoked using the default set
-of parameters. If the test class is not specified in the argument,
-whole AVPERF suite is executed, which is defined in
-src/chrome/test/functional/PYAUTO_TESTS.
-
-To Run Tests
-------------
-0) Build pyauto (http://www.chromium.org/developers/testing/pyauto)
-
-1) Add the following in the .gclient and execute "gclient sync". This step is
-necessary to pull the test video/audio from deps.
-
-"custom_deps" : {
- "src/chrome/test/data/media/avperf":
- "http://src.chromium.org/svn/trunk/deps/avperf",
-},
-
-2) Execute "python media_test_runner.py" from "src/chrome/test/functional"
-directory. Available options can be obtained by "media_test_runner.py -h"
-
-3) The results are reported to the standard output. An example output is
-
-RESULT time: t= [0.01182, 0.00995, 2.02328, 2.02021] sec
-RESULT procutil: p= [14.10000, 15.20000, 9.10000, 9.00000] percent
-RESULT procuser: l= [0.54000, 0.88000, 0.74000, 1.08000] load
-RESULT procsystem: l= [0.06000, 0.11000, 0.09000, 0.13000] load
-RESULT memoryrss: m= [34.74637, 35.27885, 34.46374, 35.60243] MB
-RESULT memoryvms: m= [1001.08288, 1001.34502, 1001.08288, 1001.34502] MB
-RESULT memoryutil: p= [0.87187, 0.88523, 0.86478, 0.89335] percent
-
-This data is read by the perfbot and used for displaying perf graphs and
-regression monitoring. The perfbot link is
-http://build.chromium.org/p/chromium.perf_av/console.
diff --git a/chrome/test/functional/media/__init__.py b/chrome/test/functional/media/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/chrome/test/functional/media/__init__.py
+++ /dev/null
diff --git a/chrome/test/functional/media/audio_latency_perf.py b/chrome/test/functional/media/audio_latency_perf.py
deleted file mode 100755
index 3775457..0000000
--- a/chrome/test/functional/media/audio_latency_perf.py
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Audio latency performance test.
-
-Benchmark measuring how fast we can continuously repeat a short sound clip. In
-the ideal scenario we'd have zero latency processing script, seeking back to the
-beginning of the clip, and resuming audio playback.
-
-Performance is recorded as the average latency of N playbacks. I.e., if we play
-a clip 50 times and the ideal duration of all playbacks is 1000ms and the total
-duration is 1500ms, the recorded result is (1500ms - 1000ms) / 50 == 10ms.
-"""
-import os
-
-import pyauto_media
-import pyauto_utils
-import pyauto
-
-
-# HTML test path; relative to src/chrome/test/data.
-_TEST_HTML_PATH = os.path.join('media', 'html', 'audio_latency_perf.html')
-
-
-class AudioLatencyPerfTest(pyauto.PyUITest):
- """PyAuto test container. See file doc string for more information."""
-
- def testAudioLatency(self):
- """Launches HTML test which runs the audio latency test."""
- self.NavigateToURL(self.GetFileURLForDataPath(_TEST_HTML_PATH))
-
- # Block until the test finishes and notifies us.
- self.assertTrue(self.ExecuteJavascript('startTest();'))
- latency = float(self.GetDOMValue('averageLatency'))
- pyauto_utils.PrintPerfResult('audio_latency', 'latency', latency, 'ms')
-
-
-if __name__ == '__main__':
- pyauto_media.Main()
diff --git a/chrome/test/functional/media/audio_playback_perf.py b/chrome/test/functional/media/audio_playback_perf.py
deleted file mode 100755
index 1b91351..0000000
--- a/chrome/test/functional/media/audio_playback_perf.py
+++ /dev/null
@@ -1,103 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Audio basic playback test. Verifies basic audio output.
-
-The tests plays an audio file and records its output while playing. It uses
-SOX tool to eliminate silence from begining and end of audio recorded. Then it
-uses PESQ tool to verify the recorded audio against expected file.
-
-The output of PESQ is a pair of numbers between 0 and 5 describing how close the
-recorded audio is to its reference file.
-
-The output of this test are the PESQ values that are graphed, example:
-RESULT audio_pesq: ref= 4.498 score
-RESULT audio_pesq: actual= 4.547 score
-"""
-
-import logging
-import os
-import sys
-import tempfile
-
-import audio_tools
-import pyauto_media
-import pyauto
-import pyauto_utils
-
-
-_TEST_HTML_PATH = pyauto.PyUITest.GetFileURLForDataPath('media', 'html',
- 'audio_record.html')
-_MEDIA_PATH = os.path.abspath(os.path.join(pyauto.PyUITest.DataDir(),
- 'pyauto_private', 'media'))
-
-# The media file to play.
-_TEST_AUDIO = pyauto.PyUITest.GetFileURLForPath(_MEDIA_PATH, 'dance2_10sec.wav')
-# The recording duration should be at least as the media duration. We use 5
-# extra seconds of record in this test.
-_RECORD_DURATION = 15
-
-# Due to different noise introduced by audio recording tools on windows and
-# linux, we require an expected audio file per platform.
-if 'win32' in sys.platform:
- _TEST_EXPECTED_AUDIO = os.path.join(_MEDIA_PATH, 'audio_record_win.wav')
-else:
- _TEST_EXPECTED_AUDIO = os.path.join(_MEDIA_PATH, 'audio_record_lin.wav')
-
-
-def GetTempFilename():
- """Returns an absolute path to an empty temp file."""
- f, path = tempfile.mkstemp(suffix='_actual.wav')
- os.close(f)
- return path
-
-
-class AudioRecordPerfTest(pyauto.PyUITest):
- """PyAuto test container. See file doc string for more information."""
-
- def testBasicAudioPlaybackRecord(self):
- """Plays an audio file and verifies its output against expected."""
- # The 2 temp files that will be potentially used in the test.
- temp_file = None
- file_no_silence = None
- # Rebase test expectation file is REBASE=1 env variable is set.
- rebase = 'REBASE' in os.environ
-
- try:
- temp_file = GetTempFilename()
- record_thread = audio_tools.AudioRecorderThread(_RECORD_DURATION,
- temp_file)
- record_thread.start()
- self.NavigateToURL(_TEST_HTML_PATH)
- self.assertTrue(self.ExecuteJavascript("startTest('%s');" % _TEST_AUDIO))
- record_thread.join()
-
- if record_thread.error:
- self.fail(record_thread.error)
- file_no_silence = _TEST_EXPECTED_AUDIO if rebase else GetTempFilename()
- audio_tools.RemoveSilence(temp_file, file_no_silence)
-
- # Exit if we just want to rebase expected output.
- if rebase:
- return
-
- pesq_values = audio_tools.RunPESQ(_TEST_EXPECTED_AUDIO, file_no_silence)
- if not pesq_values:
- self.fail('Test failed to get pesq results.')
- pyauto_utils.PrintPerfResult('audio_pesq', 'ref', pesq_values[0], 'score')
- pyauto_utils.PrintPerfResult('audio_pesq', 'actual', pesq_values[1],
- 'score')
- except:
- logging.error('Test failed: %s', self.GetDOMValue('error'))
- finally:
- # Delete the temporary files used by the test.
- if temp_file:
- os.remove(temp_file)
- if not rebase and file_no_silence:
- os.remove(file_no_silence)
-
-
-if __name__ == '__main__':
- pyauto_media.Main()
diff --git a/chrome/test/functional/media/audio_tools.py b/chrome/test/functional/media/audio_tools.py
deleted file mode 100755
index 3b14a7c..0000000
--- a/chrome/test/functional/media/audio_tools.py
+++ /dev/null
@@ -1,168 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Audio tools for recording and analyzing audio.
-
-The audio tools provided here are mainly to:
-- record playing audio.
-- remove silence from beginning and end of audio file.
-- compare audio files using PESQ tool.
-
-The tools are supported on Windows and Linux.
-"""
-
-import commands
-import ctypes
-import logging
-import os
-import re
-import subprocess
-import sys
-import threading
-import time
-
-import pyauto_media
-import pyauto
-
-
-_TOOLS_PATH = os.path.abspath(os.path.join(pyauto.PyUITest.DataDir(),
- 'pyauto_private', 'media', 'tools'))
-
-WINDOWS = 'win32' in sys.platform
-if WINDOWS:
- _PESQ_PATH = os.path.join(_TOOLS_PATH, 'pesq.exe')
- _SOX_PATH = os.path.join(_TOOLS_PATH, 'sox.exe')
- _AUDIO_RECORDER = r'SoundRecorder.exe'
- _FORCE_MIC_VOLUME_MAX_UTIL = os.path.join(_TOOLS_PATH,
- r'force_mic_volume_max.exe')
-else:
- _PESQ_PATH = os.path.join(_TOOLS_PATH, 'pesq')
- _SOX_PATH = commands.getoutput('which sox')
- _AUDIO_RECORDER = commands.getoutput('which arecord')
- _PACMD_PATH = commands.getoutput('which pacmd')
-
-
-class AudioRecorderThread(threading.Thread):
- """A thread that records audio out of the default audio output."""
-
- def __init__(self, duration, output_file, record_mono=False):
- threading.Thread.__init__(self)
- self.error = ''
- self._duration = duration
- self._output_file = output_file
- self._record_mono = record_mono
-
- def run(self):
- """Starts audio recording."""
- if WINDOWS:
- if self._record_mono:
- logging.error("Mono recording not supported on Windows yet!")
-
- duration = time.strftime('%H:%M:%S', time.gmtime(self._duration))
- cmd = [_AUDIO_RECORDER, '/FILE', self._output_file, '/DURATION',
- duration]
- # This is needed to run SoundRecorder.exe on Win-64 using Python-32 bit.
- ctypes.windll.kernel32.Wow64DisableWow64FsRedirection(
- ctypes.byref(ctypes.c_long()))
- else:
- num_channels = 1 if self._record_mono else 2
- cmd = [_AUDIO_RECORDER, '-d', self._duration, '-f', 'dat', '-c',
- str(num_channels), self._output_file]
-
- cmd = [str(s) for s in cmd]
- logging.debug('Running command: %s', ' '.join(cmd))
- returncode = subprocess.call(cmd, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- if returncode != 0:
- self.error = 'Failed to record audio.'
- else:
- logging.debug('Finished recording audio into %s.', self._output_file)
-
-
-def RunPESQ(audio_file_ref, audio_file_test, sample_rate=16000):
- """Runs PESQ to compare audio test file to a reference audio file.
-
- Args:
- audio_file_ref: The reference audio file used by PESQ.
- audio_file_test: The audio test file to compare.
- sample_rate: Sample rate used by PESQ algorithm, possible values are only
- 8000 or 16000.
-
- Returns:
- A tuple of float values representing PESQ scores of the audio_file_ref and
- audio_file_test consecutively.
- """
- # Work around a bug in PESQ when the ref file path is > 128 chars. PESQ will
- # compute an incorrect score then (!), and the relative path to the ref file
- # should be a lot shorter than the absolute one.
- audio_file_ref = os.path.relpath(audio_file_ref)
- cmd = [_PESQ_PATH, '+%d' % sample_rate, audio_file_ref, audio_file_test]
- logging.debug('Running command: %s', ' '.join(cmd))
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- output, error = p.communicate()
- if p.returncode != 0:
- logging.error('Error running pesq: %s\n%s', output, error)
- # Last line of PESQ output shows the results. Example:
- # P.862 Prediction (Raw MOS, MOS-LQO): = 4.180 4.319
- result = re.search('Prediction.*= (\d{1}\.\d{3})\t(\d{1}\.\d{3})',
- output)
- if not result or len(result.groups()) != 2:
- return None
- return (float(result.group(1)), float(result.group(2)))
-
-
-def RemoveSilence(input_audio_file, output_audio_file):
- """Removes silence from beginning and end of the input_audio_file.
-
- Args:
- input_audio_file: The audio file to remove silence from.
- output_audio_file: The audio file to save the output audio.
- """
- # SOX documentation for silence command: http://sox.sourceforge.net/sox.html
- # To remove the silence from both beginning and end of the audio file, we call
- # sox silence command twice: once on normal file and again on its reverse,
- # then we reverse the final output.
- # Silence parameters are (in sequence):
- # ABOVE_PERIODS: The period for which silence occurs. Value 1 is used for
- # silence at beginning of audio.
- # DURATION: the amount of time in seconds that non-silence must be detected
- # before sox stops trimming audio.
- # THRESHOLD: value used to indicate what sample value is treates as silence.
- ABOVE_PERIODS = '1'
- DURATION = '2'
- THRESHOLD = '5%'
-
- cmd = [_SOX_PATH, input_audio_file, output_audio_file, 'silence',
- ABOVE_PERIODS, DURATION, THRESHOLD, 'reverse', 'silence',
- ABOVE_PERIODS, DURATION, THRESHOLD, 'reverse']
- logging.debug('Running command: %s', ' '.join(cmd))
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- output, error = p.communicate()
- if p.returncode != 0:
- logging.error('Error removing silence from audio: %s\n%s', output, error)
-
-
-def ForceMicrophoneVolumeTo100Percent():
- if WINDOWS:
- # The volume max util is implemented in WebRTC in
- # webrtc/tools/force_mic_volume_max/force_mic_volume_max.cc.
- if not os.path.exists(_FORCE_MIC_VOLUME_MAX_UTIL):
- raise Exception('Missing required binary %s.' %
- _FORCE_MIC_VOLUME_MAX_UTIL)
- cmd = [_FORCE_MIC_VOLUME_MAX_UTIL]
- else:
- # The recording device id is machine-specific. We assume here it is called
- # Monitor of render (which corresponds to the id render.monitor). You can
- # list the available recording devices with pacmd list-sources.
- RECORDING_DEVICE_ID = 'render.monitor'
- HUNDRED_PERCENT_VOLUME = '65536'
- cmd = [_PACMD_PATH, 'set-source-volume', RECORDING_DEVICE_ID,
- HUNDRED_PERCENT_VOLUME]
-
- logging.debug('Running command: %s', ' '.join(cmd))
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- output, error = p.communicate()
- if p.returncode != 0:
- logging.error('Error forcing mic volume to 100%%: %s\n%s', output, error)
diff --git a/chrome/test/functional/media/cns_test_base.py b/chrome/test/functional/media/cns_test_base.py
deleted file mode 100644
index 04271d5..0000000
--- a/chrome/test/functional/media/cns_test_base.py
+++ /dev/null
@@ -1,201 +0,0 @@
-# Copyright (c) 2012 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.
-
-"""Constrained network server (CNS) test base."""
-
-import logging
-import os
-import Queue
-import subprocess
-import sys
-import threading
-import urllib2
-
-import pyauto
-import pyauto_paths
-
-
-# List of commonly used network constraints settings.
-# Each setting is a tuppe of the form:
-# ('TEST_NAME', [BANDWIDTH_Kbps, LATENCY_ms, PACKET_LOSS_%])
-#
-# Note: The test name should satisfy the regex [\w\.-]+ (check
-# tools/perf_expectations/tests/perf_expectations_unittest.py for details). It
-# is used to name the result graphs on the dashboards.
-#
-# The WiFi, DSL, and Cable settings were taken from webpagetest.org as
-# approximations of their respective real world networks. The settings were
-# based on 2011 FCC Broadband Data report (http://www.fcc.gov/document/
-# measuring-broadband-america-report-consumer-broadband-performance-us).
-DialUp = ('DialUp', [56, 120, 5])
-Slow = ('Slow', [256, 105, 1])
-Wifi = ('Wifi', [1024, 60, 0])
-DSL = ('DSL', [1541, 50, 0])
-Cable = ('Cable', [5120, 28, 0])
-NoConstraints = ('NoConstraints', [0, 0, 0])
-
-# Path to CNS executable relative to source root.
-_CNS_PATH = os.path.join(
- 'media', 'tools', 'constrained_network_server', 'cns.py')
-
-# Port to start the CNS on.
-_CNS_PORT = 9000
-
-# A flag to determine whether to launch a local CNS instance or to connect
-# to the external CNS server. Default to False since all current bots use an
-# external instance.
-# If not on Windows, set USE_LOCAL_CNS=1 env variable to switch the flag.
-USE_LOCAL_CNS = ('win' not in sys.platform and 'USE_LOCAL_CNS' in os.environ and
- os.environ['USE_LOCAL_CNS'] == '1')
-
-# Base CNS URL, only requires & separated parameter names appended.
-if USE_LOCAL_CNS:
- CNS_BASE_URL = 'http://127.0.0.1:%d/ServeConstrained?' % _CNS_PORT
-else:
- CNS_BASE_URL = 'http://chromeperf34:%d/ServeConstrained?' % _CNS_PORT
- CNS_CLEANUP_URL = 'http://chromeperf34:%d/Cleanup' % _CNS_PORT
-
-# Used for server sanity check.
-_TEST_VIDEO = 'roller.webm'
-
-# Directory root to serve files from.
-_ROOT_PATH = os.path.join(pyauto.PyUITest.DataDir(), 'pyauto_private', 'media')
-
-
-class CNSTestBase(pyauto.PyUITest):
- """CNS test base hadles startup and teardown of CNS server."""
-
- def __init__(self, *args, **kwargs):
- """Initialize CNSTestBase by setting the arguments for CNS server.
-
- Args:
- Check cns.py command line argument list for details.
- """
- self._port = kwargs.get('port', _CNS_PORT)
- self._interface = kwargs.get('interface', 'lo')
- self._www_root = kwargs.get('www_root', _ROOT_PATH)
- self._verbose = kwargs.get('verbose', True)
- self._expiry_time = kwargs.get('expiry_time', 0)
- self._socket_timeout = kwargs.get('socket_timeout')
- pyauto.PyUITest.__init__(self, *args, **kwargs)
-
- def setUp(self):
- """Ensures the Constrained Network Server (CNS) server is up and running."""
- if USE_LOCAL_CNS:
- self._SetUpLocal()
- else:
- self._SetUpExternal()
-
- def _SetUpExternal(self):
- """Ensures the test can connect to the external CNS server."""
- if self.WaitUntil(self._CanAccessServer, retry_sleep=3, timeout=30,
- debug=False):
- pyauto.PyUITest.setUp(self)
- else:
- self.fail('Failed to connect to CNS.')
-
- def _SetUpLocal(self):
- """Starts the CNS server locally."""
- cmd = [sys.executable, os.path.join(pyauto_paths.GetSourceDir(), _CNS_PATH),
- '--port', str(self._port),
- '--interface', self._interface,
- '--www-root', self._www_root,
- '--expiry-time', str(self._expiry_time)]
-
- if self._socket_timeout:
- cmd.extend(['--socket-timeout', str(self._socket_timeout)])
- if self._verbose:
- cmd.append('-v')
- logging.debug('Starting CNS server: %s ', ' '.join(cmd))
-
- self._cns_process = subprocess.Popen(cmd, stderr=subprocess.PIPE)
- ProcessLogger(self._cns_process)
-
- if self.WaitUntil(self._CanAccessServer, retry_sleep=3, timeout=30,
- debug=False):
- pyauto.PyUITest.setUp(self)
- else:
- self.tearDown()
- self.fail('Failed to start CNS.')
-
- def _CanAccessServer(self):
- """Checks if the CNS server can serve a file with no network constraints."""
- test_url = ''.join([CNS_BASE_URL, 'f=', _TEST_VIDEO])
- try:
- return urllib2.urlopen(test_url) is not None
- except Exception:
- return False
-
- def tearDown(self):
- """Stops the Constrained Network Server (CNS)."""
- if USE_LOCAL_CNS:
- logging.debug('Stopping CNS server.')
- # Do not use process.kill(), it will not clean up cns.
- self.Kill(self._cns_process.pid)
- # Need to wait since the process logger has a lock on the process stderr.
- self._cns_process.wait()
- self.assertFalse(self._cns_process.returncode is None)
- logging.debug('CNS server stopped.')
- else:
- # Call CNS Cleanup to remove all ports created by this client.
- self.NavigateToURL(CNS_CLEANUP_URL)
- pyauto.PyUITest.tearDown(self)
-
-
-class ProcessLogger(threading.Thread):
- """A thread to log a process's stderr output."""
-
- def __init__(self, process):
- """Starts the process logger thread.
-
- Args:
- process: The process to log.
- """
- threading.Thread.__init__(self)
- self._process = process
- self.start()
-
- def run(self):
- """Adds debug statements for the process's stderr output."""
- line = True
- while line:
- line = self._process.stderr.readline()
- logging.debug(line.strip())
-
-
-def GetFileURL(file_name, bandwidth=0, latency=0, loss=0, new_port=False):
- """Returns CNS URL for the file with specified constraints.
-
- Args:
- Check cns.ServeConstrained() args for more details.
- """
- video_url = [CNS_BASE_URL, 'f=' + file_name]
- if bandwidth > 0:
- video_url.append('bandwidth=%d' % bandwidth)
- if latency > 0:
- video_url.append('latency=%d' % latency)
- if loss > 0:
- video_url.append('loss=%d' % loss)
- if new_port:
- video_url.append('new_port=%s' % new_port)
- return '&'.join(video_url)
-
-
-def CreateCNSPerfTasks(network_constraints_settings, test_media_files):
- """Returns a queue of tasks combinining network constrains with media files.
-
- Args:
- network_constraints_settings: List of (setting_name, setting_values)
- tupples.
- test_media_files: List of media files to run the tests on.
- """
- # Convert relative test path into an absolute path.
- tasks = Queue.Queue()
- for file_name in test_media_files:
- for series_name, settings in network_constraints_settings:
- logging.debug('Add test: %s\tSettings: %s\tMedia: %s', series_name,
- settings, file_name)
- tasks.put((series_name, settings, file_name))
-
- return tasks
diff --git a/chrome/test/functional/media/media_basic_playback.py b/chrome/test/functional/media/media_basic_playback.py
deleted file mode 100755
index e70b262..0000000
--- a/chrome/test/functional/media/media_basic_playback.py
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Basic playback test. Checks playback, seek, and replay based on events.
-
-This test uses the bear videos from the test matrix in h264, vp8, and theora
-formats.
-"""
-import logging
-import os
-
-import pyauto_media
-import pyauto
-
-
-# HTML test path; relative to src/chrome/test/data.
-_TEST_HTML_PATH = os.path.join('media', 'html', 'media_basic_playback.html')
-
-# Test videos to play. TODO(dalecurtis): Convert to text matrix parser when we
-# have more test videos in the matrix. Code already written, see patch here:
-# https://chromiumcodereview.appspot.com/9290008/#ps12
-_TEST_VIDEOS = [
- pyauto.PyUITest.GetFileURLForContentDataPath('media', name)
- for name in ['bear.mp4', 'bear.ogv', 'bear.webm', 'bear_silent.mp4',
- 'bear_silent.ogv', 'bear_silent.webm']]
-
-# Expected events for the first iteration and every iteration thereafter.
-_EXPECTED_EVENTS_0 = [('ended', 2), ('playing', 2), ('seeked', 1),
- ('suspend', 1)]
-_EXPECTED_EVENTS_n = [('abort', 1), ('emptied', 1)] + _EXPECTED_EVENTS_0
-
-
-class MediaBasicPlaybackTest(pyauto.PyUITest):
- """PyAuto test container. See file doc string for more information."""
-
- def testBasicPlaybackMatrix(self):
- """Launches HTML test which plays each video until end, seeks, and replays.
-
- Specifically ensures that after the above sequence of events, the following
- are true:
-
- 1. The first video has only 2x playing, 2x ended, and 1x seeked events.
- 2. Each subsequent video additionally has 1x abort and 1x emptied due to
- switching of the src attribute.
- 3. video.currentTime == video.duration for each video.
-
- See the HTML file at _TEST_HTML_PATH for more information.
- """
- self.NavigateToURL(self.GetFileURLForDataPath(_TEST_HTML_PATH))
-
- for i, media in enumerate(_TEST_VIDEOS):
- logging.debug('Running basic playback test for %s', media)
-
- # Block until the test finishes and notifies us. Upon return the value of
- # video.currentTime == video.duration is provided.
- try:
- self.assertTrue(self.ExecuteJavascript("startTest('%s');" % media))
-
- # PyAuto has trouble with arrays, so convert to string prior to request.
- events = self.GetDOMValue("events.join(',')").split(',')
- counts = [(item, events.count(item)) for item in sorted(set(events))]
-
- # The first loop will not have the abort and emptied events triggered by
- # changing the video src.
- if (i == 0):
- self.assertEqual(counts, _EXPECTED_EVENTS_0)
- else:
- self.assertEqual(counts, _EXPECTED_EVENTS_n)
- except:
- logging.debug(
- 'Test failed with events: %s', self.GetDOMValue("events.join(',')"))
- raise
-
-
-if __name__ == '__main__':
- pyauto_media.Main()
diff --git a/chrome/test/functional/media/media_constrained_network_perf.py b/chrome/test/functional/media/media_constrained_network_perf.py
deleted file mode 100755
index d06b82d..0000000
--- a/chrome/test/functional/media/media_constrained_network_perf.py
+++ /dev/null
@@ -1,210 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Records metrics on playing media under constrained network conditions.
-
-Spins up a Constrained Network Server (CNS) and runs through a test matrix of
-bandwidth, latency, and packet loss settings. Tests running media files defined
-in _TEST_MEDIA_EPP record the extra-play-percentage (EPP) metric and the
-time-to-playback (TTP) metric in a format consumable by the Chromium perf bots.
-Other tests running media files defined in _TEST_MEDIA_NO_EPP record only the
-TTP metric.
-
-Since even a small number of different settings yields a large test matrix, the
-design is threaded... however PyAuto is not, so a global lock is used when calls
-into PyAuto are necessary. The number of threads can be set by _TEST_THREADS.
-
-The CNS code is located under: <root>/src/media/tools/constrained_network_server
-"""
-
-import logging
-import os
-import posixpath
-import Queue
-
-import pyauto_media
-import pyauto_utils
-
-import cns_test_base
-import worker_thread
-
-# The network constraints used for measuring ttp and epp.
-# Previous tests with 2% and 5% packet loss resulted in inconsistent data. Thus
-# packet loss is not used often in perf tests. Tests with very low bandwidth,
-# such as 56K Dial-up resulted in very slow tests (about 8 mins to run each
-# test iteration). In addition, metrics for Dial-up would be out of range of the
-# other tests metrics, making the graphs hard to read.
-_TESTS_TO_RUN = [cns_test_base.Cable,
- cns_test_base.Wifi,
- cns_test_base.DSL,
- cns_test_base.Slow,
- cns_test_base.NoConstraints]
-
-# HTML test path; relative to src/chrome/test/data. Loads a test video and
-# records metrics in JavaScript.
-_TEST_HTML_PATH = os.path.join(
- 'media', 'html', 'media_constrained_network.html')
-
-# Number of threads to use during testing.
-_TEST_THREADS = 3
-
-# Number of times we run the same test to eliminate outliers.
-_TEST_ITERATIONS = 3
-
-# Media file names used for measuring epp and tpp.
-_TEST_MEDIA_EPP = ['roller.webm']
-_TEST_MEDIA_EPP.extend(posixpath.join('crowd', name) for name in
- ['crowd360.ogv', 'crowd.wav', 'crowd.ogg'])
-
-# Media file names used for measuring tpp without epp.
-_TEST_MEDIA_NO_EPP = [posixpath.join('dartmoor', name) for name in
- ['dartmoor2.ogg', 'dartmoor2.m4a', 'dartmoor2.mp3',
- 'dartmoor2.wav']]
-_TEST_MEDIA_NO_EPP.extend(posixpath.join('crowd', name) for name in
- ['crowd1080.webm', 'crowd1080.ogv', 'crowd1080.mp4',
- 'crowd360.webm', 'crowd360.mp4'])
-
-# Timeout values for epp and ttp tests in seconds.
-_TEST_EPP_TIMEOUT = 180
-_TEST_TTP_TIMEOUT = 20
-
-
-class CNSWorkerThread(worker_thread.WorkerThread):
- """Worker thread. Runs a test for each task in the queue."""
-
- def __init__(self, *args, **kwargs):
- """Sets up CNSWorkerThread class variables."""
- # Allocate local vars before WorkerThread.__init__ runs the thread.
- self._metrics = {}
- self._test_iterations = _TEST_ITERATIONS
- worker_thread.WorkerThread.__init__(self, *args, **kwargs)
-
- def _HaveMetricOrError(self, var_name, unique_url):
- """Checks if the page has variable value ready or if an error has occured.
-
- The varaible value must be set to < 0 pre-run.
-
- Args:
- var_name: The variable name to check the metric for.
- unique_url: The url of the page to check for the variable's metric.
-
- Returns:
- True is the var_name value is >=0 or if an error_msg exists.
- """
- self._metrics[var_name] = int(self.GetDOMValue(var_name, url=unique_url))
- end_test = self.GetDOMValue('endTest', url=unique_url)
-
- return self._metrics[var_name] >= 0 or end_test
-
- def _GetEventsLog(self, unique_url):
- """Returns the log of video events fired while running the test.
-
- Args:
- unique_url: The url of the page identifying the test.
- """
- return self.GetDOMValue('eventsMsg', url=unique_url)
-
- def _GetVideoProgress(self, unique_url):
- """Gets the video's current play progress percentage.
-
- Args:
- unique_url: The url of the page to check for video play progress.
- """
- return int(self.CallJavascriptFunc('calculateProgress', url=unique_url))
-
- def RunTask(self, unique_url, task):
- """Runs the specific task on the url given.
-
- It is assumed that a tab with the unique_url is already loaded.
- Args:
- unique_url: A unique identifier of the test page.
- task: A (series_name, settings, file_name, run_epp) tuple.
- Returns:
- True if at least one iteration of the tests run as expected.
- """
- ttp_results = []
- epp_results = []
- # Build video source URL. Values <= 0 mean the setting is disabled.
- series_name, settings, (file_name, run_epp) = task
- video_url = cns_test_base.GetFileURL(
- file_name, bandwidth=settings[0], latency=settings[1],
- loss=settings[2], new_port=True)
-
- graph_name = series_name + '_' + os.path.basename(file_name)
- for iter_num in xrange(self._test_iterations):
- # Start the test!
- self.CallJavascriptFunc('startTest', [video_url], url=unique_url)
-
- # Wait until the necessary metrics have been collected.
- self._metrics['epp'] = self._metrics['ttp'] = -1
- self.WaitUntil(self._HaveMetricOrError, args=['ttp', unique_url],
- retry_sleep=1, timeout=_TEST_EPP_TIMEOUT, debug=False)
- # Do not wait for epp if ttp is not available.
- if self._metrics['ttp'] >= 0:
- ttp_results.append(self._metrics['ttp'])
- if run_epp:
- self.WaitUntil(
- self._HaveMetricOrError, args=['epp', unique_url], retry_sleep=2,
- timeout=_TEST_EPP_TIMEOUT, debug=False)
-
- if self._metrics['epp'] >= 0:
- epp_results.append(self._metrics['epp'])
-
- logging.debug('Iteration:%d - Test %s ended with %d%% of the video '
- 'played.', iter_num, graph_name,
- self._GetVideoProgress(unique_url),)
-
- if self._metrics['ttp'] < 0 or (run_epp and self._metrics['epp'] < 0):
- logging.error('Iteration:%d - Test %s failed to end gracefully due '
- 'to time-out or error.\nVideo events fired:\n%s',
- iter_num, graph_name, self._GetEventsLog(unique_url))
-
- # End of iterations, print results,
- pyauto_utils.PrintPerfResult('ttp', graph_name, ttp_results, 'ms')
-
- # Return true if we got at least one result to report.
- if run_epp:
- pyauto_utils.PrintPerfResult('epp', graph_name, epp_results, '%')
- return len(epp_results) != 0
- return len(ttp_results) != 0
-
-
-class MediaConstrainedNetworkPerfTest(cns_test_base.CNSTestBase):
- """PyAuto test container. See file doc string for more information."""
-
- def _RunDummyTest(self, test_path):
- """Runs a dummy test with high bandwidth and no latency or packet loss.
-
- Fails the unit test if the dummy test does not end.
-
- Args:
- test_path: Path to HTML/JavaScript test code.
- """
- tasks = Queue.Queue()
- tasks.put(('Dummy Test', [5000, 0, 0], (_TEST_MEDIA_EPP[0], True)))
- # Dummy test should successfully finish by passing all the tests.
- if worker_thread.RunWorkerThreads(self, CNSWorkerThread, tasks, 1,
- test_path):
- self.fail('Failed to run dummy test.')
-
- def testConstrainedNetworkPerf(self):
-
- """Starts CNS, spins up worker threads to run through _TEST_CONSTRAINTS."""
- # Run a dummy test to avoid Chrome/CNS startup overhead.
- logging.debug('Starting a dummy test to avoid Chrome/CNS startup overhead.')
- self._RunDummyTest(_TEST_HTML_PATH)
- logging.debug('Dummy test has finished. Starting real perf tests.')
-
- # Tests that wait for EPP metrics.
- media_files = [(name, True) for name in _TEST_MEDIA_EPP]
- media_files.extend((name, False) for name in _TEST_MEDIA_NO_EPP)
- tasks = cns_test_base.CreateCNSPerfTasks(_TESTS_TO_RUN, media_files)
- if worker_thread.RunWorkerThreads(self, CNSWorkerThread, tasks,
- _TEST_THREADS, _TEST_HTML_PATH):
- self.fail('Some tests failed to run as expected.')
-
-
-if __name__ == '__main__':
- pyauto_media.Main()
diff --git a/chrome/test/functional/media/media_jerky.py b/chrome/test/functional/media/media_jerky.py
deleted file mode 100755
index 6d1424b..0000000
--- a/chrome/test/functional/media/media_jerky.py
+++ /dev/null
@@ -1,224 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Jerkiness performance test for video playback.
-
-Uses jerky tool, (http://go/jerky), to record a jerkiness metric for videos
-sensitive to jerkiness.
-
-Jerkiness is defined as a percentage of the average on screen frame time by the
-formula below. Where smoothed_frame_time[i] represents a frame's on screen time
-plus amortized measurement gap error (time taken to capture each frame).
-
-sqrt(average((avg_frame_time - smoothed_frame_time[i])^2, i=m..n))
-------------------------------------------------------------------
- avg_frame_time
-
-Currently, only the Linux binaries are checked in for this test since we only
-have a Linux performance bot. The current binary is a custom build with some
-fixes from veganjerky (http://go/veganjerky) for timing, waiting, and stdout
-flushing.
-
-TODO(dalecurtis): Move Jerky tool sources into the Chromium tree.
-
-TODO(dalecurtis): Jerky tool uses a questionable method for determining torn
-frames, determine if it is actually worth recording.
-"""
-
-import glob
-import logging
-import os
-import re
-import subprocess
-import tempfile
-
-import pyauto_media
-import pyauto
-import pyauto_utils
-
-# HTML test path; relative to src/chrome/test/data.
-_TEST_HTML_PATH = os.path.join('media', 'html', 'media_jerky.html')
-
-# Path under data path for test files.
-_TEST_MEDIA_PATH = os.path.join('pyauto_private', 'media', 'birds')
-
-# Path to Jerky tool executable.
-_JERKY_PATH = os.path.join('pyauto_private', 'media', 'tools', 'jerky')
-
-# Regular expression for extracting jerkiness percentage. Sample line:
-# using 1:9 title 'test.log (35.36% jerky, 0 teared frames)' lw 2 with lines
-_JERKY_LOG_REGEX = re.compile(
- r'\((\d{0,3}\.?\d{0,2})% jerky, (\d+) teared frames\)')
-
-# Regular expression for extracting computed fps. Sample line:
-# INFO: 33797 us per frame => 29.6 fps.
-_JERKY_LOG_FPS_REGEX = re.compile(r' => (\d+\.\d+) fps')
-
-# Minimum and maximum number of iterations for each test. Due to timing issues
-# the jerky tool may not always calculate the fps correctly. When invalid
-# results are detected, the test is rerun up to the maxium # of times set below.
-_JERKY_ITERATIONS_MIN = 3
-_JERKY_ITERATIONS_MAX = 10
-
-# The media files used for testing. Each entry represents a tuple of (filename,
-# width, height, fps). The width and height are used to create a calibration
-# pattern for jerky tool. The fps is used to ensure Jerky tool computed a valid
-# result.
-_TEST_VIDEOS = [('birds540.webm', 960, 540, 29.9)]
-
-
-def GetTempFilename():
- """Returns an absolute path to an empty temp file."""
- f, path = tempfile.mkstemp(prefix='jerky_tmp')
- os.close(f)
- return path
-
-
-class MediaJerkyPerfTest(pyauto.PyUITest):
- """PyAuto test container. See file doc string for more information."""
-
- def StartJerkyCapture(self):
- """Starts jerky tool in capture mode and waits until its ready to capture.
-
- Returns:
- A tuple of the jerky process and an absolute path to the capture log.
- """
- jerky_log = GetTempFilename()
- logging.debug('Logging data to %s', jerky_log)
- process = subprocess.Popen(
- [os.path.join(self.DataDir(), _JERKY_PATH),
- 'capture', '--log', jerky_log],
- stdout=subprocess.PIPE)
-
- # Set the jerky tool process to soft-realtime w/ round-robin scheduling.
- subprocess.check_call(['sudo', 'chrt', '-r', '-p', str(process.pid)])
-
- # Wait for server to start up.
- line = True
- while line:
- line = process.stdout.readline()
- if 'Waiting for calibration pattern to disappear' in line:
- return process, jerky_log
- self.fail('Failed to launch Jerky tool.')
-
- def AnalyzeJerkyCapture(self, jerky_log):
- """Run jerky analyze on the specified log and return various metrics.
-
- Once analyze has completed, the jerky_log and associated outputs will be
- removed.
-
- Args:
- jerky_log: Absolute path to the capture log.
-
- Returns:
- Tuple of fps, jerkiness, and torn frames.
- """
- results_log_base = GetTempFilename()
- process = subprocess.Popen(
- [os.path.join(self.DataDir(), _JERKY_PATH),
- 'analyze', '--ref', jerky_log, '--out', results_log_base],
- stdout=subprocess.PIPE)
-
- # Wait for process to end w/o risking deadlock.
- stdout = process.communicate()[0]
- self.assertEquals(process.returncode, 0)
-
- # Scrape out the calculated FPS.
- fps_match = None
- for line in stdout.splitlines():
- fps_match = _JERKY_LOG_FPS_REGEX.search(line)
- if fps_match:
- break
-
- # Open *.error.gnuplot and scrape out jerkiness.
- jerky_match = None
- with open('%s.error.gnuplot' % results_log_base) as results:
- for line in results:
- jerky_match = _JERKY_LOG_REGEX.search(line)
- if jerky_match:
- break
-
- # Cleanup all the temp and results files jerky spits out.
- for log in glob.glob('%s*' % results_log_base) + [jerky_log]:
- os.unlink(log)
-
- if fps_match and jerky_match:
- return (float(fps_match.group(1)), float(jerky_match.group(1)),
- int(jerky_match.group(2)))
- return None, None, None
-
- def testMediaJerkyPerformance(self):
- """Launches Jerky tool and records jerkiness for HTML5 videos.
-
- For each video, the test starts up jerky tool then plays until the Jerky
- tool collects enough information. Next the capture log is analyzed using
- Jerky's analyze command. If the computed fps matches the expected fps the
- jerkiness metric is recorded.
-
- The test will run up to _JERKY_ITERATIONS_MAX times in an attempt to get at
- least _JERKY_ITERATIONS_MIN valid values. The results are recorded under
- the 'jerkiness' variable for graphing on the bots.
- """
- self.NavigateToURL(self.GetFileURLForDataPath(_TEST_HTML_PATH))
-
- # Xvfb on the bots is restricted to 1024x768 at present. Ensure we're using
- # all of the real estate we can. Jerky tool needs a clear picture of every
- # frame, so we can't clip the video in any way.
- self.SetWindowDimensions(0, 0, 1024, 768)
-
- for name, width, height, expected_fps in _TEST_VIDEOS:
- jerkiness = []
- torn_frames = []
- file_url = self.GetFileURLForDataPath(
- os.path.join(_TEST_MEDIA_PATH, name))
-
- # Initialize the calibration area for Jerky tool.
- self.assertTrue(self.ExecuteJavascript(
- 'initializeTest(%d, %d);' % (width, height)))
-
- runs_left = _JERKY_ITERATIONS_MIN
- runs_total = 0
- while runs_left > 0 and runs_total < _JERKY_ITERATIONS_MAX:
- runs_total += 1
- logging.info('Running Jerky perf test #%d for %s.', runs_total, name)
-
- # Startup Jerky tool in capture mode.
- jerky_process, jerky_log = self.StartJerkyCapture()
-
- # Start playback of the test video.
- self.assertTrue(self.ExecuteJavascript("startTest('%s');" % file_url))
-
- # Wait for jerky tool to finish if it hasn't already.
- self.assertTrue(jerky_process.wait() == 0)
-
- # Stop playback of the test video so the next run can cleanly find the
- # calibration zone.
- self.assertTrue(self.ExecuteJavascript('stopTest();'))
-
- # Analyze the results.
- jerky_fps, jerky_percent, jerky_torn_frames = self.AnalyzeJerkyCapture(
- jerky_log)
- if (jerky_fps is None or jerky_percent is None or
- jerky_torn_frames is None):
- logging.error('No metrics recorded for this run.')
- continue
-
- # Ensure the results for this run are valid.
- if jerky_fps != expected_fps:
- logging.error(
- 'Invalid fps detected (actual: %f, expected: %f, jerkiness: %f). '
- 'Discarding results for this run.', jerky_fps, expected_fps,
- jerky_percent)
- continue
-
- jerkiness.append(jerky_percent)
- torn_frames.append(jerky_torn_frames)
- runs_left -= 1
-
- pyauto_utils.PrintPerfResult('jerkiness', name, jerkiness, '%')
-
-
-if __name__ == '__main__':
- pyauto_media.Main()
diff --git a/chrome/test/functional/media/media_scrub_perf.py b/chrome/test/functional/media/media_scrub_perf.py
deleted file mode 100755
index e8d605a..0000000
--- a/chrome/test/functional/media/media_scrub_perf.py
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Scrubbing performance test for <video>.
-
-Measures the times to scrub video and audio files. Scrubbing is simulated by
-having consecutive small seeks performed. The test measures both forward and
-backward scrubbing.
-"""
-
-import os
-
-import pyauto_media
-import pyauto_utils
-import pyauto
-
-# HTML test path; relative to src/chrome/test/data.
-_TEST_HTML_PATH = os.path.join('media', 'html', 'media_scrub.html')
-
-# Path under data path for test files.
-_TEST_MEDIA_PATH = os.path.join('media', 'avperf')
-
-# The media files used for testing.
-_TEST_MEDIA = [os.path.join('tulip', name) for name in
- ['tulip2.webm', 'tulip2.wav', 'tulip2.ogv', 'tulip2.ogg',
- 'tulip2.mp4', 'tulip2.mp3', 'tulip2.m4a']]
-
-
-class MediaScrubPerfTest(pyauto.PyUITest):
- """PyAuto test container. See file doc string for more information."""
-
- def testMediaScrubPerformance(self):
- """Launches HTML test which runs the scrub test and records performance."""
- self.NavigateToURL(self.GetFileURLForDataPath(_TEST_HTML_PATH))
-
- for media in _TEST_MEDIA:
- file_name = self.GetFileURLForDataPath(
- os.path.join(_TEST_MEDIA_PATH, media))
-
- # Some tests take more than the default PyAuto calls timeout, so we start
- # each test and wait until 'testDone' flag is set by the test.
- self.CallJavascriptFunc('startTest', [file_name])
-
- if not self.WaitUntil(self.GetDOMValue, args=['testDone'],
- retry_sleep=5, timeout=180, debug=False):
- error_msg = 'Scrubbing tests timed out.'
- else:
- error_msg = self.GetDOMValue('errorMsg')
- if error_msg:
- self.fail('Error while running the test: %s' % error_msg)
-
- forward_scrub_time = float(self.GetDOMValue('forwardScrubTime'))
- backward_scrub_time = float(self.GetDOMValue('backwardScrubTime'))
- mixed_scrub_time = float(self.GetDOMValue('mixedScrubTime'))
- pyauto_utils.PrintPerfResult('scrubbing', os.path.basename(file_name) +
- '_forward', forward_scrub_time, 'ms')
- pyauto_utils.PrintPerfResult('scrubbing', os.path.basename(file_name) +
- '_backward', backward_scrub_time, 'ms')
- pyauto_utils.PrintPerfResult('scrubbing', os.path.basename(file_name) +
- '_mixed', mixed_scrub_time, 'ms')
-
-
-if __name__ == '__main__':
- pyauto_media.Main()
diff --git a/chrome/test/functional/media/media_seek_perf.py b/chrome/test/functional/media/media_seek_perf.py
deleted file mode 100755
index b0e86b5..0000000
--- a/chrome/test/functional/media/media_seek_perf.py
+++ /dev/null
@@ -1,117 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Seek performance testing for <video>.
-
-Calculates the short and long seek times for different video formats on
-different network constraints.
-"""
-
-import logging
-import os
-import posixpath
-
-import pyauto_media
-import pyauto_utils
-
-import cns_test_base
-import worker_thread
-
-# Number of threads to use during testing.
-_TEST_THREADS = 3
-
-# HTML test path; relative to src/chrome/test/data.
-_TEST_HTML_PATH = os.path.join('media', 'html', 'media_seek.html')
-
-# The media files used for testing.
-# Path under CNS root folder (pyauto_private/media).
-_TEST_VIDEOS = [posixpath.join('dartmoor', name) for name in
- ['dartmoor2.mp3', 'dartmoor2.wav']]
-
-_TEST_VIDEOS.extend([posixpath.join('crowd', name) for name in
- ['crowd1080.webm', 'crowd1080.ogv', 'crowd1080.mp4',
- 'crowd360.webm', 'crowd360.ogv', 'crowd360.mp4']])
-
-# Constraints to run tests on.
-_TESTS_TO_RUN = [
- cns_test_base.Wifi,
- cns_test_base.NoConstraints]
-
-
-class SeekWorkerThread(worker_thread.WorkerThread):
- """Worker thread. Runs a test for each task in the queue."""
-
- def RunTask(self, unique_url, task):
- """Runs the specific task on the url given.
-
- It is assumed that a tab with the unique_url is already loaded.
- Args:
- unique_url: A unique identifier of the test page.
- task: A (series_name, settings, file_name) tuple to run the test on.
- """
- series_name, settings, file_name = task
-
- video_url = cns_test_base.GetFileURL(
- file_name, bandwidth=settings[0], latency=settings[1],
- loss=settings[2])
-
- # Start the test!
- self.CallJavascriptFunc('startTest', [video_url], unique_url)
-
- logging.debug('Running perf test for %s.', video_url)
- # Time out is dependent on (seeking time * iterations). For 3 iterations
- # per seek we get total of 18 seeks per test. We expect buffered and
- # cached seeks to be fast. Through experimentation an average of 10 secs
- # per seek was found to be adequate.
- if not self.WaitUntil(self.GetDOMValue, args=['endTest', unique_url],
- retry_sleep=5, timeout=300, debug=False):
- error_msg = 'Seek tests timed out.'
- else:
- error_msg = self.GetDOMValue('errorMsg', unique_url)
-
- cached_states = self.GetDOMValue(
- "Object.keys(CachedState).join(',')", unique_url).split(',')
- seek_test_cases = self.GetDOMValue(
- "Object.keys(SeekTestCase).join(',')", unique_url).split(',')
-
- graph_name = series_name + '_' + os.path.basename(file_name)
- for state in cached_states:
- for seek_case in seek_test_cases:
- values = self.GetDOMValue(
- "seekRecords[CachedState.%s][SeekTestCase.%s].join(',')" %
- (state, seek_case), unique_url)
- if values:
- results = [float(value) for value in values.split(',')]
- else:
- results = []
- pyauto_utils.PrintPerfResult('seek_%s_%s' % (state.lower(),
- seek_case.lower()), graph_name,
- results, 'ms')
-
- if error_msg:
- logging.error('Error while running %s: %s.', graph_name, error_msg)
- return False
- else:
- return True
-
-
-class MediaSeekPerfTest(cns_test_base.CNSTestBase):
- """PyAuto test container. See file doc string for more information."""
-
- def __init__(self, *args, **kwargs):
- """Initialize the CNSTestBase with socket_timeout = 60 secs."""
- cns_test_base.CNSTestBase.__init__(self, socket_timeout='60',
- *args, **kwargs)
-
- def testMediaSeekPerformance(self):
- """Launches HTML test which plays each video and records seek stats."""
- tasks = cns_test_base.CreateCNSPerfTasks(_TESTS_TO_RUN, _TEST_VIDEOS)
- if worker_thread.RunWorkerThreads(self, SeekWorkerThread, tasks,
- _TEST_THREADS, _TEST_HTML_PATH):
- self.fail('Some tests failed to run as expected.')
-
-
-if __name__ == '__main__':
- pyauto_media.Main()
diff --git a/chrome/test/functional/media/media_stat_perf.py b/chrome/test/functional/media/media_stat_perf.py
deleted file mode 100755
index f212848..0000000
--- a/chrome/test/functional/media/media_stat_perf.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""CPU, Memory, and FPS performance test for <video>.
-
-Calculates decoded fps, dropped fps, CPU, and memory statistics while playing
-HTML5 media element. The test compares results of playing a media file on
-different video resolutions.
-"""
-
-import logging
-import os
-import psutil
-
-import pyauto_media
-import pyauto
-import pyauto_utils
-
-# HTML test path; relative to src/chrome/test/data.
-_TEST_HTML_PATH = os.path.join('media', 'html', 'media_stat_perf.html')
-
-# Path under data path for test files.
-_TEST_MEDIA_PATH_CROWD = os.path.join('pyauto_private', 'media', 'crowd')
-
-# Path under data path for test files.
-_TEST_MEDIA_PATH_TULIP = os.path.join('media', 'avperf', 'tulip')
-# The media files used for testing.
-_TEST_VIDEOS = [os.path.join(_TEST_MEDIA_PATH_CROWD, name) for name in [
- 'crowd2160.webm', 'crowd1080.webm']]
-_TEST_VIDEOS.extend([os.path.join(_TEST_MEDIA_PATH_TULIP, name) for name in [
- 'tulip2.webm', 'tulip2.wav', 'tulip2.ogv', 'tulip2.ogg', 'tulip2.mp4',
- 'tulip2.mp3', 'tulip2.m4a']])
-
-class MediaStatsPerfTest(pyauto.PyUITest):
- """PyAuto test container. See file doc string for more information."""
-
- def _GetChromeRendererProcess(self):
- """Returns the Chrome renderer process."""
- renderer_id = self.GetBrowserInfo()['windows'][0]['tabs'][1]['renderer_pid']
- if not renderer_id:
- self.fail('Can not find the tab renderer process.')
- return psutil.Process(renderer_id)
-
- def testMediaPerformance(self):
- """Launches HTML test which plays each video and records statistics."""
- for file_name in _TEST_VIDEOS:
- # Append a tab and delete it at the end of the test to free its memory.
- self.AppendTab(pyauto.GURL(self.GetFileURLForDataPath(_TEST_HTML_PATH)))
-
- file_url = self.GetFileURLForDataPath(file_name)
- logging.debug('Running perf test for %s.', file_url)
-
- renderer_process = self._GetChromeRendererProcess()
- # Call to set a starting time to record CPU usage by the renderer.
- renderer_process.get_cpu_percent()
-
- self.assertTrue(
- self.CallJavascriptFunc('startTest', [file_url], tab_index=1))
-
- cpu_usage = renderer_process.get_cpu_percent()
- mem_usage_mb = renderer_process.get_memory_info()[0] / 1024
- file_name = os.path.basename(file_name)
- pyauto_utils.PrintPerfResult('cpu', file_name, cpu_usage, '%')
- pyauto_utils.PrintPerfResult('memory', file_name, mem_usage_mb, 'KB')
-
- decoded_fps = [
- float(value) for value in
- self.GetDOMValue("decodedFPS.join(',')", tab_index=1).split(',')]
- dropped_frames = self.GetDOMValue('droppedFrames', tab_index=1)
- dropped_fps = [
- float(value) for value in
- self.GetDOMValue("droppedFPS.join(',')", tab_index=1).split(',')]
-
- pyauto_utils.PrintPerfResult('fps', file_name, decoded_fps, 'fps')
- pyauto_utils.PrintPerfResult('dropped_fps', file_name, dropped_fps, 'fps')
- pyauto_utils.PrintPerfResult('dropped_frames', file_name, dropped_frames,
- 'frames')
-
- self.CloseTab(tab_index=1)
-
-
-if __name__ == '__main__':
- pyauto_media.Main()
diff --git a/chrome/test/functional/media/mixed_audio_latency_perf.py b/chrome/test/functional/media/mixed_audio_latency_perf.py
deleted file mode 100755
index f3764d7..0000000
--- a/chrome/test/functional/media/mixed_audio_latency_perf.py
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Audio latency performance test.
-
-Benchmark measuring how fast we can continuously repeat a short sound
-clip, while another clip is running in the background. In the ideal
-scenario we'd have zero latency processing script, seeking back to the
-beginning of the clip, and resuming audio playback.
-
-Performance is recorded as the average latency of N playbacks. I.e., if we play
-a clip 50 times and the ideal duration of all playbacks is 1000ms and the total
-duration is 1500ms, the recorded result is (1500ms - 1000ms) / 50 == 10ms.
-"""
-import os
-
-import pyauto_media
-import pyauto_utils
-import pyauto
-
-
-# HTML test path; relative to src/chrome/test/data.
-_TEST_HTML_PATH = os.path.join('media', 'html', 'mixed_audio_latency_perf.html')
-
-
-class MixedAudioLatencyPerfTest(pyauto.PyUITest):
- """PyAuto test container. See file doc string for more information."""
-
- def testAudioLatency(self):
- """Launches HTML test which runs the audio latency test."""
- self.NavigateToURL(self.GetFileURLForDataPath(_TEST_HTML_PATH))
-
- # Block until the test finishes and notifies us.
- self.assertTrue(self.ExecuteJavascript('startTest();'))
- latency = float(self.GetDOMValue('averageLatency'))
- pyauto_utils.PrintPerfResult('audio_latency', 'latency_bg_clip', latency,
- 'ms')
-
-
-if __name__ == '__main__':
- pyauto_media.Main()
diff --git a/chrome/test/functional/media/pyauto_media.py b/chrome/test/functional/media/pyauto_media.py
deleted file mode 100644
index 952330b2..0000000
--- a/chrome/test/functional/media/pyauto_media.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (c) 2012 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.
-
-"""PyAuto media test base. Handles PyAuto initialization and path setup.
-
-Required to ensure each media test can load the appropriate libraries. Each
-test must include this snippet:
-
- # This should be at the top
- import pyauto_media
-
- <test code>
-
- # This should be at the bottom.
- if __name__ == '__main__':
- pyauto_media.Main()
-"""
-
-import os
-import sys
-
-
-def _SetupPaths():
- """Add paths required for loading PyAuto and other utilities to sys.path."""
- media_dir = os.path.abspath(os.path.dirname(__file__))
- sys.path.append(media_dir)
- sys.path.append(os.path.normpath(os.path.join(media_dir, os.pardir)))
-
- # Add psutil library path.
- # TODO(dalecurtis): This should only be added for tests which use psutil.
- sys.path.append(os.path.normpath(os.path.join(
- media_dir, os.pardir, os.pardir, os.pardir, os.pardir,
- 'third_party', 'psutil')))
-
-
-_SetupPaths()
-
-
-import pyauto_functional
-Main = pyauto_functional.Main
diff --git a/chrome/test/functional/media/worker_thread.py b/chrome/test/functional/media/worker_thread.py
deleted file mode 100644
index 394d051..0000000
--- a/chrome/test/functional/media/worker_thread.py
+++ /dev/null
@@ -1,154 +0,0 @@
-# Copyright (c) 2012 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.
-
-"""Worker thread base class.
-
-Worker threads are used to run multiple PyUITests simultaneously. They
-synchronize calls to the browser."""
-
-import itertools
-import threading
-import pyauto
-
-
-# A static lock used to synchronize worker threads access to the browser.
-__lock = threading.RLock()
-
-def synchronized(fn):
- """A decorator to wrap a lock around function calls."""
- def syncFun(*args, **kwargs):
- with __lock:
- return fn(*args, **kwargs)
-
- return syncFun
-
-
-def RunWorkerThreads(pyauto_test, test_worker_class, tasks, num_threads,
- test_path):
- """Creates a matrix of tasks and starts test worker threads to run them.
-
- Args:
- pyauto_test: Reference to a pyauto.PyUITest instance.
- test_worker_class: WorkerThread class reference.
- tasks: Queue of tasks to run by the worker threads.
- num_threads: Number of threads to run simultaneously.
- test_path: Path to HTML/JavaScript test code.
- """
- # Convert relative test path into an absolute path.
- test_url = pyauto_test.GetFileURLForDataPath(test_path)
-
- # Add shutdown magic to end of queue.
- for _ in xrange(num_threads):
- tasks.put(None)
-
- threads = []
- for _ in xrange(num_threads):
- threads.append(test_worker_class(pyauto_test, tasks, test_url))
-
- # Wait for threads to exit, gracefully or otherwise.
- for thread in threads:
- thread.join()
-
- return sum(thread.failures for thread in threads)
-
-
-class WorkerThread(threading.Thread):
- """Thread which for each queue task: opens tab, runs task, closes tab."""
-
- # Atomic, monotonically increasing task identifier. Used to ID tabs.
- _task_id = itertools.count()
-
- def __init__(self, pyauto_test, tasks, url):
- """Sets up WorkerThread class variables.
-
- Args:
- pyauto_test: Reference to a pyauto.PyUITest instance.
- tasks: Queue containing task tuples used by RunTest().
- url: File URL to HTML/JavaScript test code.
- """
- threading.Thread.__init__(self)
- self.__pyauto = pyauto_test
- self.__tasks = tasks
- self.__url = url
- self.failures = 0
- self.start()
-
- def RunTask(self, unique_url, task):
- """Runs the specific task on the url test page.
-
- This method should be overridden to start the test on the unique_url page.
-
- Args:
- unique_url: A unique identifier of the test page.
- task: A tuple with information needed to run the test.
- Returns:
- True if the task finished as expected.
- """
- raise NotImplementedError('RunTask should be defined in a subclass.')
-
- def run(self):
- """For each task in queue: opens new tab, calls RunTask(), then closes tab.
-
- No exception handling is done to make sure the main thread exits properly
- during Chrome crashes or other failures.
-
- For a clean shutdown, put the magic exit value None in the queue.
- """
- while True:
- task = self.__tasks.get()
- # Check for magic exit values.
- if task is None:
- break
- # Make the test URL unique so we can figure out our tab index later.
- unique_url = '%s?%d' % (self.__url, WorkerThread._task_id.next())
- self.AppendTab(unique_url)
- if not self.RunTask(unique_url, task):
- self.failures += 1
- self.CloseTabByURL(unique_url)
- self.__tasks.task_done()
-
- def __FindTabLocked(self, url):
- """Returns the tab index for the tab belonging to this url.
-
- __lock must be owned by caller.
- """
- if url is None:
- return 0
- for tab in self.__pyauto.GetBrowserInfo()['windows'][0]['tabs']:
- if tab['url'] == url:
- return tab['index']
-
- # The following are wrappers to pyauto.PyUITest functions. They are wrapped
- # with an internal lock to avoid problems when more than one thread edits the
- # state of the browser.
- #
- # We limit access of subclasses to the following functions. If subclasses
- # access other PyUITest functions, then there is no guarantee of thread
- # safety.
- #
- # For details on the args check pyauto.PyUITest class.
- @synchronized
- def AppendTab(self, url):
- self.__pyauto.AppendTab(pyauto.GURL(url))
-
- @synchronized
- def CallJavascriptFunc(self, fun_name, fun_args=[], url=None):
- return self.__pyauto.CallJavascriptFunc(fun_name, fun_args,
- tab_index=self.__FindTabLocked(url))
-
- @synchronized
- def CloseTabByURL(self, url):
- """Closes the tab with the given url."""
- self.__pyauto.CloseTab(tab_index=self.__FindTabLocked(url))
-
- @synchronized
- def GetDOMValue(self, name, url=None):
- return self.__pyauto.GetDOMValue(name, tab_index=self.__FindTabLocked(url))
-
- def WaitUntil(self, *args, **kwargs):
- """We do not need to lock WaitUntil since it does not call into Chrome.
-
- Ensure that the function passed in the args is thread safe.
- """
- return self.__pyauto.WaitUntil(*args, **kwargs)
diff --git a/chrome/test/functional/memory.py b/chrome/test/functional/memory.py
deleted file mode 100755
index ee2ae4c..0000000
--- a/chrome/test/functional/memory.py
+++ /dev/null
@@ -1,134 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import os
-import sys
-import time
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-import test_utils
-
-
-class MemoryTest(pyauto.PyUITest):
- """Tests for memory usage of Chrome-related processes.
-
- These tests are meant to be used manually, not as part of the continuous
- test cycle. This is because each test starts up and periodically
- measures/records the memory usage of a relevant Chrome process, doing so
- repeatedly until the test is manually killed. Currently, this script only
- works in Linux and ChromeOS, as it uses a Linux shell command to query the
- system for process memory usage info (test_utils.GetMemoryUsageOfProcess()).
-
- The tests in this suite produce the following output files (relative to the
- current working directory):
-
- testTabRendererProcessMemoryUsage: 'renderer_process_mem.txt'
- testExtensionProcessMemoryUsage: 'extension_process_mem.txt'
- """
-
- # Constants for all tests in this suite.
- NUM_SECONDS_BETWEEN_MEASUREMENTS = 10
- MEASUREMENT_LOG_MESSAGE_TEMPLATE = '[%s] %.2f MB (pid: %d)'
- LOG_TO_OUTPUT_FILE = True
-
- # Constants for testTabRendererProcessMemoryUsage.
- RENDERER_PROCESS_URL = 'http://chrome.angrybirds.com'
- RENDERER_PROCESS_OUTPUT_FILE = 'renderer_process_mem.txt'
-
- # Constants for testExtensionProcessMemoryUsage.
- EXTENSION_LOCATION = os.path.abspath(os.path.join(
- pyauto.PyUITest.DataDir(), 'extensions', 'google_talk.crx'))
- EXTENSION_PROCESS_NAME = 'Google Talk'
- EXTENSION_PROCESS_OUTPUT_FILE = 'extension_process_mem.txt'
-
- def _GetPidOfExtensionProcessByName(self, name):
- """Identifies the process ID of an extension process, given its name.
-
- Args:
- name: The string name of an extension process, as returned by the function
- GetBrowserInfo().
-
- Returns:
- The integer process identifier (PID) for the specified process, or
- None if the PID cannot be identified.
- """
- info = self.GetBrowserInfo()['extension_views']
- pid = [x['pid'] for x in info if x['name'] == '%s' % name]
- if pid:
- return pid[0]
- return None
-
- def _LogMessage(self, log_file, msg):
- """Logs a message to the screen, and to a log file if necessary.
-
- Args:
- log_file: The string name of a log file to which to write.
- msg: The message to log.
- """
- print msg
- sys.stdout.flush()
- if self.LOG_TO_OUTPUT_FILE:
- print >>open(log_file, 'a'), msg
-
- def testTabRendererProcessMemoryUsage(self):
- """Test the memory usage of the renderer process for a tab.
-
- This test periodically queries the system for the current memory usage
- of a tab's renderer process. The test will take measurements forever; you
- must manually kill the test to terminate it.
- """
- if (self.LOG_TO_OUTPUT_FILE and
- os.path.exists(self.RENDERER_PROCESS_OUTPUT_FILE)):
- os.remove(self.RENDERER_PROCESS_OUTPUT_FILE)
- self.NavigateToURL(self.RENDERER_PROCESS_URL)
- self._LogMessage(
- self.RENDERER_PROCESS_OUTPUT_FILE,
- 'Memory usage for renderer process of a tab navigated to: "%s"' % (
- self.RENDERER_PROCESS_URL))
-
- # A user must manually kill this test to terminate the following loop.
- while True:
- pid = self.GetBrowserInfo()['windows'][0]['tabs'][0]['renderer_pid']
- usage = test_utils.GetMemoryUsageOfProcess(pid)
- current_time = time.asctime(time.localtime(time.time()))
- self._LogMessage(
- self.RENDERER_PROCESS_OUTPUT_FILE,
- self.MEASUREMENT_LOG_MESSAGE_TEMPLATE % (current_time, usage, pid))
- time.sleep(self.NUM_SECONDS_BETWEEN_MEASUREMENTS)
-
- def testExtensionProcessMemoryUsage(self):
- """Test the memory usage of an extension process.
-
- This test periodically queries the system for the current memory usage
- of an extension process. The test will take measurements forever; you
- must manually kill the test to terminate it.
- """
- if (self.LOG_TO_OUTPUT_FILE and
- os.path.exists(self.EXTENSION_PROCESS_OUTPUT_FILE)):
- os.remove(self.EXTENSION_PROCESS_OUTPUT_FILE)
- self.InstallExtension(self.EXTENSION_LOCATION)
- # The PID is 0 until the extension has a chance to start up.
- self.WaitUntil(
- lambda: self._GetPidOfExtensionProcessByName(
- self.EXTENSION_PROCESS_NAME) not in [0, None])
- self._LogMessage(
- self.EXTENSION_PROCESS_OUTPUT_FILE,
- 'Memory usage for extension process with name: "%s"' % (
- self.EXTENSION_PROCESS_NAME))
-
- # A user must manually kill this test to terminate the following loop.
- while True:
- pid = self._GetPidOfExtensionProcessByName(self.EXTENSION_PROCESS_NAME)
- usage = test_utils.GetMemoryUsageOfProcess(pid)
- current_time = time.asctime(time.localtime(time.time()))
- self._LogMessage(
- self.EXTENSION_PROCESS_OUTPUT_FILE,
- self.MEASUREMENT_LOG_MESSAGE_TEMPLATE % (current_time, usage, pid))
- time.sleep(self.NUM_SECONDS_BETWEEN_MEASUREMENTS)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/multiprofile.py b/chrome/test/functional/multiprofile.py
deleted file mode 100755
index c715db2..0000000
--- a/chrome/test/functional/multiprofile.py
+++ /dev/null
@@ -1,314 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import re
-
-import pyauto_functional
-import pyauto
-
-
-class MultiprofileTest(pyauto.PyUITest):
- """Tests for Multi-Profile / Multi-users"""
-
- _RESTORE_STARTUP_URL_VALUE = 4
- _RESTORE_LASTOPEN_URL_VALUE = 1
- _RESTORE_DEFAULT_URL_VALUE = 0
-
- def Debug(self):
- """Test method for experimentation.
-
- This method will not run automatically.
- """
- while True:
- raw_input('Hit <enter> to dump info.. ')
- self.pprint(self.GetMultiProfileInfo())
-
- def _GetSearchEngineWithKeyword(self, keyword, windex=0):
- """Get search engine info and return an element that matches keyword.
-
- Args:
- keyword: Search engine keyword field.
- windex: The window index, default is 0.
-
- Returns:
- A search engine info dict or None.
- """
- match_list = ([x for x in self.GetSearchEngineInfo(windex=windex)
- if x['keyword'] == keyword])
- if match_list:
- return match_list[0]
- return None
-
- def _SetPreferences(self, dict, windex=0):
- """Sets preferences settings.
-
- Args:
- _dict: Dictionary of key preferences and its value to be set.
- windex: The window index, defaults to 0 (the first window).
- """
- for key in dict.iterkeys():
- self.SetPrefs(key, dict[key], windex=windex)
-
- def _SetStartUpPage(self, url, windex=0):
- """Set start up page.
-
- Args:
- url: URL of the page to be set as start up page.
- windex: The window index, default is 0.
- """
- _dict = {pyauto.kURLsToRestoreOnStartup: [url],
- pyauto.kRestoreOnStartup: self._RESTORE_STARTUP_URL_VALUE}
- self._SetPreferences(_dict, windex=windex)
- prefs_info = self.GetPrefsInfo(windex=windex).Prefs(
- pyauto.kURLsToRestoreOnStartup)
- self.assertTrue(url in prefs_info)
-
- def _SetHomePage(self, url, windex=0):
- """Create new profile and set home page.
-
- Args:
- url: URL of the page to be set as home page
- windex: The window index, default is 0.
- """
- _dict = {pyauto.kHomePage: url,
- pyauto.kHomePageIsNewTabPage: False, pyauto.kShowHomeButton: True,
- pyauto.kRestoreOnStartup: self._RESTORE_DEFAULT_URL_VALUE}
- self._SetPreferences(_dict, windex=windex)
- self.assertTrue(url in
- self.GetPrefsInfo(windex=windex).Prefs(pyauto.kHomePage))
-
- def _SetSessionRestoreURLs(self, set_restore, windex=0):
- """Create new profile and set home page.
-
- Args:
- set_restore: Value of action of start up.
- windex: The window index, default is 0.
- """
- self.NavigateToURL('http://www.google.com/', windex)
- self.AppendTab(pyauto.GURL('http://news.google.com/'), windex)
- num_tabs = self.GetTabCount(windex)
- dict = {pyauto.kRestoreOnStartup: set_restore}
- self._SetPreferences(dict, windex=windex)
-
- def _AddSearchEngine(self, title, keyword, url, windex=0):
- """Add search engine.
-
- Args:
- title: Name for search engine.
- keyword: Keyword, used to initiate a custom search from omnibox.
- url: URL template for this search engine's query.
- windex: The window index, default is 0.
- """
- self.AddSearchEngine(title, keyword, url, windex=windex)
- name = self._GetSearchEngineWithKeyword(keyword, windex=windex)
- self.assertTrue(name)
-
- def _AssertStartUpPage(self, url, profile='Default'):
- """Asserts start up page for given profile.
-
- Args:
- url: URL of the page to be set as start up page
- profile: The profile name, defaults to 'Default'.
- """
- self.AppendBrowserLaunchSwitch('--profile-directory=' + profile)
- self.RestartBrowser(clear_profile=False)
- info = self.GetBrowserInfo()
- self.assertEqual(url, info['windows'][0]['tabs'][0]['url'].rstrip('/'))
- self.assertTrue(url in
- self.GetPrefsInfo().Prefs(pyauto.kURLsToRestoreOnStartup))
-
- def _AssertHomePage(self, url, profile='Default'):
- """Asserts home page for given profile.
-
- Args:
- url: URL of the page to be set as home page
- profile: The profile name, defaults to 'Dafault'.
- """
- self.AppendBrowserLaunchSwitch('--profile-directory=' + profile)
- self.RestartBrowser(clear_profile=False)
- self.assertTrue(url in self.GetPrefsInfo().Prefs(pyauto.kHomePage))
-
- def _AssertDefaultSearchEngine(self, search_engine, profile='Default'):
- """Asserts default search engine for given profile.
-
- Args:
- search_engine: Name of default search engine.
- profile: The profile name, defaults to 'Default'.
- """
- self.AppendBrowserLaunchSwitch('--profile-directory=' + profile)
- self.RestartBrowser(clear_profile=False)
- name = self._GetSearchEngineWithKeyword(search_engine)
- self.assertTrue(name['is_default'])
- self.SetOmniboxText('test search')
- self.OmniboxAcceptInput()
- self.assertTrue(re.search(search_engine, self.GetActiveTabURL().spec()))
-
- def _AssertSessionRestore(self, url_list, set_restore, num_tabs=1,
- profile='Default'):
- """Asserts urls when session is set to restored or set default.
-
- Args:
- url_list: List of URL to be restored.
- set_restore: Value of action of start up.
- num_tabs: Number of tabs to be restored, default is 1.
- profile: The profile name, defaults to 'Default'.
- """
- self.AppendBrowserLaunchSwitch('--profile-directory=' + profile)
- self.RestartBrowser(clear_profile=False)
- self.assertEqual(num_tabs, self.GetTabCount())
- self.assertEqual(self.GetPrefsInfo().Prefs(pyauto.kRestoreOnStartup),
- set_restore)
- tab_index = 0
- while (tab_index < num_tabs):
- self.ActivateTab(tab_index)
- self.assertEqual(url_list[tab_index], self.GetActiveTabURL().spec())
- tab_index += 1
-
- def testBasic(self):
- """Multi-profile windows can open."""
- self.assertEqual(1, self.GetBrowserWindowCount())
- self.assertTrue(self.GetMultiProfileInfo()['enabled'],
- msg='Multi-profile is not enabled')
- self.OpenNewBrowserWindowWithNewProfile()
- # Verify multi-profile info.
- multi_profile = self.GetMultiProfileInfo()
- self.assertEqual(2, len(multi_profile['profiles']))
- new_profile = multi_profile['profiles'][1]
- self.assertTrue(new_profile['name'])
-
- # Verify browser windows.
- self.assertEqual(2, self.GetBrowserWindowCount(),
- msg='New browser window did not open')
- info = self.GetBrowserInfo()
- new_profile_window = info['windows'][1]
- self.assertEqual('Profile 1', new_profile_window['profile_path'])
- self.assertEqual(1, len(new_profile_window['tabs']))
- self.assertEqual('chrome://newtab/', new_profile_window['tabs'][0]['url'])
-
- def test20NewProfiles(self):
- """Verify we can create 20 new profiles."""
- for index in range(1, 21):
- self.OpenNewBrowserWindowWithNewProfile()
- multi_profile = self.GetMultiProfileInfo()
- self.assertEqual(index + 1, len(multi_profile['profiles']),
- msg='Expected %d profiles after adding %d new users. Got %d' % (
- index + 1, index, len(multi_profile['profiles'])))
-
- def testStartUpPageOptionInMultiProfile(self):
- """Test startup page for Multi-profile windows."""
- self.assertTrue(self.GetMultiProfileInfo()['enabled'],
- msg='Multi-profile is not enabled')
- # Launch browser with new Profile 1, set startup page to 'www.google.com'.
- self.OpenNewBrowserWindowWithNewProfile()
- self._SetStartUpPage('http://www.google.com', windex=1)
- # Launch browser with new Profile 2, set startup page to 'www.yahoo.com'.
- self.OpenNewBrowserWindowWithNewProfile()
- # Verify start up page for Profile 2 is still newtab page.
- info = self.GetBrowserInfo()
- self.assertEqual('chrome://newtab/', info['windows'][2]['tabs'][0]['url'])
- self._SetStartUpPage('http://www.yahoo.com', windex=2)
- # Exit Profile 1 / Profile 2
- self.CloseBrowserWindow(2)
- self.CloseBrowserWindow(1)
- # Relaunch Browser with Profile 2, verify startup page.
- self._AssertStartUpPage('http://www.yahoo.com', profile='Profile 2')
- # Relaunch Browser with Profile 1, verify startup page.
- self._AssertStartUpPage('http://www.google.com', profile='Profile 1')
-
- def testHomePageOptionMultiProfile(self):
- """Test Home page for Multi-profile windows."""
- self.assertTrue(self.GetMultiProfileInfo()['enabled'],
- msg='Multi-profile is not enabled')
- # Launch browser with new Profile 1, set homepage to 'www.google.com'.
- self.OpenNewBrowserWindowWithNewProfile()
- self._SetHomePage('http://www.google.com', windex=1)
- # Launch browser with new Profile 2, set homepage to 'www.yahoo.com'.
- self.OpenNewBrowserWindowWithNewProfile()
- self._SetHomePage('http://www.yahoo.com', windex=2)
- # Exit Profile 1 / Profile 2
- self.CloseBrowserWindow(2)
- self.CloseBrowserWindow(1)
- # Relaunch Browser with Profile 2, verify startup page.
- self._AssertHomePage('http://www.yahoo.com', profile='Profile 2')
- # Relaunch Browser with Profile 1, verify startup page.
- self._AssertHomePage('http://www.google.com', profile='Profile 1')
-
- def testSessionRestoreInMultiProfile(self):
- """Test session restore preference for Multi-profile windows."""
- self.assertTrue(self.GetMultiProfileInfo()['enabled'],
- msg='Multi-profile is not enabled')
- # Launch browser with new Profile 1, set pref to restore session on
- # startup.
- self.OpenNewBrowserWindowWithNewProfile()
- self._SetSessionRestoreURLs(self._RESTORE_LASTOPEN_URL_VALUE, windex=1)
- # Launch browser with new Profile 2, do not set session restore pref.
- self.OpenNewBrowserWindowWithNewProfile()
- self._SetSessionRestoreURLs(self._RESTORE_DEFAULT_URL_VALUE, windex=2)
- # Exit Profile 1 / Profile 2
- self.CloseBrowserWindow(2)
- self.CloseBrowserWindow(1)
- # Relaunch Browser with Profile 1, verify session restores on startup.
- url_list = ['http://www.google.com/', 'http://news.google.com/']
- self._AssertSessionRestore(url_list, self._RESTORE_LASTOPEN_URL_VALUE,
- num_tabs=2, profile='Profile 1')
- # Relaunch Browser with Profile 2, verify session does not get restored.
- url_list = ['chrome://newtab/']
- self._AssertSessionRestore(url_list, self._RESTORE_DEFAULT_URL_VALUE,
- num_tabs=1, profile='Profile 2')
-
- def testMakeSearchEngineDefaultInMultiprofile(self):
- """Test adding and making a search engine default for Multi-profiles."""
- self.assertTrue(self.GetMultiProfileInfo()['enabled'],
- msg='Multi-profile is not enabled')
- # Launch browser with new Profile 1, add search engine to 'Hulu'.
- self.OpenNewBrowserWindowWithNewProfile()
- self._AddSearchEngine('Hulu', 'hulu.com',
- 'http://www.hulu.com/search?query=%s&ref=os&src={referrer:source?}', 1)
- self.MakeSearchEngineDefault('hulu.com', windex=1)
- # Launch browser with new Profile 2, add search engine to 'Youtube'.
- self.OpenNewBrowserWindowWithNewProfile()
- self._AddSearchEngine('YouTube Video Search', 'youtube.com',
- 'http://www.youtube.com/results?search_query=%s&page={startPage?}'+
- '&utm_source=opensearch', 2)
- self.MakeSearchEngineDefault('youtube.com', windex=2)
- # Exit Profile 1 / Profile 2
- self.CloseBrowserWindow(2)
- self.CloseBrowserWindow(1)
- # Relaunch Browser with Profile 1, verify default search engine as 'Hulu'.
- self._AssertDefaultSearchEngine('hulu.com', profile='Profile 1')
- # Relaunch Browser with Profile 2, verify default search engine as
- # 'Youtube'.
- self._AssertDefaultSearchEngine('youtube.com', profile='Profile 2')
-
- def testDeleteSearchEngineInMultiprofile(self):
- """Test adding then deleting a search engine for Multi-profiles."""
- self.assertTrue(self.GetMultiProfileInfo()['enabled'],
- msg='Multi-profile is not enabled')
- # Launch browser with new Profile 1, add 'foo.com' as new search engine.
- self.OpenNewBrowserWindowWithNewProfile()
- self._AddSearchEngine('foo', 'foo.com', 'http://foo/?q=%s', windex=1)
- # Launch browser with new Profile 2, add 'foo.com' as new search engine.
- self.OpenNewBrowserWindowWithNewProfile()
- self._AddSearchEngine('foo', 'foo.com', 'http://foo/?q=%s', windex=2)
- # Delete search engine 'foo.com' from Profile 1 and exit.
- self.DeleteSearchEngine('foo.com', windex=1)
- self.CloseBrowserWindow(2)
- self.CloseBrowserWindow(1)
- # Relaunch Browser with Profile 1, verify search engine 'foo.com'
- # is deleted.
- self.AppendBrowserLaunchSwitch('--profile-directory=Profile 1')
- self.RestartBrowser(clear_profile=False)
- foo = self._GetSearchEngineWithKeyword('foo.com')
- self.assertFalse(foo)
- # Relaunch Browser with Profile 2, verify search engine 'foo.com'
- # is not deleted.
- self.AppendBrowserLaunchSwitch('--profile-directory=Profile 2')
- self.RestartBrowser(clear_profile=False)
- foo = self._GetSearchEngineWithKeyword('foo.com')
- self.assertTrue(foo)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/nacl_sdk.py b/chrome/test/functional/nacl_sdk.py
deleted file mode 100755
index 41a95fa..0000000
--- a/chrome/test/functional/nacl_sdk.py
+++ /dev/null
@@ -1,796 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import copy
-import ctypes
-from distutils import version
-import fnmatch
-import glob
-import hashlib
-import logging
-import os
-import platform
-import re
-import shutil
-import subprocess
-import sys
-import tempfile
-import urllib2
-import xml.dom.minidom
-import zipfile
-
-import pyauto_functional # Must be imported before pyauto.
-import pyauto
-import pyauto_utils
-import test_utils
-
-
-class NaClSDKTest(pyauto.PyUITest):
- """Tests for the NaCl SDK."""
- _isExamplesTest = False
- _extracted_sdk_path = None
- _temp_dir = None
- _updated_pepper_versions = []
- _latest_updated_pepper_versions = []
- _settings = {
- 'post_sdk_download_url': 'http://code.google.com/chrome/nativeclient/'
- 'docs/download.html',
- 'post_sdk_zip': 'http://storage.googleapis.com/'
- 'nativeclient-mirror/nacl/nacl_sdk/nacl_sdk.zip',
- 'min_required_chrome_build': 14,
- }
-
- def tearDown(self):
- pyauto.PyUITest.tearDown(self)
- if not self._isExamplesTest:
- self._RemoveDownloadedTestFile()
-
- def testNaClSDK(self):
- """Verify that NaCl SDK is working properly."""
- if not self._HasAllSystemRequirements():
- logging.info('System does not meet the requirements.')
- return
- self._extracted_sdk_path = tempfile.mkdtemp()
- self._VerifyDownloadLinks()
- self._VerifyNaClSDKInstaller()
- self._VerifyInstall()
- self._VerifyUpdate()
- self._LaunchServerAndVerifyExamplesAllPepperVersions()
-
- def NaClSDKExamples(self):
- """Verify if NaCl SDK examples are working."""
- self._isExamplesTest = True
- nacl_sdk_root = os.environ.get('NACL_SDK_ROOT', None)
- pepper_version = os.environ.get('PEPPER_VER', None)
- if nacl_sdk_root and pepper_version:
- self._LaunchServerAndVerifyExamples('pepper_' + pepper_version,
- nacl_sdk_root)
- else:
- self.fail(msg='Missing pepper version to be checked or SDK path.')
-
- def _VerifyDownloadLinks(self):
- """Verify the download links.
-
- Simply verify that NaCl download links exist in html page.
- """
- html = None
- for i in xrange(3):
- try:
- html = urllib2.urlopen(self._settings['post_sdk_download_url']).read()
- break
- except:
- pass
- self.assertTrue(html,
- msg='Cannot open URL: %s' %
- self._settings['post_sdk_download_url'])
- sdk_url = self._settings['post_sdk_zip']
- self.assertTrue(sdk_url in html,
- msg='Missing SDK download URL: %s' % sdk_url)
-
- def _VerifyNaClSDKInstaller(self):
- """Verify NaCl SDK installer."""
- search_list = [
- 'sdk_cache/',
- 'sdk_tools/',
- ]
- mac_lin_additional_search_items = [
- 'naclsdk',
- ]
- win_additional_search_items = [
- 'naclsdk.bat'
- ]
- self._DownloadNaClSDK()
- self._ExtractNaClSDK()
- if pyauto.PyUITest.IsWin():
- self._SearchNaClSDKFile(
- search_list + win_additional_search_items)
- elif pyauto.PyUITest.IsMac() or pyauto.PyUITest.IsLinux():
- self._SearchNaClSDKFile(
- search_list + mac_lin_additional_search_items)
- else:
- self.fail(msg='NaCl SDK does not support this OS.')
-
- def _VerifyInstall(self):
- """Install NACL sdk."""
- # Executing naclsdk(.bat) list
- if pyauto.PyUITest.IsWin():
- source_file = os.path.join(
- self._extracted_sdk_path, 'nacl_sdk', 'naclsdk.bat')
- elif pyauto.PyUITest.IsMac() or pyauto.PyUITest.IsLinux():
- source_file = os.path.join(
- self._extracted_sdk_path, 'nacl_sdk', 'naclsdk')
- subprocess.call(['chmod', '-R', '755', self._extracted_sdk_path])
- else:
- self.fail(msg='NaCl SDK does not support this OS.')
- subprocess.Popen([source_file, 'list'],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE).communicate()
-
- def _VerifyUpdate(self):
- """Update NACL sdk"""
- # Executing naclsdk(.bat) update
- if pyauto.PyUITest.IsWin():
- source_file = os.path.join(self._extracted_sdk_path, 'nacl_sdk',
- 'naclsdk.bat')
- elif pyauto.PyUITest.IsMac() or pyauto.PyUITest.IsLinux():
- source_file = os.path.join(self._extracted_sdk_path, 'nacl_sdk',
- 'naclsdk')
- else:
- self.fail(msg='NaCl SDK does not support this OS.')
- # Executing nacl_sdk(.bat) update to get the latest version.
- updated_output = subprocess.Popen([source_file, 'update'],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
- self._updated_pepper_versions.extend(
- re.findall('Updating bundle (pepper_[0-9]{2})', updated_output))
- self._updated_pepper_versions = list(set(self._updated_pepper_versions))
- self._updated_pepper_versions.sort(key=str.lower)
- updated_pepper_versions_len = len(self._updated_pepper_versions)
- self._latest_updated_pepper_versions = filter(
- lambda x: x >= 'pepper_18', self._updated_pepper_versions)
-
- def _GetURLForExampleName(self, name, toolchain):
- return 'http://localhost:5103/%s/index_%s.html' % (name, toolchain)
-
- def _GetExampleNamesAndURLs(self, examples_path):
- """Get a list of all examples as (name, url) tuples.
-
- Args:
- examples_path: The path to the examples directory in the NaCl SDK.
- """
- toolchains = ['newlib', 'glibc', 'pnacl']
-
- examples = []
- for toolchain in toolchains:
- for example in os.listdir(examples_path):
- html_path = os.path.join(examples_path, example,
- 'index_%s.html' % (toolchain,))
- if os.path.exists(html_path):
- example_url = self._GetURLForExampleName(example, toolchain)
- examples.append((example, example_url))
- return examples
-
- def _LaunchServerAndVerifyExamplesAllPepperVersions(self):
- for pepper_version in self._latest_updated_pepper_versions:
- pepper_path = os.path.join(self._extracted_sdk_path,
- 'nacl_sdk', 'pepper_' + str(pepper_version))
- self._LaunchServerAndVerifyExamples(pepper_version, pepper_path)
-
- def _LaunchServerAndVerifyExamples(self, pepper_version, pepper_path):
- """Start local HTTP server and verify examples."""
- if self._ChromeAndPepperVersionMatch(pepper_version):
- # Close server if it's already open.
- if self._IsURLAlive('http://localhost:5103'):
- self._CloseHTTPServer()
-
- examples_path = os.path.join(pepper_path, 'examples')
-
- # Launch local http server.
- proc = subprocess.Popen(['make RUN'], shell=True, cwd=examples_path)
- self.WaitUntil(
- lambda: self._IsURLAlive('http://localhost:5103'),
- timeout=150, retry_sleep=1)
-
- examples = self._GetExampleNamesAndURLs(examples_path)
- try:
- self._OpenExamplesAndStartTest(examples)
- finally:
- self._CloseHTTPServer(proc)
-
- else:
- self.pprint('Pepper Version %s does not match the Chrome version %s.'
- % (pepper_version,
- self.GetBrowserInfo()['properties']['ChromeVersion']))
-
- def _ChromeAndPepperVersionMatch(self, pepper_version='pepper_18'):
- """Determine if chrome and pepper version match"""
- version_number = re.findall('pepper_([0-9]{2})', pepper_version)
- browser_info = self.GetBrowserInfo()
- chrome_version = browser_info['properties']['ChromeVersion']
- chrome_build = int(chrome_version.split('.')[0])
- return int(chrome_build) == int(version_number[0])
-
- def _RemoveDownloadedTestFile(self):
- """Delete downloaded files and dirs from downloads directory."""
- if self._extracted_sdk_path and os.path.exists(self._extracted_sdk_path):
- self._CloseHTTPServer()
-
- def _RemoveFile():
- shutil.rmtree(self._extracted_sdk_path, ignore_errors=True)
- return os.path.exists(self._extracted_sdk_path)
-
- success = self.WaitUntil(_RemoveFile, retry_sleep=2,
- expect_retval=False)
- self.assertTrue(success,
- msg='Cannot remove %s' % self._extracted_sdk_path)
-
- if self._temp_dir:
- pyauto_utils.RemovePath(self._temp_dir)
-
- def _OpenExamplesAndStartTest(self, examples):
- """Open each example and verify that it's working.
-
- Args:
- examples: A list of example (name, url) tuples.
- """
- example_verify_funcs = {
- 'dlopen': self._VerifyDynamicLibraryOpen,
- 'file_io': self._VerifyFileIoExample,
- 'geturl': self._VerifyGetURLExample,
- 'input_events': self._VerifyInputEventsExample,
- 'load_progress': self._VerifyLoadProgressExample,
- 'mt_input_events': self._VerifyMultithreadedInputEventsExample,
- 'pi_generator': self._VerifyPiGeneratorExample,
- 'sine_synth': self._VerifySineSynthExample,
- 'websocket': self._VerifyWebSocketExample,
- }
-
- # Remove examples that we don't yet verify
- examples = [(name, url) for name, url in examples
- if name in example_verify_funcs]
-
- # Open all examples.
- for name, url in examples:
- self.AppendTab(pyauto.GURL(url))
- self._CheckForCrashes()
-
- # Verify all examples are working.
- for name, url in examples:
- self._VerifyAnExample(name, url, example_verify_funcs[name])
- self._CheckForCrashes()
-
- # Close each tab and check for crashes.
- tab_count = self.GetTabCount()
- for index in xrange(tab_count - 1, 0, -1):
- self.CloseTab(tab_index=index)
- self._CheckForCrashes()
-
- def _VerifyAnExample(self, name, url, verify_func):
- """Verify NaCl example is working.
-
- Args:
- name: A string name of the example.
- url: A string url of the example.
- verify_func: The function to verify the example.
- Takes (tab_index, name, url) as parameters.
- """
- if not verify_func:
- self.fail(msg='No test available for %s.' % name)
-
- info = self.GetBrowserInfo()
- tabs = info['windows'][0]['tabs']
- tab_index = None
- for tab in tabs:
- if url == tab['url']:
- self.ActivateTab(tab['index'])
- tab_index = tab['index']
- break
-
- if tab_index:
- verify_func(tab_index, name, url)
-
- def _VerifyElementPresent(self, element_id, expected_value, tab_index, msg,
- attribute='innerHTML', timeout=150):
- """Determine if dom element has the expected value.
-
- Args:
- element_id: Dom element's id.
- expected_value: String to be matched against the Dom element.
- tab_index: Tab index to work on.
- attribute: Attribute to match |expected_value| against, if
- given. Defaults to 'innerHTML'.
- timeout: The max timeout (in secs) for which to wait.
- """
- js_code = """
- var output = document.getElementById('%s').%s;
- var result;
- if (output.indexOf('%s') != -1)
- result = 'pass';
- else
- result = 'fail';
- window.domAutomationController.send(result);
- """ % (element_id, attribute, expected_value)
- success = self.WaitUntil(
- lambda: self.ExecuteJavascript(js_code, tab_index),
- timeout=timeout, expect_retval='pass')
- self.assertTrue(success, msg=msg)
-
- def _CreateJSToSimulateMouseclick(self):
- """Create javascript to simulate mouse click event."""
- js_code = """
- var rightClick = document.createEvent('MouseEvents');
- rightClick.initMouseEvent(
- 'mousedown', true, true, document,
- 1, 32, 121, 10, 100,
- false, false, false, false,
- 2, common.naclModule
- );
- common.naclModule.dispatchEvent(rightClick);
- window.domAutomationController.send('done');
- """
- return js_code
-
- def _VerifyInputEventsExample(self, tab_index, name, url):
- """Verify Input Events Example.
-
- Args:
- tab_index: Tab index integer that the example is on.
- name: A string name of the example.
- url: A string url of the example.
- """
- success = self._VerifyElementPresent('eventString', 'DidChangeView',
- tab_index, msg='Example %s failed. URL: %s' % (name, url))
-
- # Simulate mouse click on event module.
- js_code = self._CreateJSToSimulateMouseclick()
- self.ExecuteJavascript(js_code, tab_index)
-
- # Check if 'eventString' has handled above mouse click.
- success = self.WaitUntil(
- lambda: re.search('DidHandleInputEvent', self.GetDOMValue(
- 'document.getElementById("eventString").innerHTML',
- tab_index)).group(), expect_retval='DidHandleInputEvent')
- self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
-
- def _VerifyMultithreadedInputEventsExample(self, tab_index, name, url):
- """Verify Input Events Example.
-
- Args:
- tab_index: Tab index integer that the example is on.
- name: A string name of the example.
- url: A string url of the example.
- """
- success = self.WaitUntil(
- lambda: bool(self.GetDOMValue(
- 'document.getElementById("eventString").innerHTML',
- tab_index).find('DidChangeView') + 1))
-
- self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
-
- # Simulate mouse click on event module.
- js_code = self._CreateJSToSimulateMouseclick()
- self.ExecuteJavascript(js_code, tab_index)
-
- # Check if above mouse click is handled.
- success = self._VerifyElementPresent('eventString', 'Mouse event',
- tab_index, msg='Example %s failed. URL: %s' % (name, url))
-
- # Kill worker thread and queue
- js_code = """
- document.getElementsByTagName('button')[0].click();
- window.domAutomationController.send('done');
- """
- self.ExecuteJavascript(js_code, tab_index)
-
- # Check if main thread has cancelled queue.
- success = self._VerifyElementPresent('eventString', 'Received cancel',
- tab_index, msg='Example %s failed. URL: %s' % (name, url))
-
- # Simulate mouse click on event module.
- js_code = self._CreateJSToSimulateMouseclick()
- self.ExecuteJavascript(js_code, tab_index)
-
- # Check if above mouse click is not handled after killing worker thread.
- def _CheckMouseClickEventStatus():
- return self.GetDOMValue(
- 'document.getElementById("eventString").innerHTML',
- tab_index).find('Mouse event', self.GetDOMValue(
- 'document.getElementById("eventString").innerHTML', tab_index).find(
- 'Received cancel'))
-
- success = self.WaitUntil(_CheckMouseClickEventStatus, expect_retval=-1)
- self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
-
- def _VerifyFileIoExample(self, tab_index, name, url):
- """Verify File IO Example.
-
- Args:
- tab_index: Tab index integer that the example is on.
- name: A string name of the example.
- url: A string url of the example.
- """
- def _CheckStatus(substring_expected, fail_msg):
- self.assertTrue(
- self.WaitUntil(
- lambda: self.GetDOMValue(
- 'document.getElementById("statusField").innerHTML', tab_index)\
- .find(substring_expected) != -1, expect_retval=True),
- msg='Example %s failed. URL: %s. Reason: %s' % (name, url, fail_msg))
-
- # Give permission to use file system by clicking infobar OK
- infobar_index = test_utils.WaitForInfobarTypeAndGetIndex(self,
- 'confirm_infobar', 0, tab_index)
- self.PerformActionOnInfobar('accept', infobar_index, 0, tab_index)
- _CheckStatus('Ready!', 'NaCl module load')
-
- # Check that deleting non-existing files gives file not found
- js_code = """
- document.getElementById('file_name').value = '/abc';
- document.getElementById('file_editor').value = 'test';
- document.getElementById('delete_but').click();
- window.domAutomationController.send('done');
- """
- self.ExecuteJavascript(js_code, tab_index)
- _CheckStatus('File not found', 'Delete non-existing')
-
- # Check that saving works
- js_code = """
- document.getElementById('save_but').click();
- window.domAutomationController.send('done');
- """
- self.ExecuteJavascript(js_code, tab_index)
- _CheckStatus('Save successful', 'Save test')
-
- # Check that we load what we saved
- js_code = """
- document.getElementById('file_editor').value = 'different';
- document.getElementById('load_but').click();
- window.domAutomationController.send('done');
- """
- self.ExecuteJavascript(js_code, tab_index)
- _CheckStatus('Load complete', 'Load test')
- self.assertTrue(
- self.GetDOMValue('document.getElementById("file_editor").value',
- tab_index).find('test') != -1, msg='Loaded wrong text or failed')
-
- # Check that we delete files successfully
- js_code = """
- document.getElementById('delete_but').click();
- window.domAutomationController.send('done');
- """
- self.ExecuteJavascript(js_code, tab_index)
- _CheckStatus('File deleted', 'Delete test')
-
- # Check that file is deleted and load produces not found
- js_code = """
- document.getElementById('load_but').click();
- window.domAutomationController.send('done');
- """
- self.ExecuteJavascript(js_code, tab_index)
- _CheckStatus('File not found', 'Load deleted test')
-
- def _VerifyWebSocketExample(self, tab_index, name, url):
- """Verify Web Socket Open Example.
-
- Args:
- tab_index: Tab index integer that the example is on.
- name: A string name of the example.
- url: A string url of the example.
- """
- # Check if example is loaded.
- success = self.WaitUntil(
- lambda: self.GetDOMValue(
- 'document.getElementById("statusField").innerHTML', tab_index),
- expect_retval='SUCCESS')
- self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
-
- # Simulate clicking on Connect button to establish a connection.
- js_code = """
- document.getElementsByTagName('input')[1].click();
- window.domAutomationController.send('done');
- """
- self.ExecuteJavascript(js_code, tab_index)
-
- # Check if connected
- success = self._VerifyElementPresent('log', 'connected', tab_index,
- msg='Example %s failed. URL: %s' % (name, url))
-
- # Simulate clicking on Send button to send text message in log.
- js_code = """
- document.getElementsByTagName('input')[3].click();
- window.domAutomationController.send('done');
- """
- self.ExecuteJavascript(js_code, tab_index)
- success = self.WaitUntil(
- lambda: bool(re.search('send:', self.GetDOMValue(
- 'document.getElementById("log").textContent', tab_index))))
- self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
-
- def _VerifyDynamicLibraryOpen(self, tab_index, name, url):
- """Verify Dynamic Library Open Example.
-
- Args:
- tab_index: Tab index integer that the example is on.
- name: A string name of the example.
- url: A string url of the example.
- """
- # Check if example is loaded.
- success = self._VerifyElementPresent('log', 'Eightball loaded!',
- tab_index, msg='Example %s failed. URL: %s' % (name, url))
-
- # Simulate clicking on ASK button and check answer log for desired answer.
- js_code = """
- document.getElementsByTagName('input')[1].click();
- window.domAutomationController.send('done');
- """
- self.ExecuteJavascript(js_code, tab_index)
- def _CheckAnswerLog():
- return bool(re.search(r'NO|YES|42|MAYBE NOT|DEFINITELY|'
- 'ASK ME TOMORROW|MAYBE|PARTLY CLOUDY',
- self.GetDOMValue('document.getElementById("log").innerHTML',
- tab_index)))
-
- success = self.WaitUntil(_CheckAnswerLog)
- self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
-
- def _VerifyLoadProgressExample(self, tab_index, name, url):
- """Verify Dynamic Library Open Example.
-
- Args:
- tab_index: Tab index integer that the example is on.
- name: A string name of the example.
- url: A string url of the example.
- """
- # Check if example loads and displays loading progress.
- success = self.WaitUntil(
- lambda: self.GetDOMValue(
- 'document.getElementById("statusField").innerHTML', tab_index),
- timeout=150, expect_retval='SUCCESS')
- self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
-
- def _CheckLoadProgressStatus():
- return re.search(
- r'(loadstart).+(progress:).+(load).+(loadend).+(lastError:)',
- self.GetDOMValue(
- 'document.getElementById("log").innerHTML', tab_index))
- success = self.WaitUntil(_CheckLoadProgressStatus)
- self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
-
- def _VerifyPiGeneratorExample(self, tab_index, name, url):
- """Verify Pi Generator Example.
-
- Args:
- tab_index: Tab index integer that the example is on.
- name: A string name of the example.
- url: A string url of the example.
- """
- success = self.WaitUntil(
- lambda: self.GetDOMValue('document.getElementById("pi").value',
- tab_index)[0:3],
- expect_retval='3.1')
- self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
-
- def _VerifySineSynthExample(self, tab_index, name, url):
- """Verify Sine Wave Synthesizer Example.
-
- Args:
- tab_index: Tab index integer that the example is on.
- name: A string name of the example.
- url: A string url of the example.
- """
- success = self.WaitUntil(
- lambda: self.GetDOMValue(
- 'document.getElementById("frequency_field").value',
- tab_index), timeout=150, expect_retval='440')
- self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
- self.ExecuteJavascript(
- 'document.body.getElementsByTagName("button")[0].click();'
- 'window.domAutomationController.send("done")',
- tab_index)
-
- def _VerifyGetURLExample(self, tab_index, name, url):
- """Verify GetURL Example.
-
- Args:
- tab_index: Tab index integer that the example is on.
- name: A string name of the example.
- url: A string url of the example.
- """
- success = self.WaitUntil(
- lambda: self.GetDOMValue(
- 'document.getElementById("statusField").innerHTML',
- tab_index), timeout=150, expect_retval='SUCCESS')
- self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
- self.ExecuteJavascript(
- 'document.getElementById("button").click();'
- 'window.domAutomationController.send("done")',
- tab_index)
- success = self._VerifyElementPresent('general_output', 'test passed',
- tab_index, msg='Example %s failed. URL: %s' % (name, url))
-
- def _CheckForCrashes(self):
- """Check for any browser/tab crashes and hangs."""
- self.assertTrue(self.GetBrowserWindowCount(),
- msg='Browser crashed, no window is open.')
-
- info = self.GetBrowserInfo()
- breakpad_folder = info['properties']['DIR_CRASH_DUMPS']
- old_dmp_files = glob.glob(os.path.join(breakpad_folder, '*.dmp'))
-
- # Verify there're no crash dump files.
- for dmp_file in glob.glob(os.path.join(breakpad_folder, '*.dmp')):
- self.assertTrue(dmp_file in old_dmp_files,
- msg='Crash dump %s found' % dmp_file)
-
- # Check for any crashed tabs.
- tabs = info['windows'][0]['tabs']
- for tab in tabs:
- if tab['url'] != 'about:blank':
- if not self.GetDOMValue('document.body.innerHTML', tab['index']):
- self.fail(msg='Tab crashed on %s' % tab['url'])
-
- def _GetPlatformArchitecture(self):
- """Get platform architecture.
-
- Returns:
- A string representing the platform architecture.
- """
- if pyauto.PyUITest.IsWin():
- if os.environ['PROGRAMFILES'] == 'C:\\Program Files (x86)':
- return '64bit'
- else:
- return '32bit'
- elif pyauto.PyUITest.IsMac() or pyauto.PyUITest.IsLinux():
- if platform.machine() == 'x86_64':
- return '64bit'
- else:
- return '32bit'
- return '32bit'
-
- def _HasPathInTree(self, pattern, is_file, root=os.curdir):
- """Recursively checks if a file/directory matching a pattern exists.
-
- Args:
- pattern: Pattern of file or directory name.
- is_file: True if looking for file, or False if looking for directory.
- root: Directory to start looking.
-
- Returns:
- True, if root contains the directory name pattern, or
- False otherwise.
- """
- for path, dirs, files in os.walk(os.path.abspath(root)):
- if is_file:
- if len(fnmatch.filter(files, pattern)):
- return True
- else:
- if len(fnmatch.filter(dirs, pattern)):
- return True
- return False
-
- def _HasAllSystemRequirements(self):
- """Verify NaCl SDK installation system requirements.
-
- Returns:
- True, if system passed requirements, or
- False otherwise.
- """
- # Check python version.
- if sys.version_info[0:2] < (2, 6):
- return False
-
- # Check OS requirements.
- if pyauto.PyUITest.IsMac():
- mac_min_version = version.StrictVersion('10.6')
- mac_version = version.StrictVersion(platform.mac_ver()[0])
- if mac_version < mac_min_version:
- return False
- elif pyauto.PyUITest.IsWin():
- if not (self.IsWin7() or self.IsWinVista() or self.IsWinXP()):
- return False
- elif pyauto.PyUITest.IsLinux():
- pass # TODO(chrisphan): Check Lin requirements.
- else:
- return False
-
- # Check for Chrome version compatibility.
- # NaCl supports Chrome 10 and higher builds.
- min_required_chrome_build = self._settings['min_required_chrome_build']
- browser_info = self.GetBrowserInfo()
- chrome_version = browser_info['properties']['ChromeVersion']
- chrome_build = int(chrome_version.split('.')[0])
- return chrome_build >= min_required_chrome_build
-
- def _DownloadNaClSDK(self):
- """Download NaCl SDK."""
- self._temp_dir = tempfile.mkdtemp()
- dl_file = urllib2.urlopen(self._settings['post_sdk_zip'])
- file_path = os.path.join(self._temp_dir, 'nacl_sdk.zip')
-
- try:
- f = open(file_path, 'wb')
- f.write(dl_file.read())
- except IOError:
- self.fail(msg='Cannot open %s.' % file_path)
- finally:
- f.close()
-
- def _ExtractNaClSDK(self):
- """Extract NaCl SDK."""
- source_file = os.path.join(self._temp_dir, 'nacl_sdk.zip')
- if zipfile.is_zipfile(source_file):
- zip = zipfile.ZipFile(source_file, 'r')
- zip.extractall(self._extracted_sdk_path)
- else:
- self.fail(msg='%s is not a valid zip file' % source_file)
-
- def _IsURLAlive(self, url):
- """Test if URL is alive."""
- try:
- urllib2.urlopen(url)
- except:
- return False
- return True
-
- def _CloseHTTPServer(self, proc=None):
- """Close HTTP server.
-
- Args:
- proc: Process that opened the HTTP server.
- proc is None when there is no pointer to HTTP server process.
- """
- if not self._IsURLAlive('http://localhost:5103'):
- return
- response = urllib2.urlopen('http://localhost:5103')
- html = response.read()
- if not 'Native Client' in html:
- self.fail(msg='Port 5103 is in use.')
-
- urllib2.urlopen('http://localhost:5103?quit=1')
- success = self.WaitUntil(
- lambda: self._IsURLAlive('http://localhost:5103'),
- retry_sleep=1, expect_retval=False)
- if not success:
- if not proc:
- self.fail(msg='Failed to close HTTP server.')
- else:
- if proc.poll() == None:
- try:
- proc.kill()
- except:
- self.fail(msg='Failed to close HTTP server.')
-
- def _SearchNaClSDKFile(self, search_list):
- """Search NaCl SDK file for example files and directories in Windows.
-
- Args:
- search_list: A list of strings, representing file and
- directory names for which to search.
- """
- missing_items = []
- for name in search_list:
- is_file = name.find('/') < 0
- if not is_file:
- name = name.replace('/', '')
- if not self._HasPathInTree(name, is_file, self._extracted_sdk_path):
- missing_items.append(name)
- self.assertEqual(len(missing_items), 0,
- msg='Missing files or directories: %s' %
- ', '.join(map(str, missing_items)))
-
- def ExtraChromeFlags(self):
- """Ensures Nacl is enabled.
-
- Returns:
- A list of extra flags to pass to Chrome when it is launched.
- """
- extra_chrome_flags = [
- '--enable-nacl',
- '--enable-nacl-exception-handling',
- '--nacl-gdb',
- ]
- return pyauto.PyUITest.ExtraChromeFlags(self) + extra_chrome_flags
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/netflix.py b/chrome/test/functional/netflix.py
deleted file mode 100755
index 4951b9b..0000000
--- a/chrome/test/functional/netflix.py
+++ /dev/null
@@ -1,256 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import logging
-import os
-import time
-
-import pyauto_functional
-import pyauto
-import test_utils
-
-
-class NetflixTestHelper():
- """Helper functions for Netflix tests.
-
- For sample usage, look at class NetflixTest.
- """
-
- # Netflix player states.
- IS_GUEST_MODE_ERROR = '0'
- IS_PLAYING = '4'
-
- TITLE_HOMEPAGE = 'http://movies.netflix.com/WiHome'
- SIGNOUT_PAGE = 'https://account.netflix.com/Logout'
- # 30 Rock.
- VIDEO_URL = 'https://movies.netflix.com/WiPlayer?movieid=70136124'
- ALT_VIDEO_URL = 'https://movies.netflix.com/WiPlayer?movieid=70133713'
- _pyauto = None
-
- def __init__(self, pyauto):
- self._pyauto = pyauto
-
- def _IsNetflixPluginEnabled(self):
- """Determine Netflix plugin availability and its state."""
- return [x for x in self._pyauto.GetPluginsInfo().Plugins() \
- if x['name'] == 'Netflix' and x['enabled']]
-
- def _LoginToNetflix(self):
- """Login to Netflix."""
- credentials = self._pyauto.GetPrivateInfo()['test_netflix_acct']
- board_name = self._pyauto.ChromeOSBoard()
- assert credentials.get(board_name), \
- 'No netflix credentials for %s.' % board_name
- self._pyauto.NavigateToURL(credentials['login_url'])
- login_js = """
- document.getElementById('email').value='%s';
- document.getElementById('password').value='%s';
- window.domAutomationController.send('ok');
- """ % (credentials[board_name], credentials['password'])
- self._pyauto.assertEqual(self._pyauto.ExecuteJavascript(login_js), 'ok',
- msg='Failed to set login credentials.')
- self._pyauto.assertTrue(self._pyauto.SubmitForm('login-form'),
- msg='Login to Netflix failed. We think this is an authetication '
- 'problem from the Netflix side. Sometimes we also see this while '
- 'login in manually.')
-
- def _GetVideoDroppedFrames(self, tab_index=0, windex=0):
- """Returns total Netflix video dropped frames."""
- js = """
- var frames = nrdp.video.droppedFrames;
- window.domAutomationController.send(frames + '');
- """
- return int(self._pyauto.ExecuteJavascript(js, tab_index=tab_index,
- windex=windex))
-
- def _GetVideoFrames(self, tab_index=0, windex=0):
- """Returns Netflix video total frames."""
- js = """
- var frames = nrdp.video.totalFrames;
- window.domAutomationController.send(frames + '');
- """
- return int(self._pyauto.ExecuteJavascript(js, tab_index=tab_index,
- windex=windex))
-
- def _HandleInfobars(self, err_msg):
- """Manage infobars that come up during the test."""
- def _HandleNetflixInfobar():
- tab_info = self._pyauto.GetBrowserInfo()['windows'][0]['tabs'][0]
- infobars = tab_info['infobars']
- index = 0
- for infobar in infobars:
- if 'netflix' in infobar['text']:
- # After storage infobar pops up, clicking the Ok button immediately
- # returns the Storage error on faster machines like Stumpy/Lumpy so
- # adding a delay of 1 second here.
- time.sleep(1)
- self._pyauto.PerformActionOnInfobar('accept', infobar_index=index)
- return True
- index = index + 1
- return False
- self._pyauto.assertTrue(self._pyauto.WaitUntil(_HandleNetflixInfobar),
- msg=err_msg)
-
- def CurrentPlaybackTime(self):
- """Returns the current playback time in seconds."""
- time = self._pyauto.ExecuteJavascript("""
- time = nrdp.video.currentTime;
- window.domAutomationController.send(time + '');
- """)
- return int(float(time))
-
- def SignOut(self):
- """Sign out from Netflix Login."""
- self._pyauto.NavigateToURL(self.SIGNOUT_PAGE)
-
- def LoginAndStartPlaying(self):
- """Login and start playing the video."""
- self._pyauto.assertTrue(self._pyauto._IsNetflixPluginEnabled(),
- msg='Netflix plugin is disabled or not available.')
- self._pyauto._LoginToNetflix()
- self._pyauto.assertTrue(self._pyauto.WaitUntil(
- lambda: self._pyauto.GetActiveTabURL().spec(),
- expect_retval=self.TITLE_HOMEPAGE),
- msg='Login to Netflix failed.')
- self._pyauto.NavigateToURL(self.VIDEO_URL)
- self._pyauto._HandleInfobars(err_msg='Netflix infobar did not show up')
-
- def CheckNetflixPlaying(self, expected_result, error_msg):
- """Check if Netflix is playing the video or not.
-
- Args:
- expected_result: expected return value from Netflix player.
- error_msg: If expected value isn't matching, error message to throw.
- """
- self._pyauto.assertTrue(self._pyauto.WaitUntil(
- lambda: self._pyauto.ExecuteJavascript("""
- if (typeof nrdp == 'undefined') {
- window.domAutomationController.send('not ready');
- }
- player_status = nrdp.video.readyState;
- window.domAutomationController.send(player_status + '');
- """), expect_retval=expected_result),
- msg=error_msg)
-
-
-class NetflixTest(pyauto.PyUITest, NetflixTestHelper):
- """Test case for Netflix player."""
-
- def __init__(self, methodName='runTest', **kwargs):
- pyauto.PyUITest.__init__(self, methodName, **kwargs)
- NetflixTestHelper.__init__(self, self)
-
- def ShouldAutoLogin(self):
- return False
-
- def _Login(self):
- """Perform login"""
- credentials = self.GetPrivateInfo()['test_google_account']
- self.Login(credentials['username'], credentials['password'])
- logging.info('Logged in as %s' % credentials['username'])
- login_info = self.GetLoginInfo()
- self.assertTrue(login_info['is_logged_in'], msg='Login failed.')
- self.assertFalse(login_info['is_guest'],
- msg='Should not be logged in as guest.')
-
- def setUp(self):
- assert os.geteuid() == 0, 'Run test as root since we might need to logout'
- pyauto.PyUITest.setUp(self)
- if self.GetLoginInfo()['is_logged_in']:
- self.Logout()
- self._Login()
-
- def tearDown(self):
- self.SignOut()
- pyauto.PyUITest.tearDown(self)
-
- def testPlayerLoadsAndPlays(self):
- """Test that Netflix player loads and plays the title."""
- self.LoginAndStartPlaying()
- self._HandleInfobars(err_msg='Netflix plugin access infobar did not show up')
- self.CheckNetflixPlaying(self.IS_PLAYING,
- 'Player did not start playing the title.')
-
- def testMultiplePlayback(self):
- """Test that playing two titles, Netflix returns multiple play error."""
- self.LoginAndStartPlaying()
- self._HandleInfobars(err_msg='Netflix plugin access infobar did not show up')
- self.CheckNetflixPlaying(self.IS_PLAYING,
- 'Player did not start playing the title.')
- self.AppendTab(self.ALT_VIDEO_URL)
- self.assertTrue('Multiple Play Error' in self.GetTabContents(),
- msg='Multiple Play Error is not found on the page.')
-
- def testPlaying(self):
- """Test that title playing progresses."""
- self.LoginAndStartPlaying()
- self._HandleInfobars(err_msg='Netflix plugin access infobar did not show up')
- self.CheckNetflixPlaying(self.IS_PLAYING,
- 'Player did not start playing the title.')
- title_length = self.ExecuteJavascript("""
- time = nrdp.video.duration;
- window.domAutomationController.send(time + '');
- """)
- title_length = int(float(title_length))
- prev_time = 0
- current_time = 0
- count = 0
- while current_time < title_length:
- # We want to test playing only for ten seconds.
- count = count + 1
- if count == 10:
- break
- current_time = self.CurrentPlaybackTime()
- self.assertTrue(prev_time <= current_time,
- msg='Prev playing time %s is greater than current time %s.'
- % (prev_time, current_time))
- prev_time = current_time
- # play video for some time
- time.sleep(1)
- # In case player doesn't start playing at all, above while loop may
- # still pass. So re-verifying and assuming that player did play something
- # during last 10 seconds.
- self.assertTrue(current_time > 0,
- msg='Netflix player did not start playing.')
-
-
-class NetflixGuestModeTest(pyauto.PyUITest, NetflixTestHelper):
- """Netflix in guest mode."""
-
- def __init__(self, methodName='runTest', **kwargs):
- pyauto.PyUITest.__init__(self, methodName, **kwargs)
- NetflixTestHelper.__init__(self, self)
-
- def setUp(self):
- assert os.geteuid() == 0, 'Run test as root since we might need to logout'
- pyauto.PyUITest.setUp(self)
- if self.GetLoginInfo()['is_logged_in']:
- self.Logout()
- self.LoginAsGuest()
- login_info = self.GetLoginInfo()
- self.assertTrue(login_info['is_logged_in'], msg='Not logged in at all.')
- self.assertTrue(login_info['is_guest'], msg='Not logged in as guest.')
-
- def ShouldAutoLogin(self):
- return False
-
- def tearDown(self):
- self.AppendTab(self.SIGNOUT_PAGE)
- self.Logout()
- pyauto.PyUITest.tearDown(self)
-
- def testGuestMode(self):
- """Test that Netflix doesn't play in guest mode login."""
- self.LoginAndStartPlaying()
- self.CheckNetflixPlaying(
- self.IS_GUEST_MODE_ERROR,
- 'Netflix player did not return a Guest mode error.')
- # crosbug.com/p/14009
- self.assertTrue('Netflix Video Player Unavailable' in self.GetTabContents(),
- msg='Guest Mode error is not found on the page.')
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/ntp.py b/chrome/test/functional/ntp.py
deleted file mode 100755
index f176943..0000000
--- a/chrome/test/functional/ntp.py
+++ /dev/null
@@ -1,473 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import copy
-import os
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-import test_utils
-
-
-class NTPTest(pyauto.PyUITest):
- """Test of the NTP."""
-
- # Default apps are registered in ProfileImpl::RegisterComponentExtensions().
- _EXPECTED_DEFAULT_APPS = [
- {u'title': u'Chrome Web Store'},
- ]
- if pyauto.PyUITest.IsChromeOS():
- _EXPECTED_DEFAULT_APPS.append({u'title': u'Files'})
- _EXPECTED_DEFAULT_APPS.append({u'title': u'Chrome'})
- else:
- _EXPECTED_DEFAULT_APPS.append({u'title': u'Cloud Print'})
-
- # Default menu and thumbnail mode preferences are set in
- # ShownSectionsHandler::RegisterUserPrefs.
- if pyauto.PyUITest.IsChromeOS():
- _EXPECTED_DEFAULT_THUMB_INFO = {
- u'apps': True,
- u'most_visited': False
- }
- _EXPECTED_DEFAULT_MENU_INFO = {
- u'apps': False,
- u'most_visited': True,
- u'recently_closed': True
- }
- else:
- _EXPECTED_DEFAULT_THUMB_INFO = {
- u'apps': False,
- u'most_visited': True
- }
- _EXPECTED_DEFAULT_MENU_INFO = {
- u'apps': False,
- u'most_visited': False,
- u'recently_closed': False
- }
-
- def Debug(self):
- """Test method for experimentation.
-
- This method is not run automatically.
- """
- while True:
- raw_input('Interact with the browser and hit <enter> to dump NTP info...')
- print '*' * 20
- self.pprint(self._GetNTPInfo())
-
- def __init__(self, methodName='runTest'):
- super(NTPTest, self).__init__(methodName)
-
- # Create some dummy file urls we can use in the tests.
- filenames = ['title1.html', 'title2.html']
- titles = [u'', u'Title Of Awesomeness']
- urls = map(lambda name: self.GetFileURLForDataPath(name), filenames)
- self.PAGES = map(lambda url, title: {'url': url, 'title': title},
- urls, titles)
-
- def _NTPContainsThumbnail(self, check_thumbnail):
- """Returns whether the NTP's Most Visited section contains the given
- thumbnail."""
- for thumbnail in self.GetNTPThumbnails():
- if check_thumbnail['url'] == thumbnail['url']:
- return True
- return False
-
- def testFreshProfile(self):
- """Tests that the NTP with a fresh profile is correct"""
- thumbnails = self.GetNTPThumbnails()
- default_sites = self.GetNTPDefaultSites()
- self.assertEqual(len(default_sites), len(thumbnails))
- for thumbnail, default_site in zip(thumbnails, default_sites):
- self.assertEqual(thumbnail['url'], default_site)
- self.assertEqual(0, len(self.GetNTPRecentlyClosed()))
-
- def testRemoveDefaultThumbnails(self):
- """Tests that the default thumbnails can be removed"""
- self.RemoveNTPDefaultThumbnails()
- self.assertFalse(self.GetNTPThumbnails())
- self.RestoreAllNTPThumbnails()
- self.assertEqual(len(self.GetNTPDefaultSites()),
- len(self.GetNTPThumbnails()))
- self.RemoveNTPDefaultThumbnails()
- self.assertFalse(self.GetNTPThumbnails())
-
- def testOneMostVisitedSite(self):
- """Tests that a site is added to the most visited sites"""
- self.RemoveNTPDefaultThumbnails()
- self.NavigateToURL(self.PAGES[1]['url'])
- thumbnail = self.GetNTPThumbnails()[0]
- self.assertEqual(self.PAGES[1]['url'], thumbnail['url'])
- self.assertEqual(self.PAGES[1]['title'], thumbnail['title'])
-
- def testRemoveThumbnail(self):
- """Tests removing a thumbnail works"""
- self.RemoveNTPDefaultThumbnails()
- for page in self.PAGES:
- self.AppendTab(pyauto.GURL(page['url']))
-
- thumbnails = self.GetNTPThumbnails()
- for thumbnail in thumbnails:
- self.assertEquals(thumbnail, self.GetNTPThumbnails()[0])
- self.RemoveNTPThumbnail(thumbnail)
- self.assertFalse(self._NTPContainsThumbnail(thumbnail))
- self.assertFalse(self.GetNTPThumbnails())
-
- def testIncognitoNotAppearInMostVisited(self):
- """Tests that visiting a page in incognito mode does cause it to appear in
- the Most Visited section"""
- self.RemoveNTPDefaultThumbnails()
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
- self.NavigateToURL(self.PAGES[0]['url'], 1, 0)
- self.assertFalse(self.GetNTPThumbnails())
-
- def testDifferentProfileNotAppearInMostVisited(self):
- """Tests that visiting a page in one profile does not cause it to appear in
- the Most Visited section of another."""
- self.RemoveNTPDefaultThumbnails()
- self.OpenNewBrowserWindowWithNewProfile()
- self.NavigateToURL(self.PAGES[0]['url'], 1, 0)
- self.assertFalse(self.GetNTPThumbnails())
-
- def testThumbnailPersistence(self):
- """Tests that thumbnails persist across Chrome restarts"""
- self.RemoveNTPDefaultThumbnails()
- for page in self.PAGES:
- self.AppendTab(pyauto.GURL(page['url']))
- thumbnails = self.GetNTPThumbnails()
- self.RestartBrowser(clear_profile=False)
- self.assertEqual(thumbnails, self.GetNTPThumbnails())
-
- def testRestoreAllRemovedThumbnails(self):
- """Tests restoring all removed thumbnails"""
- for page in self.PAGES:
- self.AppendTab(pyauto.GURL(page['url']))
-
- thumbnails = self.GetNTPThumbnails()
- for thumbnail in thumbnails:
- self.RemoveNTPThumbnail(thumbnail)
-
- self.RestoreAllNTPThumbnails()
- self.assertEquals(thumbnails, self.GetNTPThumbnails())
-
- def testThumbnailRanking(self):
- """Tests that the thumbnails are ordered according to visit count"""
- self.RemoveNTPDefaultThumbnails()
- for page in self.PAGES:
- self.AppendTab(pyauto.GURL(page['url']))
- thumbnails = self.GetNTPThumbnails()
- self.assertEqual(self.PAGES[0]['url'], self.GetNTPThumbnails()[0]['url'])
- self.AppendTab(pyauto.GURL(self.PAGES[1]['url']))
- self.assertEqual(self.PAGES[1]['url'], self.GetNTPThumbnails()[0]['url'])
- self.AppendTab(pyauto.GURL(self.PAGES[0]['url']))
- self.AppendTab(pyauto.GURL(self.PAGES[0]['url']))
- self.assertEqual(self.PAGES[0]['url'], self.GetNTPThumbnails()[0]['url'])
-
- def testThumbnailTitleChangeAfterPageTitleChange(self):
- """Tests that once a page title changes, the thumbnail title changes too"""
- self.RemoveNTPDefaultThumbnails()
- self.NavigateToURL(self.PAGES[0]['url'])
- self.assertEqual(self.PAGES[0]['title'],
- self.GetNTPThumbnails()[0]['title'])
- self.ExecuteJavascript('window.domAutomationController.send(' +
- 'document.title = "new title")')
- self.assertEqual('new title', self.GetNTPThumbnails()[0]['title'])
-
- def testCloseOneTab(self):
- """Tests that closing a tab populates the recently closed list"""
- self.RemoveNTPDefaultThumbnails()
- self.AppendTab(pyauto.GURL(self.PAGES[1]['url']))
- self.CloseTab(tab_index=1)
- self.assertEqual(self.PAGES[1]['url'],
- self.GetNTPRecentlyClosed()[0]['url'])
- self.assertEqual(self.PAGES[1]['title'],
- self.GetNTPRecentlyClosed()[0]['title'])
-
- def testCloseOneWindow(self):
- """Tests that closing a window populates the recently closed list"""
- self.RemoveNTPDefaultThumbnails()
- self.OpenNewBrowserWindow(True)
- self.NavigateToURL(self.PAGES[0]['url'], 1, 0)
- self.AppendTab(pyauto.GURL(self.PAGES[1]['url']), 1)
- self.CloseBrowserWindow(1)
- expected = [{ u'type': u'window',
- u'tabs': [
- { u'type': u'tab',
- u'url': self.PAGES[0]['url'],
- u'direction': u'ltr' },
- { u'type': u'tab',
- u'url': self.PAGES[1]['url']}]
- }]
- self.assertEquals(expected, test_utils.StripUnmatchedKeys(
- self.GetNTPRecentlyClosed(), expected))
-
- def testCloseMultipleTabs(self):
- """Tests closing multiple tabs populates the Recently Closed section in
- order"""
- self.RemoveNTPDefaultThumbnails()
- self.AppendTab(pyauto.GURL(self.PAGES[0]['url']))
- self.AppendTab(pyauto.GURL(self.PAGES[1]['url']))
- self.CloseTab(tab_index=2)
- self.CloseTab(tab_index=1)
- expected = [{ u'type': u'tab',
- u'url': self.PAGES[0]['url']
- },
- { u'type': u'tab',
- u'url': self.PAGES[1]['url']
- }]
- self.assertEquals(expected, test_utils.StripUnmatchedKeys(
- self.GetNTPRecentlyClosed(), expected))
-
- def testCloseWindowWithOneTab(self):
- """Tests that closing a window with only one tab only shows up as a tab in
- the Recently Closed section"""
- self.RemoveNTPDefaultThumbnails()
- self.OpenNewBrowserWindow(True)
- self.NavigateToURL(self.PAGES[0]['url'], 1, 0)
- self.CloseBrowserWindow(1)
- expected = [{ u'type': u'tab',
- u'url': self.PAGES[0]['url']
- }]
- self.assertEquals(expected, test_utils.StripUnmatchedKeys(
- self.GetNTPRecentlyClosed(), expected))
-
- def testCloseMultipleWindows(self):
- """Tests closing multiple windows populates the Recently Closed list"""
- self.RemoveNTPDefaultThumbnails()
- self.OpenNewBrowserWindow(True)
- self.NavigateToURL(self.PAGES[0]['url'], 1, 0)
- self.AppendTab(pyauto.GURL(self.PAGES[1]['url']), 1)
- self.OpenNewBrowserWindow(True)
- self.NavigateToURL(self.PAGES[1]['url'], 2, 0)
- self.AppendTab(pyauto.GURL(self.PAGES[0]['url']), 2)
- self.CloseBrowserWindow(2)
- self.CloseBrowserWindow(1)
- expected = [{ u'type': u'window',
- u'tabs': [
- { u'type': u'tab',
- u'url': self.PAGES[0]['url'],
- u'direction': u'ltr' },
- { u'type': u'tab',
- u'url': self.PAGES[1]['url']}]
- },
- { u'type': u'window',
- u'tabs': [
- { u'type': u'tab',
- u'url': self.PAGES[1]['url'],
- u'direction': u'ltr' },
- { u'type': u'tab',
- u'url': self.PAGES[0]['url']}]
- }]
- self.assertEquals(expected, test_utils.StripUnmatchedKeys(
- self.GetNTPRecentlyClosed(), expected))
-
- def testRecentlyClosedIncognito(self):
- """Tests that we don't record closure of Incognito tabs or windows"""
- #self.RemoveNTPDefaultThumbnails()
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
- self.NavigateToURL(self.PAGES[0]['url'], 1, 0)
- self.AppendTab(pyauto.GURL(self.PAGES[0]['url']), 1)
- self.AppendTab(pyauto.GURL(self.PAGES[1]['url']), 1)
- self.CloseTab(windex=1)
- self.assertFalse(self.GetNTPRecentlyClosed())
- self.CloseBrowserWindow(1)
- self.assertFalse(self.GetNTPRecentlyClosed())
-
- def _VerifyAppInfo(self, actual_info, expected_info):
- """Ensures that the actual app info contains the expected app info.
-
- This method assumes that both the actual and expected information for each
- app contains at least the 'title' attribute. Both sets of info are
- considered to match if the actual info contains at least the specified
- expected info (if the actual info contains additional values that are not
- specified in the expected info, that's ok). This function will fail the
- current test if both sets of info don't match.
-
- Args:
- actual_info: A list of dictionaries representing the information from
- all apps that would currently be displayed on the NTP.
- expected_info: A corrresponding list of dictionaries representing the
- information that is expected.
- """
- # Ensure all app info dictionaries contain at least the 'title' attribute.
- self.assertTrue(all(map(lambda app: 'title' in app, actual_info)) and
- all(map(lambda app: 'title' in app, expected_info)),
- msg='At least one app is missing the "title" attribute.')
-
- # Sort both app lists by title to ensure they're in a known order.
- actual_info = sorted(actual_info, key=lambda app: app['title'])
- expected_info = sorted(expected_info, key=lambda app: app['title'])
-
- # Ensure the expected info matches the actual info.
- self.assertTrue(len(actual_info) == len(expected_info),
- msg='Expected %d app(s) on NTP, but got %d instead.' % (
- len(expected_info), len(actual_info)))
- for i, expected_app in enumerate(expected_info):
- for attribute in expected_app:
- self.assertTrue(attribute in actual_info[i],
- msg='Expected attribute "%s" not found in app info.' % (
- attribute))
- self.assertTrue(expected_app[attribute] == actual_info[i][attribute],
- msg='For attribute "%s", expected value "%s", but got '
- '"%s".' % (attribute, expected_app[attribute],
- actual_info[i][attribute]))
-
- def _InstallAndVerifySamplePackagedApp(self):
- """Installs a sample packaged app and verifies the install is successful.
-
- Returns:
- The string ID of the installed app.
- """
- app_crx_file = os.path.abspath(os.path.join(
- self.DataDir(), 'pyauto_private', 'apps', 'countdown.crx'))
- return self.InstallExtension(app_crx_file)
-
- def testGetAppsInNewProfile(self):
- """Ensures that the only app in a new profile is the Web Store app."""
- app_info = self.GetNTPApps()
- self._VerifyAppInfo(app_info, self._EXPECTED_DEFAULT_APPS)
-
- def testGetAppsWhenInstallApp(self):
- """Ensures that an installed app is reflected in the app info in the NTP."""
- self._InstallAndVerifySamplePackagedApp()
- app_info = self.GetNTPApps()
- expected_app_info = [
- {
- u'title': u'Countdown'
- }
- ]
- expected_app_info.extend(self._EXPECTED_DEFAULT_APPS)
- self._VerifyAppInfo(app_info, expected_app_info)
-
- def testGetAppsWhenInstallNonApps(self):
- """Ensures installed non-apps are not reflected in the NTP app info."""
- # Install a regular extension and a theme.
- ext_crx_file = os.path.abspath(os.path.join(self.DataDir(), 'extensions',
- 'page_action.crx'))
- self.InstallExtension(ext_crx_file)
- theme_crx_file = os.path.abspath(os.path.join(self.DataDir(), 'extensions',
- 'theme.crx'))
- self.SetTheme(theme_crx_file)
- # Verify that no apps are listed on the NTP except for the Web Store.
- app_info = self.GetNTPApps()
- self._VerifyAppInfo(app_info, self._EXPECTED_DEFAULT_APPS)
-
- def testUninstallApp(self):
- """Ensures that an uninstalled app is reflected in the NTP app info."""
- # First, install an app and verify that it exists in the NTP app info.
- installed_app_id = self._InstallAndVerifySamplePackagedApp()
- app_info = self.GetNTPApps()
- expected_app_info = [
- {
- u'title': u'Countdown'
- }
- ]
- expected_app_info.extend(self._EXPECTED_DEFAULT_APPS)
- self._VerifyAppInfo(app_info, expected_app_info)
-
- # Next, uninstall the app and verify that it is removed from the NTP.
- self.assertTrue(self.UninstallExtensionById(installed_app_id),
- msg='Call to UninstallExtensionById() returned False.')
- app_info = self.GetNTPApps()
- self._VerifyAppInfo(app_info, self._EXPECTED_DEFAULT_APPS)
-
- def testCannotUninstallWebStore(self):
- """Ensures that the WebStore app cannot be uninstalled."""
- # Verify that the WebStore app is already installed in a fresh profile.
- app_info = self.GetNTPApps()
- self._VerifyAppInfo(app_info, self._EXPECTED_DEFAULT_APPS)
- self.assertTrue(app_info and 'id' in app_info[0],
- msg='Cannot identify ID of WebStore app.')
- webstore_id = app_info[0]['id']
-
- # Attempt to uninstall the WebStore app and verify that it still exists
- # in the App info of the NTP even after we try to uninstall it.
- self.assertFalse(self.UninstallExtensionById(webstore_id),
- msg='Call to UninstallExtensionById() returned True.')
- self._VerifyAppInfo(self.GetNTPApps(), self._EXPECTED_DEFAULT_APPS)
-
- def testLaunchAppWithDefaultSettings(self):
- """Verifies that an app can be launched with the default settings."""
- # Install an app.
- installed_app_id = self._InstallAndVerifySamplePackagedApp()
-
- # Launch the app from the NTP.
- self.LaunchApp(installed_app_id)
-
- # Verify that the second tab in the first window is the app launch URL.
- # It should be the second tab, not the first, since the call to LaunchApp
- # should have first opened the NTP in a new tab, and then launched the app
- # from there.
- info = self.GetBrowserInfo()
- actual_tab_url = info['windows'][0]['tabs'][1]['url']
- expected_app_url_start = 'chrome-extension://' + installed_app_id
- self.assertTrue(actual_tab_url.startswith(expected_app_url_start),
- msg='The app was not launched.')
-
- def testLaunchAppRegularTab(self):
- """Verifies that an app can be launched in a regular tab."""
- installed_app_id = self._InstallAndVerifySamplePackagedApp()
-
- self.SetAppLaunchType(installed_app_id, 'regular', windex=0)
- self.LaunchApp(installed_app_id)
-
- # Verify that the second tab in the first window is the app launch URL.
- info = self.GetBrowserInfo()
- actual_tab_url = info['windows'][0]['tabs'][1]['url']
- expected_app_url_start = 'chrome-extension://' + installed_app_id
- self.assertTrue(actual_tab_url.startswith(expected_app_url_start),
- msg='The app was not launched in a regular tab.')
-
- def testLaunchAppPinnedTab(self):
- """Verifies that an app can be launched in a pinned tab."""
- installed_app_id = self._InstallAndVerifySamplePackagedApp()
-
- self.SetAppLaunchType(installed_app_id, 'pinned', windex=0)
- self.LaunchApp(installed_app_id)
-
- # Verify that the first tab in the first window is the app launch URL, and
- # that it is a pinned tab.
- info = self.GetBrowserInfo()
- actual_tab_url = info['windows'][0]['tabs'][0]['url']
- expected_app_url_start = 'chrome-extension://' + installed_app_id
- self.assertTrue(actual_tab_url.startswith(expected_app_url_start) and
- info['windows'][0]['tabs'][0]['pinned'],
- msg='The app was not launched in a pinned tab.')
-
- def testLaunchAppFullScreen(self):
- """Verifies that an app can be launched in fullscreen mode."""
- installed_app_id = self._InstallAndVerifySamplePackagedApp()
-
- self.SetAppLaunchType(installed_app_id, 'fullscreen', windex=0)
- self.LaunchApp(installed_app_id)
-
- # Verify that the second tab in the first window is the app launch URL, and
- # that the window is fullscreen.
- info = self.GetBrowserInfo()
- actual_tab_url = info['windows'][0]['tabs'][1]['url']
- expected_app_url_start = 'chrome-extension://' + installed_app_id
- self.assertTrue(actual_tab_url.startswith(expected_app_url_start) and
- info['windows'][0]['fullscreen'],
- msg='The app was not launched in fullscreen mode.')
-
- def testLaunchAppNewWindow(self):
- """Verifies that an app can be launched in a new window."""
- installed_app_id = self._InstallAndVerifySamplePackagedApp()
-
- self.SetAppLaunchType(installed_app_id, 'window', windex=0)
- self.LaunchApp(installed_app_id)
-
- # Verify that a second window exists (at index 1), and that its first tab
- # is the app launch URL.
- info = self.GetBrowserInfo()
- self.assertTrue(len(info['windows']) == 2,
- msg='A second window does not exist.')
- actual_tab_url = info['windows'][1]['tabs'][0]['url']
- expected_app_url_start = 'chrome-extension://' + installed_app_id
- self.assertTrue(actual_tab_url.startswith(expected_app_url_start),
- msg='The app was not launched in the new window.')
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/omnibox.py b/chrome/test/functional/omnibox.py
deleted file mode 100755
index 75f6aac..0000000
--- a/chrome/test/functional/omnibox.py
+++ /dev/null
@@ -1,369 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import glob
-import os
-import re
-import shutil
-import tempfile
-import urlparse
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-import test_utils
-
-
-class OmniboxTest(pyauto.PyUITest):
- """Test cases for the omnibox."""
-
- def Debug(self):
- """Test method for experimentation.
-
- This method will not run automatically.
- """
- import time
- while True:
- self.pprint(self.GetOmniboxInfo().omniboxdict)
- time.sleep(1)
-
- def testFocusOnStartup(self):
- """Verify that the omnibox has focus on startup."""
- self.WaitUntilOmniboxReadyHack()
- self.assertTrue(self.GetOmniboxInfo().Properties('has_focus'))
-
- def testHistoryResult(self):
- """Verify that the omnibox can fetch items from the history."""
- url = self.GetFileURLForDataPath('title2.html')
- title = 'Title Of Awesomeness'
- self.AppendTab(pyauto.GURL(url))
- def _VerifyHistoryResult(query_list, description, windex=0):
- """Verify result matching given description for given list of queries."""
- for query_text in query_list:
- matches = test_utils.GetOmniboxMatchesFor(
- self, query_text, windex=windex,
- attr_dict={'description': description})
- self.assertTrue(matches)
- self.assertEqual(1, len(matches))
- item = matches[0]
- self.assertEqual(url, item['destination_url'])
- # Query using URL & title.
- _VerifyHistoryResult([url, title], title)
- # Verify results in another tab.
- self.AppendTab(pyauto.GURL())
- _VerifyHistoryResult([url, title], title)
- # Verify results in another window.
- self.OpenNewBrowserWindow(True)
- self.WaitUntilOmniboxReadyHack(windex=1)
- _VerifyHistoryResult([url, title], title, windex=1)
- # Verify results in an incognito window.
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
- self.WaitUntilOmniboxReadyHack(windex=2)
- _VerifyHistoryResult([url, title], title, windex=2)
-
- def _VerifyOmniboxURLMatches(self, url, description, windex=0):
- """Verify URL match results from the omnibox.
-
- Args:
- url: The URL to use.
- description: The string description within the history page and Google
- search to match against.
- windex: The window index to work on. Defaults to 0 (first window).
- """
- matches_description = test_utils.GetOmniboxMatchesFor(
- self, url, windex=windex, attr_dict={'description': description})
- self.assertEqual(1, len(matches_description))
- if description == 'Google Search':
- self.assertTrue(re.match('http://www.google.com/search.+',
- matches_description[0]['destination_url']))
- else:
- self.assertEqual(url, matches_description[0]['destination_url'])
-
- def testFetchHistoryResultItems(self):
- """Verify omnibox fetches history items in 2nd tab, window and incognito."""
- url = self.GetFileURLForDataPath('title2.html')
- title = 'Title Of Awesomeness'
- desc = 'Google Search'
- # Fetch history page item in the second tab.
- self.AppendTab(pyauto.GURL(url))
- self._VerifyOmniboxURLMatches(url, title)
- # Fetch history page items in the second window.
- self.OpenNewBrowserWindow(True)
- self.NavigateToURL(url, 1, 0)
- self._VerifyOmniboxURLMatches(url, title, windex=1)
- # Fetch google search items in incognito window.
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
- self.NavigateToURL(url, 2, 0)
- self._VerifyOmniboxURLMatches(url, desc, windex=2)
-
- def testSelect(self):
- """Verify omnibox popup selection."""
- url1 = self.GetFileURLForDataPath('title2.html')
- url2 = self.GetFileURLForDataPath('title1.html')
- title1 = 'Title Of Awesomeness'
- self.NavigateToURL(url1)
- self.NavigateToURL(url2)
- matches = test_utils.GetOmniboxMatchesFor(self, 'file://')
- self.assertTrue(matches)
- # Find the index of match for |url1|.
- index = None
- for i, match in enumerate(matches):
- if match['description'] == title1:
- index = i
- self.assertTrue(index is not None)
- self.OmniboxMovePopupSelection(index) # Select |url1| line in popup.
- self.assertEqual(url1, self.GetOmniboxInfo().Text())
- self.OmniboxAcceptInput()
- self.assertEqual(title1, self.GetActiveTabTitle())
-
- def testInlineAutoComplete(self):
- """Verify inline autocomplete for a pre-visited URL."""
- self.NavigateToURL('http://www.google.com')
- matches = test_utils.GetOmniboxMatchesFor(self, 'goog')
- self.assertTrue(matches)
- # Omnibox should suggest auto completed URL as the first item.
- matches_description = matches[0]
- self.assertTrue('www.google.com' in matches_description['contents'])
- self.assertEqual('history-url', matches_description['type'])
- # The URL should be inline-autocompleted in the omnibox.
- self.assertTrue('google.com' in self.GetOmniboxInfo().Text())
-
- def testCrazyFilenames(self):
- """Test omnibox query with filenames containing special chars.
-
- The files are created on the fly and cleaned after use.
- """
- filename = os.path.join(self.DataDir(), 'downloads', 'crazy_filenames.txt')
- zip_names = self.EvalDataFrom(filename)
- # We got .zip filenames. Change them to .html.
- crazy_filenames = [x.replace('.zip', '.html') for x in zip_names]
- title = 'given title'
-
- def _CreateFile(name):
- """Create the given html file."""
- fp = open(name, 'w') # |name| could be unicode.
- print >>fp, '<html><title>%s</title><body>' % title
- print >>fp, 'This is a junk file named <h2>%s</h2>' % repr(name)
- print >>fp, '</body></html>'
- fp.close()
-
- crazy_fileurls = []
- # Temp dir for hosting crazy filenames.
- temp_dir = tempfile.mkdtemp(prefix='omnibox')
- # Windows has a dual nature dealing with unicode filenames.
- # While the files are internally saved as unicode, there's a non-unicode
- # aware API that returns a locale-dependent coding on the true unicode
- # filenames. This messes up things.
- # Filesystem-interfacing functions like os.listdir() need to
- # be given unicode strings to "do the right thing" on win.
- # Ref: http://boodebr.org/main/python/all-about-python-and-unicode
- try:
- for filename in crazy_filenames: # |filename| is unicode.
- file_path = os.path.join(temp_dir, filename.encode('utf-8'))
- _CreateFile(os.path.join(temp_dir, filename))
- file_url = self.GetFileURLForPath(file_path)
- crazy_fileurls.append(file_url)
- self.NavigateToURL(file_url)
-
- # Verify omnibox queries.
- for file_url in crazy_fileurls:
- matches = test_utils.GetOmniboxMatchesFor(self,
- file_url, attr_dict={'type': 'url-what-you-typed',
- 'description': title})
- self.assertTrue(matches)
- self.assertEqual(1, len(matches))
- self.assertTrue(os.path.basename(file_url) in
- matches[0]['destination_url'])
- finally:
- shutil.rmtree(unicode(temp_dir)) # Unicode so that Win treats nicely.
-
- def testSuggest(self):
- """Verify suggested results in omnibox."""
- matches = test_utils.GetOmniboxMatchesFor(self, 'apple')
- self.assertTrue(matches)
- self.assertTrue([x for x in matches if x['type'] == 'search-suggest'])
-
- def testDifferentTypesOfResults(self):
- """Verify different types of results from omnibox.
-
- This includes history result, bookmark result, suggest results.
- """
- url = 'http://www.google.com/'
- title = 'Google'
- search_string = 'google'
- self.AddBookmarkURL( # Add a bookmark.
- self.GetBookmarkModel().BookmarkBar()['id'], 0, title, url)
- self.NavigateToURL(url) # Build up history.
- matches = test_utils.GetOmniboxMatchesFor(self, search_string)
- self.assertTrue(matches)
- # Verify starred result (indicating bookmarked url).
- self.assertTrue([x for x in matches if x['starred'] == True])
- for item_type in ('history-url', 'search-what-you-typed',
- 'search-suggest',):
- self.assertTrue([x for x in matches if x['type'] == item_type])
-
- def testSuggestPref(self):
- """Verify no suggests for omnibox when suggested-services disabled."""
- search_string = 'apple'
- self.assertTrue(self.GetPrefsInfo().Prefs(pyauto.kSearchSuggestEnabled))
- matches = test_utils.GetOmniboxMatchesFor(self, search_string)
- self.assertTrue(matches)
- self.assertTrue([x for x in matches if x['type'] == 'search-suggest'])
- # Disable suggest-service.
- self.SetPrefs(pyauto.kSearchSuggestEnabled, False)
- self.assertFalse(self.GetPrefsInfo().Prefs(pyauto.kSearchSuggestEnabled))
- matches = test_utils.GetOmniboxMatchesFor(self, search_string)
- self.assertTrue(matches)
- # Verify there are no suggest results.
- self.assertFalse([x for x in matches if x['type'] == 'search-suggest'])
-
- def testAutoCompleteForSearch(self):
- """Verify omnibox autocomplete for search."""
- search_string = 'youtu'
- verify_string = 'youtube'
- matches = test_utils.GetOmniboxMatchesFor(self, search_string)
- # Retrieve last contents element.
- matches_description = matches[-1]['contents'].split()
- self.assertEqual(verify_string, matches_description[0])
-
- def _GotContentHistory(self, search_text, url):
- """Check if omnibox returns a previously-visited page for given search text.
-
- Args:
- search_text: The string search text.
- url: The string URL to look for in the omnibox matches.
-
- Returns:
- True, if the omnibox returns the previously-visited page for the given
- search text, or False otherwise.
- """
- # Omnibox doesn't change results if searching the same text repeatedly.
- # So setting '' in omnibox before the next repeated search.
- self.SetOmniboxText('')
- matches = test_utils.GetOmniboxMatchesFor(self, search_text)
- matches_description = [x for x in matches if x['destination_url'] == url]
- return 1 == len(matches_description)
-
- def testContentHistory(self):
- """Verify omnibox results when entering page content.
-
- Test verifies that visited page shows up in omnibox on entering page
- content.
- """
- url = self.GetFileURLForPath(
- os.path.join(self.DataDir(), 'find_in_page', 'largepage.html'))
- self.NavigateToURL(url)
- self.assertTrue(self.WaitUntil(
- lambda: self._GotContentHistory('British throne', url)))
-
- def testOmniboxSearchHistory(self):
- """Verify page navigation/search from omnibox are added to the history."""
- url = self.GetFileURLForDataPath('title2.html')
- self.NavigateToURL(url)
- self.AppendTab(pyauto.GURL('about:blank'))
- self.SetOmniboxText('java')
- self.WaitUntilOmniboxQueryDone()
- self.OmniboxAcceptInput()
- history = self.GetHistoryInfo().History()
- self.assertEqual(2, len(history))
- self.assertEqual(url, history[1]['url'])
- self.assertEqual('java - Google Search', history[0]['title'])
-
- def _VerifyHasBookmarkResult(self, matches):
- """Verify that we have a bookmark result.
-
- Args:
- matches: A list of match items, as returned by
- test_utils.GetOmniboxMatchesFor().
- """
- matches_starred = [result for result in matches if result['starred']]
- self.assertTrue(matches_starred)
- self.assertEqual(1, len(matches_starred))
-
- def _CheckBookmarkResultForVariousInputs(self, url, title, windex=0):
- """Check if we get the bookmark for complete and partial inputs.
-
- Args:
- url: A string URL.
- title: A string title for the given URL.
- windex: The window index to use. Defaults to 0 (first window).
- """
- # Check if the complete URL would get the bookmark.
- url_matches = test_utils.GetOmniboxMatchesFor(self, url, windex=windex)
- self._VerifyHasBookmarkResult(url_matches)
- # Check if the complete title would get the bookmark.
- title_matches = test_utils.GetOmniboxMatchesFor(self, title, windex=windex)
- self._VerifyHasBookmarkResult(title_matches)
- # Check if the partial URL would get the bookmark.
- split_url = urlparse.urlsplit(url)
- partial_url = test_utils.GetOmniboxMatchesFor(
- self, split_url.scheme, windex=windex)
- self._VerifyHasBookmarkResult(partial_url)
- # Check if the partial title would get the bookmark.
- split_title = title.split()
- search_term = split_title[len(split_title) - 1]
- partial_title = test_utils.GetOmniboxMatchesFor(
- self, search_term, windex=windex)
- self._VerifyHasBookmarkResult(partial_title)
-
- def testBookmarkResultInNewTabAndWindow(self):
- """Verify omnibox finds bookmarks in search options of new tabs/windows."""
- url = self.GetFileURLForDataPath('title2.html')
- self.NavigateToURL(url)
- title = 'This is Awesomeness'
- bookmarks = self.GetBookmarkModel()
- bar_id = bookmarks.BookmarkBar()['id']
- self.AddBookmarkURL(bar_id, 0, title, url)
- bookmarks = self.GetBookmarkModel()
- nodes = bookmarks.FindByTitle(title)
- self.AppendTab(pyauto.GURL(url))
- self._CheckBookmarkResultForVariousInputs(url, title)
- self.OpenNewBrowserWindow(True)
- self.assertEqual(2, self.GetBrowserWindowCount())
- self.NavigateToURL(url, 1, 0)
- self._CheckBookmarkResultForVariousInputs(url, title, windex=1)
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
- self.assertEqual(3, self.GetBrowserWindowCount())
- self.NavigateToURL(url, 2, 0)
- self._CheckBookmarkResultForVariousInputs(url, title, windex=2)
-
- def testAutoCompleteForNonAsciiSearch(self):
- """Verify can search/autocomplete with non-ASCII incomplete keywords."""
- search_string = u'\u767e'
- verify_string = u'\u767e\u5ea6\u4e00\u4e0b'
- matches = test_utils.GetOmniboxMatchesFor(self, search_string)
- self.assertTrue(verify_string in matches[-1]['contents'])
-
-
-class OmniboxLiveTest(pyauto.PyUITest):
- """Test cases for the omnibox that hit live servers (such as Google)."""
-
- def ExtraChromeFlags(self):
- """Override default list of extra flags used in pyauto tests."""
- # Force the suggest field trial group. This doesn't guarantee that there
- # will be no experimental behaviour, but there's no other way to disable
- # all suggest field trials at the moment. TODO(mpearson): Consider allowing
- # the suggest_url to be overridden using a flag (so that we can omit the
- # "sugexp=chrome,mod=<n>" CGI param), or provide some other way to turn off
- # all suggest field trials.
- return ['--force-fieldtrials=OmniboxSearchSuggest/10/']
-
- def testGoogleSearch(self):
- """Verify Google search item in omnibox results."""
- search_text = 'hello world'
- verify_str = 'Google Search'
- url_re = 'http://www.google.com/search\?.*q=hello\+world.*'
- matches_description = test_utils.GetOmniboxMatchesFor(
- self, search_text, attr_dict={'description': verify_str})
- self.assertTrue(matches_description)
- # There should be a least one entry with the description Google. Suggest
- # results may end up having 'Google Search' in them, so use >=.
- self.assertTrue(len(matches_description) >= 1)
- item = matches_description[0]
- self.assertTrue(re.search(url_re, item['destination_url']))
- self.assertEqual('search-what-you-typed', item['type'])
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/perf.cfg b/chrome/test/functional/perf.cfg
deleted file mode 100644
index ddb7306..0000000
--- a/chrome/test/functional/perf.cfg
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright (c) 2012 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.
-
-# Configuration file for pyauto perf tests.
-# This file is used to specify google account credentials and
-# custom google account, gmail, docs, plus urls if you don't want to use
-# the public urls of these services. It is formatted as a python dictionary.
-
-{
- # Set to custom username/password if desired.
- # If you are external to Google, you must set username/password.
- # If you are internal to Google, you can leave them as None
- # and tests will try to use internal credential file.
- 'username': None,
- 'password': None,
-
- # Set to custom Google account url if desired.
- 'google_account_url': None, # Defaults to 'https://accounts.google.com'
-
- # Set to custom Gmail/Plus/Docs urls if desired.
- # Only effective for perf_endure.py
- 'gmail_url': None, # Defaults to 'https://www.gmail.com'
- 'plus_url': None, # Defaults to 'https://plus.google.com'
- 'docs_url': None, # Defaults to 'https://docs.google.com'
-}
diff --git a/chrome/test/functional/perf.py b/chrome/test/functional/perf.py
deleted file mode 100755
index 77b2eb5..0000000
--- a/chrome/test/functional/perf.py
+++ /dev/null
@@ -1,2426 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Basic pyauto performance tests.
-
-For tests that need to be run for multiple iterations (e.g., so that average
-and standard deviation values can be reported), the default number of iterations
-run for each of these tests is specified by |_DEFAULT_NUM_ITERATIONS|.
-That value can optionally be tweaked by setting an environment variable
-'NUM_ITERATIONS' to a positive integer, representing the number of iterations
-to run. An additional, initial iteration will also be run to "warm up" the
-environment, and the result from that initial iteration will be ignored.
-
-Some tests rely on repeatedly appending tabs to Chrome. Occasionally, these
-automation calls time out, thereby affecting the timing measurements (see issue
-crosbug.com/20503). To work around this, the tests discard timing measurements
-that involve automation timeouts. The value |_DEFAULT_MAX_TIMEOUT_COUNT|
-specifies the threshold number of timeouts that can be tolerated before the test
-fails. To tweak this value, set environment variable 'MAX_TIMEOUT_COUNT' to the
-desired threshold value.
-"""
-
-import BaseHTTPServer
-import commands
-import errno
-import itertools
-import logging
-import math
-import os
-import posixpath
-import re
-import SimpleHTTPServer
-import SocketServer
-import signal
-import subprocess
-import sys
-import tempfile
-import threading
-import time
-import timeit
-import urllib
-import urllib2
-import urlparse
-
-import pyauto_functional # Must be imported before pyauto.
-import pyauto
-import simplejson # Must be imported after pyauto; located in third_party.
-
-from netflix import NetflixTestHelper
-import pyauto_utils
-import test_utils
-from youtube import YoutubeTestHelper
-
-
-_CHROME_BASE_DIR = os.path.abspath(os.path.join(
- os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, os.pardir))
-
-
-def FormatChromePath(posix_path, **kwargs):
- """Convert a path relative to the Chromium root into an OS-specific path.
-
- Args:
- posix_path: a path string that may be a format().
- Example: 'src/third_party/{module_name}/__init__.py'
- kwargs: args for the format replacement.
- Example: {'module_name': 'pylib'}
-
- Returns:
- an absolute path in the current Chromium tree with formatting applied.
- """
- formated_path = posix_path.format(**kwargs)
- path_parts = formated_path.split('/')
- return os.path.join(_CHROME_BASE_DIR, *path_parts)
-
-
-def StandardDeviation(values):
- """Returns the standard deviation of |values|."""
- avg = Mean(values)
- if len(values) < 2 or not avg:
- return 0.0
- temp_vals = [math.pow(x - avg, 2) for x in values]
- return math.sqrt(sum(temp_vals) / (len(temp_vals) - 1))
-
-
-def Mean(values):
- """Returns the arithmetic mean of |values|."""
- if not values or None in values:
- return None
- return sum(values) / float(len(values))
-
-
-def GeometricMean(values):
- """Returns the geometric mean of |values|."""
- if not values or None in values or [x for x in values if x < 0.0]:
- return None
- if 0.0 in values:
- return 0.0
- return math.exp(Mean([math.log(x) for x in values]))
-
-
-class BasePerfTest(pyauto.PyUITest):
- """Base class for performance tests."""
-
- _DEFAULT_NUM_ITERATIONS = 10 # Keep synced with desktopui_PyAutoPerfTests.py.
- _DEFAULT_MAX_TIMEOUT_COUNT = 10
- _PERF_OUTPUT_MARKER_PRE = '_PERF_PRE_'
- _PERF_OUTPUT_MARKER_POST = '_PERF_POST_'
-
- def setUp(self):
- """Performs necessary setup work before running each test."""
- self._num_iterations = self._DEFAULT_NUM_ITERATIONS
- if 'NUM_ITERATIONS' in os.environ:
- self._num_iterations = int(os.environ['NUM_ITERATIONS'])
- self._max_timeout_count = self._DEFAULT_MAX_TIMEOUT_COUNT
- if 'MAX_TIMEOUT_COUNT' in os.environ:
- self._max_timeout_count = int(os.environ['MAX_TIMEOUT_COUNT'])
- self._timeout_count = 0
-
- # For users who want to see local perf graphs for Chrome when running the
- # tests on their own machines.
- self._local_perf_dir = None
- if 'LOCAL_PERF_DIR' in os.environ:
- self._local_perf_dir = os.environ['LOCAL_PERF_DIR']
- if not os.path.exists(self._local_perf_dir):
- self.fail('LOCAL_PERF_DIR environment variable specified as %s, '
- 'but this directory does not exist.' % self._local_perf_dir)
- # When outputting perf graph information on-the-fly for Chrome, this
- # variable lets us know whether a perf measurement is for a new test
- # execution, or the current test execution.
- self._seen_graph_lines = {}
-
- pyauto.PyUITest.setUp(self)
-
- # Flush all buffers to disk and wait until system calms down. Must be done
- # *after* calling pyauto.PyUITest.setUp, since that is where Chrome is
- # killed and re-initialized for a new test.
- # TODO(dennisjeffrey): Implement wait for idle CPU on Windows/Mac.
- if self.IsLinux(): # IsLinux() also implies IsChromeOS().
- os.system('sync')
- self._WaitForIdleCPU(60.0, 0.05)
-
- def _IsPIDRunning(self, pid):
- """Checks if a given process id is running.
-
- Args:
- pid: The process id of the process to check.
-
- Returns:
- True if the process is running. False if not.
- """
- try:
- # Note that this sends the signal 0, which should not interfere with the
- # process.
- os.kill(pid, 0)
- except OSError, err:
- if err.errno == errno.ESRCH:
- return False
-
- try:
- with open('/proc/%s/status' % pid) as proc_file:
- if 'zombie' in proc_file.read():
- return False
- except IOError:
- return False
- return True
-
- def _GetAllDescendentProcesses(self, pid):
- pstree_out = subprocess.check_output(['pstree', '-p', '%s' % pid])
- children = re.findall('\((\d+)\)', pstree_out)
- return [int(pid) for pid in children]
-
- def _WaitForChromeExit(self, browser_info, timeout):
- pid = browser_info['browser_pid']
- chrome_pids = self._GetAllDescendentProcesses(pid)
- initial_time = time.time()
- while time.time() - initial_time < timeout:
- if any([self._IsPIDRunning(pid) for pid in chrome_pids]):
- time.sleep(1)
- else:
- logging.info('_WaitForChromeExit() took: %s seconds',
- time.time() - initial_time)
- return
- self.fail('_WaitForChromeExit() did not finish within %s seconds' %
- timeout)
-
- def tearDown(self):
- if self._IsPGOMode():
- browser_info = self.GetBrowserInfo()
- pid = browser_info['browser_pid']
- # session_manager kills chrome without waiting for it to cleanly exit.
- # Until that behavior is changed, we stop it and wait for Chrome to exit
- # cleanly before restarting it. See:
- # crbug.com/264717
- subprocess.call(['sudo', 'pkill', '-STOP', 'session_manager'])
- os.kill(pid, signal.SIGINT)
- self._WaitForChromeExit(browser_info, 120)
- subprocess.call(['sudo', 'pkill', '-CONT', 'session_manager'])
-
- pyauto.PyUITest.tearDown(self)
-
- def _IsPGOMode(self):
- return 'USE_PGO' in os.environ
-
- def _WaitForIdleCPU(self, timeout, utilization):
- """Waits for the CPU to become idle (< utilization).
-
- Args:
- timeout: The longest time in seconds to wait before throwing an error.
- utilization: The CPU usage below which the system should be considered
- idle (between 0 and 1.0 independent of cores/hyperthreads).
- """
- time_passed = 0.0
- fraction_non_idle_time = 1.0
- logging.info('Starting to wait up to %fs for idle CPU...', timeout)
- while fraction_non_idle_time >= utilization:
- cpu_usage_start = self._GetCPUUsage()
- time.sleep(2)
- time_passed += 2.0
- cpu_usage_end = self._GetCPUUsage()
- fraction_non_idle_time = \
- self._GetFractionNonIdleCPUTime(cpu_usage_start, cpu_usage_end)
- logging.info('Current CPU utilization = %f.', fraction_non_idle_time)
- if time_passed > timeout:
- self._LogProcessActivity()
- message = ('CPU did not idle after %fs wait (utilization = %f).' % (
- time_passed, fraction_non_idle_time))
-
- # crosbug.com/37389
- if self._IsPGOMode():
- logging.info(message)
- logging.info('Still continuing because we are in PGO mode.')
- return
-
- self.fail(message)
- logging.info('Wait for idle CPU took %fs (utilization = %f).',
- time_passed, fraction_non_idle_time)
-
- def _LogProcessActivity(self):
- """Logs the output of top on Linux/Mac/CrOS.
-
- TODO: use taskmgr or similar on Windows.
- """
- if self.IsLinux() or self.IsMac(): # IsLinux() also implies IsChromeOS().
- logging.info('Logging current process activity using top.')
- cmd = 'top -b -d1 -n1'
- if self.IsMac():
- cmd = 'top -l1'
- p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
- output = p.stdout.read()
- logging.info(output)
- else:
- logging.info('Process activity logging not implemented on this OS.')
-
- def _AppendTab(self, url):
- """Appends a tab and increments a counter if the automation call times out.
-
- Args:
- url: The string url to which the appended tab should be navigated.
- """
- if not self.AppendTab(pyauto.GURL(url)):
- self._timeout_count += 1
-
- def _MeasureElapsedTime(self, python_command, num_invocations=1):
- """Measures time (in msec) to execute a python command one or more times.
-
- Args:
- python_command: A callable.
- num_invocations: An integer number of times to invoke the given command.
-
- Returns:
- The time required to execute the python command the specified number of
- times, in milliseconds as a float.
- """
- assert callable(python_command)
- def RunCommand():
- for _ in range(num_invocations):
- python_command()
- timer = timeit.Timer(stmt=RunCommand)
- return timer.timeit(number=1) * 1000 # Convert seconds to milliseconds.
-
- def _OutputPerfForStandaloneGraphing(self, graph_name, description, value,
- units, units_x, is_stacked):
- """Outputs perf measurement data to a local folder to be graphed.
-
- This function only applies to Chrome desktop, and assumes that environment
- variable 'LOCAL_PERF_DIR' has been specified and refers to a valid directory
- on the local machine.
-
- Args:
- graph_name: A string name for the graph associated with this performance
- value.
- description: A string description of the performance value. Should not
- include spaces.
- value: Either a single numeric value representing a performance
- measurement, or else a list of (x, y) tuples representing one or more
- long-running performance measurements, where 'x' is an x-axis value
- (such as an iteration number) and 'y' is the corresponding performance
- measurement. If a list of tuples is given, then the |units_x|
- argument must also be specified.
- units: A string representing the units of the performance measurement(s).
- Should not include spaces.
- units_x: A string representing the units of the x-axis values associated
- with the performance measurements, such as 'iteration' if the x values
- are iteration numbers. If this argument is specified, then the
- |value| argument must be a list of (x, y) tuples.
- is_stacked: True to draw a "stacked" graph. First-come values are
- stacked at bottom by default.
- """
- revision_num_file = os.path.join(self._local_perf_dir, 'last_revision.dat')
- if os.path.exists(revision_num_file):
- with open(revision_num_file) as f:
- revision = int(f.read())
- else:
- revision = 0
-
- if not self._seen_graph_lines:
- # We're about to output data for a new test run.
- revision += 1
-
- # Update graphs.dat.
- existing_graphs = []
- graphs_file = os.path.join(self._local_perf_dir, 'graphs.dat')
- if os.path.exists(graphs_file):
- with open(graphs_file) as f:
- existing_graphs = simplejson.loads(f.read())
- is_new_graph = True
- for graph in existing_graphs:
- if graph['name'] == graph_name:
- is_new_graph = False
- break
- if is_new_graph:
- new_graph = {
- 'name': graph_name,
- 'units': units,
- 'important': False,
- }
- if units_x:
- new_graph['units_x'] = units_x
- existing_graphs.append(new_graph)
- with open(graphs_file, 'w') as f:
- f.write(simplejson.dumps(existing_graphs))
- os.chmod(graphs_file, 0755)
-
- # Update data file for this particular graph.
- existing_lines = []
- data_file = os.path.join(self._local_perf_dir, graph_name + '-summary.dat')
- if os.path.exists(data_file):
- with open(data_file) as f:
- existing_lines = f.readlines()
- existing_lines = map(
- simplejson.loads, map(lambda x: x.strip(), existing_lines))
-
- seen_key = graph_name
- # We assume that the first line |existing_lines[0]| is the latest.
- if units_x:
- new_line = {
- 'rev': revision,
- 'traces': { description: [] }
- }
- if seen_key in self._seen_graph_lines:
- # We've added points previously for this graph line in the current
- # test execution, so retrieve the original set of points specified in
- # the most recent revision in the data file.
- new_line = existing_lines[0]
- if not description in new_line['traces']:
- new_line['traces'][description] = []
- for x_value, y_value in value:
- new_line['traces'][description].append([str(x_value), str(y_value)])
- else:
- new_line = {
- 'rev': revision,
- 'traces': { description: [str(value), str(0.0)] }
- }
-
- if is_stacked:
- new_line['stack'] = True
- if 'stack_order' not in new_line:
- new_line['stack_order'] = []
- if description not in new_line['stack_order']:
- new_line['stack_order'].append(description)
-
- if seen_key in self._seen_graph_lines:
- # Update results for the most recent revision.
- existing_lines[0] = new_line
- else:
- # New results for a new revision.
- existing_lines.insert(0, new_line)
- self._seen_graph_lines[seen_key] = True
-
- existing_lines = map(simplejson.dumps, existing_lines)
- with open(data_file, 'w') as f:
- f.write('\n'.join(existing_lines))
- os.chmod(data_file, 0755)
-
- with open(revision_num_file, 'w') as f:
- f.write(str(revision))
-
- def _OutputPerfGraphValue(self, description, value, units,
- graph_name, units_x=None, is_stacked=False):
- """Outputs a performance value to have it graphed on the performance bots.
-
- The output format differs, depending on whether the current platform is
- Chrome desktop or ChromeOS.
-
- For ChromeOS, the performance bots have a 30-character limit on the length
- of the key associated with a performance value. A key on ChromeOS is
- considered to be of the form "units_description" (for example,
- "milliseconds_NewTabPage"), and is created from the |units| and
- |description| passed as input to this function. Any characters beyond the
- length 30 limit are truncated before results are stored in the autotest
- database.
-
- Args:
- description: A string description of the performance value. Should not
- include spaces.
- value: Either a numeric value representing a performance measurement, or
- a list of values to be averaged. Lists may also contain (x, y) tuples
- representing one or more performance measurements, where 'x' is an
- x-axis value (such as an iteration number) and 'y' is the
- corresponding performance measurement. If a list of tuples is given,
- the |units_x| argument must also be specified.
- units: A string representing the units of the performance measurement(s).
- Should not include spaces.
- graph_name: A string name for the graph associated with this performance
- value. Only used on Chrome desktop.
- units_x: A string representing the units of the x-axis values associated
- with the performance measurements, such as 'iteration' if the x values
- are iteration numbers. If this argument is specified, then the
- |value| argument must be a list of (x, y) tuples.
- is_stacked: True to draw a "stacked" graph. First-come values are
- stacked at bottom by default.
- """
- if (isinstance(value, list) and value[0] is not None and
- isinstance(value[0], tuple)):
- assert units_x
- if units_x:
- assert isinstance(value, list)
-
- if self.IsChromeOS():
- # Autotest doesn't support result lists.
- autotest_value = value
- if (isinstance(value, list) and value[0] is not None and
- not isinstance(value[0], tuple)):
- autotest_value = Mean(value)
-
- if units_x:
- # TODO(dennisjeffrey): Support long-running performance measurements on
- # ChromeOS in a way that can be graphed: crosbug.com/21881.
- pyauto_utils.PrintPerfResult(graph_name, description, autotest_value,
- units + ' ' + units_x)
- else:
- # Output short-running performance results in a format understood by
- # autotest.
- perf_key = '%s_%s' % (units, description)
- if len(perf_key) > 30:
- logging.warning('The description "%s" will be truncated to "%s" '
- '(length 30) when added to the autotest database.',
- perf_key, perf_key[:30])
- print '\n%s(\'%s\', %f)%s' % (self._PERF_OUTPUT_MARKER_PRE,
- perf_key, autotest_value,
- self._PERF_OUTPUT_MARKER_POST)
-
- # Also output results in the format recognized by buildbot, for cases
- # in which these tests are run on chromeOS through buildbot. Since
- # buildbot supports result lists, it's ok for |value| to be a list here.
- pyauto_utils.PrintPerfResult(graph_name, description, value, units)
-
- sys.stdout.flush()
- else:
- # TODO(dmikurube): Support stacked graphs in PrintPerfResult.
- # See http://crbug.com/122119.
- if units_x:
- pyauto_utils.PrintPerfResult(graph_name, description, value,
- units + ' ' + units_x)
- else:
- pyauto_utils.PrintPerfResult(graph_name, description, value, units)
-
- if self._local_perf_dir:
- self._OutputPerfForStandaloneGraphing(
- graph_name, description, value, units, units_x, is_stacked)
-
- def _OutputEventForStandaloneGraphing(self, description, event_list):
- """Outputs event information to a local folder to be graphed.
-
- See function _OutputEventGraphValue below for a description of an event.
-
- This function only applies to Chrome Endure tests running on Chrome desktop,
- and assumes that environment variable 'LOCAL_PERF_DIR' has been specified
- and refers to a valid directory on the local machine.
-
- Args:
- description: A string description of the event. Should not include
- spaces.
- event_list: A list of (x, y) tuples representing one or more events
- occurring during an endurance test, where 'x' is the time of the event
- (in seconds since the start of the test), and 'y' is a dictionary
- representing relevant data associated with that event (as key/value
- pairs).
- """
- revision_num_file = os.path.join(self._local_perf_dir, 'last_revision.dat')
- if os.path.exists(revision_num_file):
- with open(revision_num_file) as f:
- revision = int(f.read())
- else:
- revision = 0
-
- if not self._seen_graph_lines:
- # We're about to output data for a new test run.
- revision += 1
-
- existing_lines = []
- data_file = os.path.join(self._local_perf_dir, '_EVENT_-summary.dat')
- if os.path.exists(data_file):
- with open(data_file) as f:
- existing_lines = f.readlines()
- existing_lines = map(eval, map(lambda x: x.strip(), existing_lines))
-
- seen_event_type = description
- value_list = []
- if seen_event_type in self._seen_graph_lines:
- # We've added events previously for this event type in the current
- # test execution, so retrieve the original set of values specified in
- # the most recent revision in the data file.
- value_list = existing_lines[0]['events'][description]
- for event_time, event_data in event_list:
- value_list.append([str(event_time), event_data])
- new_events = {
- description: value_list
- }
-
- new_line = {
- 'rev': revision,
- 'events': new_events
- }
-
- if seen_event_type in self._seen_graph_lines:
- # Update results for the most recent revision.
- existing_lines[0] = new_line
- else:
- # New results for a new revision.
- existing_lines.insert(0, new_line)
- self._seen_graph_lines[seen_event_type] = True
-
- existing_lines = map(str, existing_lines)
- with open(data_file, 'w') as f:
- f.write('\n'.join(existing_lines))
- os.chmod(data_file, 0755)
-
- with open(revision_num_file, 'w') as f:
- f.write(str(revision))
-
- def _OutputEventGraphValue(self, description, event_list):
- """Outputs a set of events to have them graphed on the Chrome Endure bots.
-
- An "event" can be anything recorded by a performance test that occurs at
- particular times during a test execution. For example, a garbage collection
- in the v8 heap can be considered an event. An event is distinguished from a
- regular perf measurement in two ways: (1) an event is depicted differently
- in the performance graphs than performance measurements; (2) an event can
- be associated with zero or more data fields describing relevant information
- associated with the event. For example, a garbage collection event will
- occur at a particular time, and it may be associated with data such as
- the number of collected bytes and/or the length of time it took to perform
- the garbage collection.
-
- This function only applies to Chrome Endure tests running on Chrome desktop.
-
- Args:
- description: A string description of the event. Should not include
- spaces.
- event_list: A list of (x, y) tuples representing one or more events
- occurring during an endurance test, where 'x' is the time of the event
- (in seconds since the start of the test), and 'y' is a dictionary
- representing relevant data associated with that event (as key/value
- pairs).
- """
- pyauto_utils.PrintPerfResult('_EVENT_', description, event_list, '')
- if self._local_perf_dir:
- self._OutputEventForStandaloneGraphing(description, event_list)
-
- def _PrintSummaryResults(self, description, values, units, graph_name):
- """Logs summary measurement information.
-
- This function computes and outputs the average and standard deviation of
- the specified list of value measurements. It also invokes
- _OutputPerfGraphValue() with the computed *average* value, to ensure the
- average value can be plotted in a performance graph.
-
- Args:
- description: A string description for the specified results.
- values: A list of numeric value measurements.
- units: A string specifying the units for the specified measurements.
- graph_name: A string name for the graph associated with this performance
- value. Only used on Chrome desktop.
- """
- logging.info('Overall results for: %s', description)
- if values:
- logging.info(' Average: %f %s', Mean(values), units)
- logging.info(' Std dev: %f %s', StandardDeviation(values), units)
- self._OutputPerfGraphValue(description, values, units, graph_name)
- else:
- logging.info('No results to report.')
-
- def _RunNewTabTest(self, description, open_tab_command, graph_name,
- num_tabs=1):
- """Runs a perf test that involves opening new tab(s).
-
- This helper function can be called from different tests to do perf testing
- with different types of tabs. It is assumed that the |open_tab_command|
- will open up a single tab.
-
- Args:
- description: A string description of the associated tab test.
- open_tab_command: A callable that will open a single tab.
- graph_name: A string name for the performance graph associated with this
- test. Only used on Chrome desktop.
- num_tabs: The number of tabs to open, i.e., the number of times to invoke
- the |open_tab_command|.
- """
- assert callable(open_tab_command)
-
- timings = []
- for iteration in range(self._num_iterations + 1):
- orig_timeout_count = self._timeout_count
- elapsed_time = self._MeasureElapsedTime(open_tab_command,
- num_invocations=num_tabs)
- # Only count the timing measurement if no automation call timed out.
- if self._timeout_count == orig_timeout_count:
- # Ignore the first iteration.
- if iteration:
- timings.append(elapsed_time)
- logging.info('Iteration %d of %d: %f milliseconds', iteration,
- self._num_iterations, elapsed_time)
- self.assertTrue(self._timeout_count <= self._max_timeout_count,
- msg='Test exceeded automation timeout threshold.')
- self.assertEqual(1 + num_tabs, self.GetTabCount(),
- msg='Did not open %d new tab(s).' % num_tabs)
- for _ in range(num_tabs):
- self.CloseTab(tab_index=1)
-
- self._PrintSummaryResults(description, timings, 'milliseconds', graph_name)
-
- def _GetConfig(self):
- """Load perf test configuration file.
-
- Returns:
- A dictionary that represents the config information.
- """
- config_file = os.path.join(os.path.dirname(__file__), 'perf.cfg')
- config = {'username': None,
- 'password': None,
- 'google_account_url': 'https://accounts.google.com/',
- 'gmail_url': 'https://www.gmail.com',
- 'plus_url': 'https://plus.google.com',
- 'docs_url': 'https://docs.google.com'}
- if os.path.exists(config_file):
- try:
- new_config = pyauto.PyUITest.EvalDataFrom(config_file)
- for key in new_config:
- if new_config.get(key) is not None:
- config[key] = new_config.get(key)
- except SyntaxError, e:
- logging.info('Could not read %s: %s', config_file, str(e))
- return config
-
- def _LoginToGoogleAccount(self, account_key='test_google_account'):
- """Logs in to a test Google account.
-
- Login with user-defined credentials if they exist.
- Else login with private test credentials if they exist.
- Else fail.
-
- Args:
- account_key: The string key in private_tests_info.txt which is associated
- with the test account login credentials to use. It will only
- be used when fail to load user-defined credentials.
-
- Raises:
- RuntimeError: if could not get credential information.
- """
- private_file = os.path.join(pyauto.PyUITest.DataDir(), 'pyauto_private',
- 'private_tests_info.txt')
- config_file = os.path.join(os.path.dirname(__file__), 'perf.cfg')
- config = self._GetConfig()
- google_account_url = config.get('google_account_url')
- username = config.get('username')
- password = config.get('password')
- if username and password:
- logging.info(
- 'Using google account credential from %s',
- os.path.join(os.path.dirname(__file__), 'perf.cfg'))
- elif os.path.exists(private_file):
- creds = self.GetPrivateInfo()[account_key]
- username = creds['username']
- password = creds['password']
- logging.info(
- 'User-defined credentials not found,' +
- ' using private test credentials instead.')
- else:
- message = 'No user-defined or private test ' \
- 'credentials could be found. ' \
- 'Please specify credential information in %s.' \
- % config_file
- raise RuntimeError(message)
- test_utils.GoogleAccountsLogin(
- self, username, password, url=google_account_url)
- self.NavigateToURL('about:blank') # Clear the existing tab.
-
- def _GetCPUUsage(self):
- """Returns machine's CPU usage.
-
- This function uses /proc/stat to identify CPU usage, and therefore works
- only on Linux/ChromeOS.
-
- Returns:
- A dictionary with 'user', 'nice', 'system' and 'idle' values.
- Sample dictionary:
- {
- 'user': 254544,
- 'nice': 9,
- 'system': 254768,
- 'idle': 2859878,
- }
- """
- try:
- f = open('/proc/stat')
- cpu_usage_str = f.readline().split()
- f.close()
- except IOError, e:
- self.fail('Could not retrieve CPU usage: ' + str(e))
- return {
- 'user': int(cpu_usage_str[1]),
- 'nice': int(cpu_usage_str[2]),
- 'system': int(cpu_usage_str[3]),
- 'idle': int(cpu_usage_str[4])
- }
-
- def _GetFractionNonIdleCPUTime(self, cpu_usage_start, cpu_usage_end):
- """Computes the fraction of CPU time spent non-idling.
-
- This function should be invoked using before/after values from calls to
- _GetCPUUsage().
- """
- time_non_idling_end = (cpu_usage_end['user'] + cpu_usage_end['nice'] +
- cpu_usage_end['system'])
- time_non_idling_start = (cpu_usage_start['user'] + cpu_usage_start['nice'] +
- cpu_usage_start['system'])
- total_time_end = (cpu_usage_end['user'] + cpu_usage_end['nice'] +
- cpu_usage_end['system'] + cpu_usage_end['idle'])
- total_time_start = (cpu_usage_start['user'] + cpu_usage_start['nice'] +
- cpu_usage_start['system'] + cpu_usage_start['idle'])
- return ((float(time_non_idling_end) - time_non_idling_start) /
- (total_time_end - total_time_start))
-
- def ExtraChromeFlags(self):
- """Ensures Chrome is launched with custom flags.
-
- Returns:
- A list of extra flags to pass to Chrome when it is launched.
- """
- flags = super(BasePerfTest, self).ExtraChromeFlags()
- # Window size impacts a variety of perf tests, ensure consistency.
- flags.append('--window-size=1024,768')
- if self._IsPGOMode():
- flags = flags + ['--no-sandbox']
- return flags
-
-
-class TabPerfTest(BasePerfTest):
- """Tests that involve opening tabs."""
-
- def testNewTab(self):
- """Measures time to open a new tab."""
- self._RunNewTabTest('NewTabPage',
- lambda: self._AppendTab('chrome://newtab'), 'open_tab')
-
- def testNewTabFlash(self):
- """Measures time to open a new tab navigated to a flash page."""
- self.assertTrue(
- os.path.exists(os.path.join(self.ContentDataDir(), 'plugin',
- 'flash.swf')),
- msg='Missing required flash data file.')
- url = self.GetFileURLForContentDataPath('plugin', 'flash.swf')
- self._RunNewTabTest('NewTabFlashPage', lambda: self._AppendTab(url),
- 'open_tab')
-
- def test20Tabs(self):
- """Measures time to open 20 tabs."""
- self._RunNewTabTest('20TabsNewTabPage',
- lambda: self._AppendTab('chrome://newtab'),
- 'open_20_tabs', num_tabs=20)
-
-
-class BenchmarkPerfTest(BasePerfTest):
- """Benchmark performance tests."""
-
- def testV8BenchmarkSuite(self):
- """Measures score from v8 benchmark suite."""
- url = self.GetFileURLForDataPath('v8_benchmark_v6', 'run.html')
-
- def _RunBenchmarkOnce(url):
- """Runs the v8 benchmark suite once and returns the results in a dict."""
- self.assertTrue(self.AppendTab(pyauto.GURL(url)),
- msg='Failed to append tab for v8 benchmark suite.')
- js_done = """
- var val = document.getElementById("status").innerHTML;
- window.domAutomationController.send(val);
- """
- self.assertTrue(
- self.WaitUntil(
- lambda: 'Score:' in self.ExecuteJavascript(js_done, tab_index=1),
- timeout=300, expect_retval=True, retry_sleep=1),
- msg='Timed out when waiting for v8 benchmark score.')
-
- js_get_results = """
- var result = {};
- result['final_score'] = document.getElementById("status").innerHTML;
- result['all_results'] = document.getElementById("results").innerHTML;
- window.domAutomationController.send(JSON.stringify(result));
- """
- results = eval(self.ExecuteJavascript(js_get_results, tab_index=1))
- score_pattern = '(\w+): (\d+)'
- final_score = re.search(score_pattern, results['final_score']).group(2)
- result_dict = {'final_score': int(final_score)}
- for match in re.finditer(score_pattern, results['all_results']):
- benchmark_name = match.group(1)
- benchmark_score = match.group(2)
- result_dict[benchmark_name] = int(benchmark_score)
- self.CloseTab(tab_index=1)
- return result_dict
-
- timings = {}
- for iteration in xrange(self._num_iterations + 1):
- result_dict = _RunBenchmarkOnce(url)
- # Ignore the first iteration.
- if iteration:
- for key, val in result_dict.items():
- timings.setdefault(key, []).append(val)
- logging.info('Iteration %d of %d:\n%s', iteration,
- self._num_iterations, self.pformat(result_dict))
-
- for key, val in timings.items():
- if key == 'final_score':
- self._PrintSummaryResults('V8Benchmark', val, 'score',
- 'v8_benchmark_final')
- else:
- self._PrintSummaryResults('V8Benchmark-%s' % key, val, 'score',
- 'v8_benchmark_individual')
-
- def testSunSpider(self):
- """Runs the SunSpider javascript benchmark suite."""
- url = self.GetFileURLForDataPath('sunspider', 'sunspider-driver.html')
- self.assertTrue(self.AppendTab(pyauto.GURL(url)),
- msg='Failed to append tab for SunSpider benchmark suite.')
-
- js_is_done = """
- var done = false;
- if (document.getElementById("console"))
- done = true;
- window.domAutomationController.send(JSON.stringify(done));
- """
- self.assertTrue(
- self.WaitUntil(
- lambda: self.ExecuteJavascript(js_is_done, tab_index=1),
- timeout=300, expect_retval='true', retry_sleep=1),
- msg='Timed out when waiting for SunSpider benchmark score.')
-
- js_get_results = """
- window.domAutomationController.send(
- document.getElementById("console").innerHTML);
- """
- # Append '<br>' to the result to simplify regular expression matching.
- results = self.ExecuteJavascript(js_get_results, tab_index=1) + '<br>'
- total = re.search('Total:\s*([\d.]+)ms', results).group(1)
- logging.info('Total: %f ms', float(total))
- self._OutputPerfGraphValue('SunSpider-total', float(total), 'ms',
- 'sunspider_total')
-
- for match_category in re.finditer('\s\s(\w+):\s*([\d.]+)ms.+?<br><br>',
- results):
- category_name = match_category.group(1)
- category_result = match_category.group(2)
- logging.info('Benchmark "%s": %f ms', category_name,
- float(category_result))
- self._OutputPerfGraphValue('SunSpider-' + category_name,
- float(category_result), 'ms',
- 'sunspider_individual')
-
- for match_result in re.finditer('<br>\s\s\s\s([\w-]+):\s*([\d.]+)ms',
- match_category.group(0)):
- result_name = match_result.group(1)
- result_value = match_result.group(2)
- logging.info(' Result "%s-%s": %f ms', category_name, result_name,
- float(result_value))
- self._OutputPerfGraphValue(
- 'SunSpider-%s-%s' % (category_name, result_name),
- float(result_value), 'ms', 'sunspider_individual')
-
- def testDromaeoSuite(self):
- """Measures results from Dromaeo benchmark suite."""
- url = self.GetFileURLForDataPath('dromaeo', 'index.html')
- self.assertTrue(self.AppendTab(pyauto.GURL(url + '?dromaeo')),
- msg='Failed to append tab for Dromaeo benchmark suite.')
-
- js_is_ready = """
- var val = document.getElementById('pause').value;
- window.domAutomationController.send(val);
- """
- self.assertTrue(
- self.WaitUntil(
- lambda: self.ExecuteJavascript(js_is_ready, tab_index=1),
- timeout=30, expect_retval='Run', retry_sleep=1),
- msg='Timed out when waiting for Dromaeo benchmark to load.')
-
- js_run = """
- $('#pause').val('Run').click();
- window.domAutomationController.send('done');
- """
- self.ExecuteJavascript(js_run, tab_index=1)
-
- js_is_done = """
- var val = document.getElementById('timebar').innerHTML;
- window.domAutomationController.send(val);
- """
- self.assertTrue(
- self.WaitUntil(
- lambda: 'Total' in self.ExecuteJavascript(js_is_done, tab_index=1),
- timeout=900, expect_retval=True, retry_sleep=2),
- msg='Timed out when waiting for Dromaeo benchmark to complete.')
-
- js_get_results = """
- var result = {};
- result['total_result'] = $('#timebar strong').html();
- result['all_results'] = {};
- $('.result-item.done').each(function (i) {
- var group_name = $(this).find('.test b').html().replace(':', '');
- var group_results = {};
- group_results['result'] =
- $(this).find('span').html().replace('runs/s', '')
-
- group_results['sub_groups'] = {}
- $(this).find('li').each(function (i) {
- var sub_name = $(this).find('b').html().replace(':', '');
- group_results['sub_groups'][sub_name] =
- $(this).text().match(/: ([\d.]+)/)[1]
- });
- result['all_results'][group_name] = group_results;
- });
- window.domAutomationController.send(JSON.stringify(result));
- """
- results = eval(self.ExecuteJavascript(js_get_results, tab_index=1))
- total_result = results['total_result']
- logging.info('Total result: ' + total_result)
- self._OutputPerfGraphValue('Dromaeo-total', float(total_result),
- 'runsPerSec', 'dromaeo_total')
-
- for group_name, group in results['all_results'].iteritems():
- logging.info('Benchmark "%s": %s', group_name, group['result'])
- self._OutputPerfGraphValue('Dromaeo-' + group_name.replace(' ', ''),
- float(group['result']), 'runsPerSec',
- 'dromaeo_individual')
- for benchmark_name, benchmark_score in group['sub_groups'].iteritems():
- logging.info(' Result "%s": %s', benchmark_name, benchmark_score)
-
- def testSpaceport(self):
- """Measures results from Spaceport benchmark suite."""
- # TODO(tonyg): Test is failing on bots. Diagnose and re-enable.
- pass
-
-# url = self.GetFileURLForDataPath('third_party', 'spaceport', 'index.html')
-# self.assertTrue(self.AppendTab(pyauto.GURL(url + '?auto')),
-# msg='Failed to append tab for Spaceport benchmark suite.')
-#
-# # The test reports results to console.log in the format "name: value".
-# # Inject a bit of JS to intercept those.
-# js_collect_console_log = """
-# window.__pyautoresult = {};
-# window.console.log = function(str) {
-# if (!str) return;
-# var key_val = str.split(': ');
-# if (!key_val.length == 2) return;
-# __pyautoresult[key_val[0]] = key_val[1];
-# };
-# window.domAutomationController.send('done');
-# """
-# self.ExecuteJavascript(js_collect_console_log, tab_index=1)
-#
-# def _IsDone():
-# expected_num_results = 30 # The number of tests in benchmark.
-# results = eval(self.ExecuteJavascript(js_get_results, tab_index=1))
-# return expected_num_results == len(results)
-#
-# js_get_results = """
-# window.domAutomationController.send(
-# JSON.stringify(window.__pyautoresult));
-# """
-# self.assertTrue(
-# self.WaitUntil(_IsDone, timeout=1200, expect_retval=True,
-# retry_sleep=5),
-# msg='Timed out when waiting for Spaceport benchmark to complete.')
-# results = eval(self.ExecuteJavascript(js_get_results, tab_index=1))
-#
-# for key in results:
-# suite, test = key.split('.')
-# value = float(results[key])
-# self._OutputPerfGraphValue(test, value, 'ObjectsAt30FPS', suite)
-# self._PrintSummaryResults('Overall', [float(x) for x in results.values()],
-# 'ObjectsAt30FPS', 'Overall')
-
-
-class LiveWebappLoadTest(BasePerfTest):
- """Tests that involve performance measurements of live webapps.
-
- These tests connect to live webpages (e.g., Gmail, Calendar, Docs) and are
- therefore subject to network conditions. These tests are meant to generate
- "ball-park" numbers only (to see roughly how long things take to occur from a
- user's perspective), and are not expected to be precise.
- """
-
- def testNewTabGmail(self):
- """Measures time to open a tab to a logged-in Gmail account.
-
- Timing starts right before the new tab is opened, and stops as soon as the
- webpage displays the substring 'Last account activity:'.
- """
- EXPECTED_SUBSTRING = 'Last account activity:'
-
- def _SubstringExistsOnPage():
- js = """
- var frame = document.getElementById("canvas_frame");
- var divs = frame.contentDocument.getElementsByTagName("div");
- for (var i = 0; i < divs.length; ++i) {
- if (divs[i].innerHTML.indexOf("%s") >= 0)
- window.domAutomationController.send("true");
- }
- window.domAutomationController.send("false");
- """ % EXPECTED_SUBSTRING
- return self.ExecuteJavascript(js, tab_index=1)
-
- def _RunSingleGmailTabOpen():
- self._AppendTab('http://www.gmail.com')
- self.assertTrue(self.WaitUntil(_SubstringExistsOnPage, timeout=120,
- expect_retval='true', retry_sleep=0.10),
- msg='Timed out waiting for expected Gmail string.')
-
- self._LoginToGoogleAccount()
- self._RunNewTabTest('NewTabGmail', _RunSingleGmailTabOpen,
- 'open_tab_live_webapp')
-
- def testNewTabCalendar(self):
- """Measures time to open a tab to a logged-in Calendar account.
-
- Timing starts right before the new tab is opened, and stops as soon as the
- webpage displays the calendar print button (title 'Print my calendar').
- """
- EXPECTED_SUBSTRING = 'Month'
-
- def _DivTitleStartsWith():
- js = """
- var divs = document.getElementsByTagName("div");
- for (var i = 0; i < divs.length; ++i) {
- if (divs[i].innerHTML == "%s")
- window.domAutomationController.send("true");
- }
- window.domAutomationController.send("false");
- """ % EXPECTED_SUBSTRING
- return self.ExecuteJavascript(js, tab_index=1)
-
- def _RunSingleCalendarTabOpen():
- self._AppendTab('http://calendar.google.com')
- self.assertTrue(self.WaitUntil(_DivTitleStartsWith, timeout=120,
- expect_retval='true', retry_sleep=0.10),
- msg='Timed out waiting for expected Calendar string.')
-
- self._LoginToGoogleAccount()
- self._RunNewTabTest('NewTabCalendar', _RunSingleCalendarTabOpen,
- 'open_tab_live_webapp')
-
- def testNewTabDocs(self):
- """Measures time to open a tab to a logged-in Docs account.
-
- Timing starts right before the new tab is opened, and stops as soon as the
- webpage displays the expected substring 'last modified' (case insensitive).
- """
- EXPECTED_SUBSTRING = 'sort'
-
- def _SubstringExistsOnPage():
- js = """
- var divs = document.getElementsByTagName("div");
- for (var i = 0; i < divs.length; ++i) {
- if (divs[i].innerHTML.toLowerCase().indexOf("%s") >= 0)
- window.domAutomationController.send("true");
- }
- window.domAutomationController.send("false");
- """ % EXPECTED_SUBSTRING
- return self.ExecuteJavascript(js, tab_index=1)
-
- def _RunSingleDocsTabOpen():
- self._AppendTab('http://docs.google.com')
- self.assertTrue(self.WaitUntil(_SubstringExistsOnPage, timeout=120,
- expect_retval='true', retry_sleep=0.10),
- msg='Timed out waiting for expected Docs string.')
-
- self._LoginToGoogleAccount()
- self._RunNewTabTest('NewTabDocs', _RunSingleDocsTabOpen,
- 'open_tab_live_webapp')
-
-
-class NetflixPerfTest(BasePerfTest, NetflixTestHelper):
- """Test Netflix video performance."""
-
- def __init__(self, methodName='runTest', **kwargs):
- pyauto.PyUITest.__init__(self, methodName, **kwargs)
- NetflixTestHelper.__init__(self, self)
-
- def tearDown(self):
- self.SignOut()
- pyauto.PyUITest.tearDown(self)
-
- def testNetflixDroppedFrames(self):
- """Measures the Netflix video dropped frames/second. Runs for 60 secs."""
- self.LoginAndStartPlaying()
- self.CheckNetflixPlaying(self.IS_PLAYING,
- 'Player did not start playing the title.')
- # Ignore first 10 seconds of video playing so we get smooth videoplayback.
- time.sleep(10)
- init_dropped_frames = self._GetVideoDroppedFrames()
- dropped_frames = []
- prev_dropped_frames = 0
- for iteration in xrange(60):
- # Ignoring initial dropped frames of first 10 seconds.
- total_dropped_frames = self._GetVideoDroppedFrames() - init_dropped_frames
- dropped_frames_last_sec = total_dropped_frames - prev_dropped_frames
- dropped_frames.append(dropped_frames_last_sec)
- logging.info('Iteration %d of %d: %f dropped frames in the last second',
- iteration + 1, 60, dropped_frames_last_sec)
- prev_dropped_frames = total_dropped_frames
- # Play the video for some time.
- time.sleep(1)
- self._PrintSummaryResults('NetflixDroppedFrames', dropped_frames, 'frames',
- 'netflix_dropped_frames')
-
- def testNetflixCPU(self):
- """Measures the Netflix video CPU usage. Runs for 60 seconds."""
- self.LoginAndStartPlaying()
- self.CheckNetflixPlaying(self.IS_PLAYING,
- 'Player did not start playing the title.')
- # Ignore first 10 seconds of video playing so we get smooth videoplayback.
- time.sleep(10)
- init_dropped_frames = self._GetVideoDroppedFrames()
- init_video_frames = self._GetVideoFrames()
- cpu_usage_start = self._GetCPUUsage()
- total_shown_frames = 0
- # Play the video for some time.
- time.sleep(60)
- total_video_frames = self._GetVideoFrames() - init_video_frames
- total_dropped_frames = self._GetVideoDroppedFrames() - init_dropped_frames
- cpu_usage_end = self._GetCPUUsage()
- fraction_non_idle_time = \
- self._GetFractionNonIdleCPUTime(cpu_usage_start, cpu_usage_end)
- # Counting extrapolation for utilization to play the video.
- extrapolation_value = fraction_non_idle_time * \
- (float(total_video_frames) + total_dropped_frames) / total_video_frames
- logging.info('Netflix CPU extrapolation: %f', extrapolation_value)
- self._OutputPerfGraphValue('NetflixCPUExtrapolation', extrapolation_value,
- 'extrapolation', 'netflix_cpu_extrapolation')
-
-
-class YoutubePerfTest(BasePerfTest, YoutubeTestHelper):
- """Test Youtube video performance."""
-
- def __init__(self, methodName='runTest', **kwargs):
- pyauto.PyUITest.__init__(self, methodName, **kwargs)
- YoutubeTestHelper.__init__(self, self)
-
- def _VerifyVideoTotalBytes(self):
- """Returns true if video total bytes information is available."""
- return self.GetVideoTotalBytes() > 0
-
- def _VerifyVideoLoadedBytes(self):
- """Returns true if video loaded bytes information is available."""
- return self.GetVideoLoadedBytes() > 0
-
- def StartVideoForPerformance(self, video_id='zuzaxlddWbk'):
- """Start the test video with all required buffering."""
- self.PlayVideoAndAssert(video_id)
- self.ExecuteJavascript("""
- ytplayer.setPlaybackQuality('hd720');
- window.domAutomationController.send('');
- """)
- self.AssertPlayerState(state=self.is_playing,
- msg='Player did not enter the playing state')
- self.assertTrue(
- self.WaitUntil(self._VerifyVideoTotalBytes, expect_retval=True),
- msg='Failed to get video total bytes information.')
- self.assertTrue(
- self.WaitUntil(self._VerifyVideoLoadedBytes, expect_retval=True),
- msg='Failed to get video loaded bytes information')
- loaded_video_bytes = self.GetVideoLoadedBytes()
- total_video_bytes = self.GetVideoTotalBytes()
- self.PauseVideo()
- logging.info('total_video_bytes: %f', total_video_bytes)
- # Wait for the video to finish loading.
- while total_video_bytes > loaded_video_bytes:
- loaded_video_bytes = self.GetVideoLoadedBytes()
- logging.info('loaded_video_bytes: %f', loaded_video_bytes)
- time.sleep(1)
- self.PlayVideo()
- # Ignore first 10 seconds of video playing so we get smooth videoplayback.
- time.sleep(10)
-
- def testYoutubeDroppedFrames(self):
- """Measures the Youtube video dropped frames/second. Runs for 60 secs.
-
- This test measures Youtube video dropped frames for three different types
- of videos like slow, normal and fast motion.
- """
- youtube_video = {'Slow': 'VT1-sitWRtY',
- 'Normal': '2tqK_3mKQUw',
- 'Fast': '8ETDE0VGJY4',
- }
- for video_type in youtube_video:
- logging.info('Running %s video.', video_type)
- self.StartVideoForPerformance(youtube_video[video_type])
- init_dropped_frames = self.GetVideoDroppedFrames()
- total_dropped_frames = 0
- dropped_fps = []
- for iteration in xrange(60):
- frames = self.GetVideoDroppedFrames() - init_dropped_frames
- current_dropped_frames = frames - total_dropped_frames
- dropped_fps.append(current_dropped_frames)
- logging.info('Iteration %d of %d: %f dropped frames in the last '
- 'second', iteration + 1, 60, current_dropped_frames)
- total_dropped_frames = frames
- # Play the video for some time
- time.sleep(1)
- graph_description = 'YoutubeDroppedFrames' + video_type
- self._PrintSummaryResults(graph_description, dropped_fps, 'frames',
- 'youtube_dropped_frames')
-
- def testYoutubeCPU(self):
- """Measures the Youtube video CPU usage. Runs for 60 seconds.
-
- Measures the Youtube video CPU usage (between 0 and 1), extrapolated to
- totalframes in the video by taking dropped frames into account. For smooth
- videoplayback this number should be < 0.5..1.0 on a hyperthreaded CPU.
- """
- self.StartVideoForPerformance()
- init_dropped_frames = self.GetVideoDroppedFrames()
- logging.info('init_dropped_frames: %f', init_dropped_frames)
- cpu_usage_start = self._GetCPUUsage()
- total_shown_frames = 0
- for sec_num in xrange(60):
- # Play the video for some time.
- time.sleep(1)
- total_shown_frames = total_shown_frames + self.GetVideoFrames()
- logging.info('total_shown_frames: %f', total_shown_frames)
- total_dropped_frames = self.GetVideoDroppedFrames() - init_dropped_frames
- logging.info('total_dropped_frames: %f', total_dropped_frames)
- cpu_usage_end = self._GetCPUUsage()
- fraction_non_idle_time = self._GetFractionNonIdleCPUTime(
- cpu_usage_start, cpu_usage_end)
- logging.info('fraction_non_idle_time: %f', fraction_non_idle_time)
- total_frames = total_shown_frames + total_dropped_frames
- # Counting extrapolation for utilization to play the video.
- extrapolation_value = (fraction_non_idle_time *
- (float(total_frames) / total_shown_frames))
- logging.info('Youtube CPU extrapolation: %f', extrapolation_value)
- # Video is still running so log some more detailed data.
- self._LogProcessActivity()
- self._OutputPerfGraphValue('YoutubeCPUExtrapolation', extrapolation_value,
- 'extrapolation', 'youtube_cpu_extrapolation')
-
-
-class FlashVideoPerfTest(BasePerfTest):
- """General flash video performance tests."""
-
- def FlashVideo1080P(self):
- """Measures total dropped frames and average FPS for a 1080p flash video.
-
- This is a temporary test to be run manually for now, needed to collect some
- performance statistics across different ChromeOS devices.
- """
- # Open up the test webpage; it's assumed the test will start automatically.
- webpage_url = 'http://www/~arscott/fl/FlashVideoTests.html'
- self.assertTrue(self.AppendTab(pyauto.GURL(webpage_url)),
- msg='Failed to append tab for webpage.')
-
- # Wait until the test is complete.
- js_is_done = """
- window.domAutomationController.send(JSON.stringify(tests_done));
- """
- self.assertTrue(
- self.WaitUntil(
- lambda: self.ExecuteJavascript(js_is_done, tab_index=1) == 'true',
- timeout=300, expect_retval=True, retry_sleep=1),
- msg='Timed out when waiting for test result.')
-
- # Retrieve and output the test results.
- js_results = """
- window.domAutomationController.send(JSON.stringify(tests_results));
- """
- test_result = eval(self.ExecuteJavascript(js_results, tab_index=1))
- test_result[0] = test_result[0].replace('true', 'True')
- test_result = eval(test_result[0]) # Webpage only does 1 test right now.
-
- description = 'FlashVideo1080P'
- result = test_result['averageFPS']
- logging.info('Result for %s: %f FPS (average)', description, result)
- self._OutputPerfGraphValue(description, result, 'FPS',
- 'flash_video_1080p_fps')
- result = test_result['droppedFrames']
- logging.info('Result for %s: %f dropped frames', description, result)
- self._OutputPerfGraphValue(description, result, 'DroppedFrames',
- 'flash_video_1080p_dropped_frames')
-
-
-class WebGLTest(BasePerfTest):
- """Tests for WebGL performance."""
-
- def _RunWebGLTest(self, url, description, graph_name):
- """Measures FPS using a specified WebGL demo.
-
- Args:
- url: The string URL that, once loaded, will run the WebGL demo (default
- WebGL demo settings are used, since this test does not modify any
- settings in the demo).
- description: A string description for this demo, used as a performance
- value description. Should not contain any spaces.
- graph_name: A string name for the performance graph associated with this
- test. Only used on Chrome desktop.
- """
- self.assertTrue(self.AppendTab(pyauto.GURL(url)),
- msg='Failed to append tab for %s.' % description)
-
- get_fps_js = """
- var fps_field = document.getElementById("fps");
- var result = -1;
- if (fps_field)
- result = fps_field.innerHTML;
- window.domAutomationController.send(JSON.stringify(result));
- """
-
- # Wait until we start getting FPS values.
- self.assertTrue(
- self.WaitUntil(
- lambda: self.ExecuteJavascript(get_fps_js, tab_index=1) != '-1',
- timeout=300, retry_sleep=1),
- msg='Timed out when waiting for FPS values to be available.')
-
- # Let the experiment run for 5 seconds before we start collecting perf
- # measurements.
- time.sleep(5)
-
- # Collect the current FPS value each second for the next 30 seconds. The
- # final result of this test will be the average of these FPS values.
- fps_vals = []
- for iteration in xrange(30):
- fps = self.ExecuteJavascript(get_fps_js, tab_index=1)
- fps = float(fps.replace('"', ''))
- fps_vals.append(fps)
- logging.info('Iteration %d of %d: %f FPS', iteration + 1, 30, fps)
- time.sleep(1)
- self._PrintSummaryResults(description, fps_vals, 'fps', graph_name)
-
- def testWebGLAquarium(self):
- """Measures performance using the WebGL Aquarium demo."""
- self._RunWebGLTest(
- self.GetFileURLForDataPath('pyauto_private', 'webgl', 'aquarium',
- 'aquarium.html'),
- 'WebGLAquarium', 'webgl_demo')
-
- def testWebGLField(self):
- """Measures performance using the WebGL Field demo."""
- self._RunWebGLTest(
- self.GetFileURLForDataPath('pyauto_private', 'webgl', 'field',
- 'field.html'),
- 'WebGLField', 'webgl_demo')
-
- def testWebGLSpaceRocks(self):
- """Measures performance using the WebGL SpaceRocks demo."""
- self._RunWebGLTest(
- self.GetFileURLForDataPath('pyauto_private', 'webgl', 'spacerocks',
- 'spacerocks.html'),
- 'WebGLSpaceRocks', 'webgl_demo')
-
-
-class GPUPerfTest(BasePerfTest):
- """Tests for GPU performance."""
-
- def setUp(self):
- """Performs necessary setup work before running each test in this class."""
- self._gpu_info_dict = self.EvalDataFrom(os.path.join(self.DataDir(),
- 'gpu', 'gpuperf.txt'))
- self._demo_name_url_dict = self._gpu_info_dict['demo_info']
- pyauto.PyUITest.setUp(self)
-
- def _MeasureFpsOverTime(self, tab_index=0):
- """Measures FPS using a specified demo.
-
- This function assumes that the demo is already loaded in the specified tab
- index.
-
- Args:
- tab_index: The tab index, default is 0.
- """
- # Let the experiment run for 5 seconds before we start collecting FPS
- # values.
- time.sleep(5)
-
- # Collect the current FPS value each second for the next 10 seconds.
- # Then return the average FPS value from among those collected.
- fps_vals = []
- for iteration in xrange(10):
- fps = self.GetFPS(tab_index=tab_index)
- fps_vals.append(fps['fps'])
- time.sleep(1)
- return Mean(fps_vals)
-
- def _GetStdAvgAndCompare(self, avg_fps, description, ref_dict):
- """Computes the average and compare set of values with reference data.
-
- Args:
- avg_fps: Average fps value.
- description: A string description for this demo, used as a performance
- value description.
- ref_dict: Dictionary which contains reference data for this test case.
-
- Returns:
- True, if the actual FPS value is within 10% of the reference FPS value,
- or False, otherwise.
- """
- std_fps = 0
- status = True
- # Load reference data according to platform.
- platform_ref_dict = None
- if self.IsWin():
- platform_ref_dict = ref_dict['win']
- elif self.IsMac():
- platform_ref_dict = ref_dict['mac']
- elif self.IsLinux():
- platform_ref_dict = ref_dict['linux']
- else:
- self.assertFail(msg='This platform is unsupported.')
- std_fps = platform_ref_dict[description]
- # Compare reference data to average fps.
- # We allow the average FPS value to be within 10% of the reference
- # FPS value.
- if avg_fps < (0.9 * std_fps):
- logging.info('FPS difference exceeds threshold for: %s', description)
- logging.info(' Average: %f fps', avg_fps)
- logging.info('Reference Average: %f fps', std_fps)
- status = False
- else:
- logging.info('Average FPS is actually greater than 10 percent '
- 'more than the reference FPS for: %s', description)
- logging.info(' Average: %f fps', avg_fps)
- logging.info(' Reference Average: %f fps', std_fps)
- return status
-
- def testLaunchDemosParallelInSeparateTabs(self):
- """Measures performance of demos in different tabs in same browser."""
- # Launch all the demos parallel in separate tabs
- counter = 0
- all_demos_passed = True
- ref_dict = self._gpu_info_dict['separate_tab_ref_data']
- # Iterate through dictionary and append all url to browser
- for url in self._demo_name_url_dict.iterkeys():
- self.assertTrue(
- self.AppendTab(pyauto.GURL(self._demo_name_url_dict[url])),
- msg='Failed to append tab for %s.' % url)
- counter += 1
- # Assert number of tab count is equal to number of tabs appended.
- self.assertEqual(self.GetTabCount(), counter + 1)
- # Measures performance using different demos and compare it golden
- # reference.
- for url in self._demo_name_url_dict.iterkeys():
- avg_fps = self._MeasureFpsOverTime(tab_index=counter)
- # Get the reference value of fps and compare the results
- if not self._GetStdAvgAndCompare(avg_fps, url, ref_dict):
- all_demos_passed = False
- counter -= 1
- self.assertTrue(
- all_demos_passed,
- msg='One or more demos failed to yield an acceptable FPS value')
-
- def testLaunchDemosInSeparateBrowser(self):
- """Measures performance by launching each demo in a separate tab."""
- # Launch demos in the browser
- ref_dict = self._gpu_info_dict['separate_browser_ref_data']
- all_demos_passed = True
- for url in self._demo_name_url_dict.iterkeys():
- self.NavigateToURL(self._demo_name_url_dict[url])
- # Measures performance using different demos.
- avg_fps = self._MeasureFpsOverTime()
- self.RestartBrowser()
- # Get the standard value of fps and compare the rseults
- if not self._GetStdAvgAndCompare(avg_fps, url, ref_dict):
- all_demos_passed = False
- self.assertTrue(
- all_demos_passed,
- msg='One or more demos failed to yield an acceptable FPS value')
-
- def testLaunchDemosBrowseForwardBackward(self):
- """Measures performance of various demos in browser going back and forth."""
- ref_dict = self._gpu_info_dict['browse_back_forward_ref_data']
- url_array = []
- desc_array = []
- all_demos_passed = True
- # Get URL/Description from dictionary and put in individual array
- for url in self._demo_name_url_dict.iterkeys():
- url_array.append(self._demo_name_url_dict[url])
- desc_array.append(url)
- for index in range(len(url_array) - 1):
- # Launch demo in the Browser
- if index == 0:
- self.NavigateToURL(url_array[index])
- # Measures performance using the first demo.
- avg_fps = self._MeasureFpsOverTime()
- status1 = self._GetStdAvgAndCompare(avg_fps, desc_array[index],
- ref_dict)
- # Measures performance using the second demo.
- self.NavigateToURL(url_array[index + 1])
- avg_fps = self._MeasureFpsOverTime()
- status2 = self._GetStdAvgAndCompare(avg_fps, desc_array[index + 1],
- ref_dict)
- # Go Back to previous demo
- self.TabGoBack()
- # Measures performance for first demo when moved back
- avg_fps = self._MeasureFpsOverTime()
- status3 = self._GetStdAvgAndCompare(
- avg_fps, desc_array[index] + '_backward',
- ref_dict)
- # Go Forward to previous demo
- self.TabGoForward()
- # Measures performance for second demo when moved forward
- avg_fps = self._MeasureFpsOverTime()
- status4 = self._GetStdAvgAndCompare(
- avg_fps, desc_array[index + 1] + '_forward',
- ref_dict)
- if not all([status1, status2, status3, status4]):
- all_demos_passed = False
- self.assertTrue(
- all_demos_passed,
- msg='One or more demos failed to yield an acceptable FPS value')
-
-
-class HTML5BenchmarkTest(BasePerfTest):
- """Tests for HTML5 performance."""
-
- def testHTML5Benchmark(self):
- """Measures performance using the benchmark at html5-benchmark.com."""
- self.NavigateToURL('http://html5-benchmark.com')
-
- start_benchmark_js = """
- benchmark();
- window.domAutomationController.send("done");
- """
- self.ExecuteJavascript(start_benchmark_js)
-
- js_final_score = """
- var score = "-1";
- var elem = document.getElementById("score");
- if (elem)
- score = elem.innerHTML;
- window.domAutomationController.send(score);
- """
- # Wait for the benchmark to complete, which is assumed to be when the value
- # of the 'score' DOM element changes to something other than '87485'.
- self.assertTrue(
- self.WaitUntil(
- lambda: self.ExecuteJavascript(js_final_score) != '87485',
- timeout=900, retry_sleep=1),
- msg='Timed out when waiting for final score to be available.')
-
- score = self.ExecuteJavascript(js_final_score)
- logging.info('HTML5 Benchmark final score: %f', float(score))
- self._OutputPerfGraphValue('HTML5Benchmark', float(score), 'score',
- 'html5_benchmark')
-
-
-class FileUploadDownloadTest(BasePerfTest):
- """Tests that involve measuring performance of upload and download."""
-
- def setUp(self):
- """Performs necessary setup work before running each test in this class."""
- self._temp_dir = tempfile.mkdtemp()
- self._test_server = PerfTestServer(self._temp_dir)
- self._test_server_port = self._test_server.GetPort()
- self._test_server.Run()
- self.assertTrue(self.WaitUntil(self._IsTestServerRunning),
- msg='Failed to start local performance test server.')
- BasePerfTest.setUp(self)
-
- def tearDown(self):
- """Performs necessary cleanup work after running each test in this class."""
- BasePerfTest.tearDown(self)
- self._test_server.ShutDown()
- pyauto_utils.RemovePath(self._temp_dir)
-
- def _IsTestServerRunning(self):
- """Determines whether the local test server is ready to accept connections.
-
- Returns:
- True, if a connection can be made to the local performance test server, or
- False otherwise.
- """
- conn = None
- try:
- conn = urllib2.urlopen('http://localhost:%d' % self._test_server_port)
- return True
- except IOError, e:
- return False
- finally:
- if conn:
- conn.close()
-
- def testDownload100MBFile(self):
- """Measures the time to download a 100 MB file from a local server."""
- CREATE_100MB_URL = (
- 'http://localhost:%d/create_file_of_size?filename=data&mb=100' %
- self._test_server_port)
- DOWNLOAD_100MB_URL = 'http://localhost:%d/data' % self._test_server_port
- DELETE_100MB_URL = ('http://localhost:%d/delete_file?filename=data' %
- self._test_server_port)
-
- # Tell the local server to create a 100 MB file.
- self.NavigateToURL(CREATE_100MB_URL)
-
- # Cleaning up downloaded files is done in the same way as in downloads.py.
- # We first identify all existing downloaded files, then remove only those
- # new downloaded files that appear during the course of this test.
- download_dir = self.GetDownloadDirectory().value()
- orig_downloads = []
- if os.path.isdir(download_dir):
- orig_downloads = os.listdir(download_dir)
-
- def _CleanupAdditionalFilesInDir(directory, orig_files):
- """Removes the additional files in the specified directory.
-
- This function will remove all files from |directory| that are not
- specified in |orig_files|.
-
- Args:
- directory: A string directory path.
- orig_files: A list of strings representing the original set of files in
- the specified directory.
- """
- downloads_to_remove = []
- if os.path.isdir(directory):
- downloads_to_remove = [os.path.join(directory, name)
- for name in os.listdir(directory)
- if name not in orig_files]
- for file_name in downloads_to_remove:
- pyauto_utils.RemovePath(file_name)
-
- def _DownloadFile(url):
- self.DownloadAndWaitForStart(url)
- self.WaitForAllDownloadsToComplete(timeout=2 * 60 * 1000) # 2 minutes.
-
- timings = []
- for iteration in range(self._num_iterations + 1):
- elapsed_time = self._MeasureElapsedTime(
- lambda: _DownloadFile(DOWNLOAD_100MB_URL), num_invocations=1)
- # Ignore the first iteration.
- if iteration:
- timings.append(elapsed_time)
- logging.info('Iteration %d of %d: %f milliseconds', iteration,
- self._num_iterations, elapsed_time)
- self.SetDownloadShelfVisible(False)
- _CleanupAdditionalFilesInDir(download_dir, orig_downloads)
-
- self._PrintSummaryResults('Download100MBFile', timings, 'milliseconds',
- 'download_file')
-
- # Tell the local server to delete the 100 MB file.
- self.NavigateToURL(DELETE_100MB_URL)
-
- def testUpload50MBFile(self):
- """Measures the time to upload a 50 MB file to a local server."""
- # TODO(dennisjeffrey): Replace the use of XMLHttpRequest in this test with
- # FileManager automation to select the upload file when crosbug.com/17903
- # is complete.
- START_UPLOAD_URL = (
- 'http://localhost:%d/start_upload?mb=50' % self._test_server_port)
-
- EXPECTED_SUBSTRING = 'Upload complete'
-
- def _IsUploadComplete():
- js = """
- result = "";
- var div = document.getElementById("upload_result");
- if (div)
- result = div.innerHTML;
- window.domAutomationController.send(result);
- """
- return self.ExecuteJavascript(js).find(EXPECTED_SUBSTRING) >= 0
-
- def _RunSingleUpload():
- self.NavigateToURL(START_UPLOAD_URL)
- self.assertTrue(
- self.WaitUntil(_IsUploadComplete, timeout=120, expect_retval=True,
- retry_sleep=0.10),
- msg='Upload failed to complete before the timeout was hit.')
-
- timings = []
- for iteration in range(self._num_iterations + 1):
- elapsed_time = self._MeasureElapsedTime(_RunSingleUpload)
- # Ignore the first iteration.
- if iteration:
- timings.append(elapsed_time)
- logging.info('Iteration %d of %d: %f milliseconds', iteration,
- self._num_iterations, elapsed_time)
-
- self._PrintSummaryResults('Upload50MBFile', timings, 'milliseconds',
- 'upload_file')
-
-
-class FlashTest(BasePerfTest):
- """Tests to measure flash performance."""
-
- def _RunFlashTestForAverageFPS(self, webpage_url, description, graph_name):
- """Runs a single flash test that measures an average FPS value.
-
- Args:
- webpage_url: The string URL to a webpage that will run the test.
- description: A string description for this test.
- graph_name: A string name for the performance graph associated with this
- test. Only used on Chrome desktop.
- """
- # Open up the test webpage; it's assumed the test will start automatically.
- self.assertTrue(self.AppendTab(pyauto.GURL(webpage_url)),
- msg='Failed to append tab for webpage.')
-
- # Wait until the final result is computed, then retrieve and output it.
- js = """
- window.domAutomationController.send(
- JSON.stringify(final_average_fps));
- """
- self.assertTrue(
- self.WaitUntil(
- lambda: self.ExecuteJavascript(js, tab_index=1) != '-1',
- timeout=300, expect_retval=True, retry_sleep=1),
- msg='Timed out when waiting for test result.')
- result = float(self.ExecuteJavascript(js, tab_index=1))
- logging.info('Result for %s: %f FPS (average)', description, result)
- self._OutputPerfGraphValue(description, result, 'FPS', graph_name)
-
- def testFlashGaming(self):
- """Runs a simple flash gaming benchmark test."""
- webpage_url = self.GetHttpURLForDataPath('pyauto_private', 'flash',
- 'FlashGamingTest2.html')
- self._RunFlashTestForAverageFPS(webpage_url, 'FlashGaming', 'flash_fps')
-
- def testFlashText(self):
- """Runs a simple flash text benchmark test."""
- webpage_url = self.GetHttpURLForDataPath('pyauto_private', 'flash',
- 'FlashTextTest2.html')
- self._RunFlashTestForAverageFPS(webpage_url, 'FlashText', 'flash_fps')
-
- def testScimarkGui(self):
- """Runs the ScimarkGui benchmark tests."""
- webpage_url = self.GetHttpURLForDataPath('pyauto_private', 'flash',
- 'scimarkGui.html')
- self.assertTrue(self.AppendTab(pyauto.GURL(webpage_url)),
- msg='Failed to append tab for webpage.')
-
- js = 'window.domAutomationController.send(JSON.stringify(tests_done));'
- self.assertTrue(
- self.WaitUntil(
- lambda: self.ExecuteJavascript(js, tab_index=1), timeout=300,
- expect_retval='true', retry_sleep=1),
- msg='Timed out when waiting for tests to complete.')
-
- js_result = """
- var result = {};
- for (var i = 0; i < tests_results.length; ++i) {
- var test_name = tests_results[i][0];
- var mflops = tests_results[i][1];
- var mem = tests_results[i][2];
- result[test_name] = [mflops, mem]
- }
- window.domAutomationController.send(JSON.stringify(result));
- """
- result = eval(self.ExecuteJavascript(js_result, tab_index=1))
- for benchmark in result:
- mflops = float(result[benchmark][0])
- mem = float(result[benchmark][1])
- if benchmark.endswith('_mflops'):
- benchmark = benchmark[:benchmark.find('_mflops')]
- logging.info('Results for ScimarkGui_%s:', benchmark)
- logging.info(' %f MFLOPS', mflops)
- logging.info(' %f MB', mem)
- self._OutputPerfGraphValue('ScimarkGui-%s-MFLOPS' % benchmark, mflops,
- 'MFLOPS', 'scimark_gui_mflops')
- self._OutputPerfGraphValue('ScimarkGui-%s-Mem' % benchmark, mem, 'MB',
- 'scimark_gui_mem')
-
-
-class LiveGamePerfTest(BasePerfTest):
- """Tests to measure performance of live gaming webapps."""
-
- def _RunLiveGamePerfTest(self, url, url_title_substring,
- description, graph_name):
- """Measures performance metrics for the specified live gaming webapp.
-
- This function connects to the specified URL to launch the gaming webapp,
- waits for a period of time for the webapp to run, then collects some
- performance metrics about the running webapp.
-
- Args:
- url: The string URL of the gaming webapp to analyze.
- url_title_substring: A string that is expected to be a substring of the
- webpage title for the specified gaming webapp. Used to verify that
- the webapp loads correctly.
- description: A string description for this game, used in the performance
- value description. Should not contain any spaces.
- graph_name: A string name for the performance graph associated with this
- test. Only used on Chrome desktop.
- """
- self.NavigateToURL(url)
- loaded_tab_title = self.GetActiveTabTitle()
- self.assertTrue(url_title_substring in loaded_tab_title,
- msg='Loaded tab title missing "%s": "%s"' %
- (url_title_substring, loaded_tab_title))
- cpu_usage_start = self._GetCPUUsage()
-
- # Let the app run for 1 minute.
- time.sleep(60)
-
- cpu_usage_end = self._GetCPUUsage()
- fraction_non_idle_time = self._GetFractionNonIdleCPUTime(
- cpu_usage_start, cpu_usage_end)
-
- logging.info('Fraction of CPU time spent non-idle: %f',
- fraction_non_idle_time)
- self._OutputPerfGraphValue(description + 'CpuBusy', fraction_non_idle_time,
- 'Fraction', graph_name + '_cpu_busy')
- v8_heap_stats = self.GetV8HeapStats()
- v8_heap_size = v8_heap_stats['v8_memory_used'] / (1024.0 * 1024.0)
- logging.info('Total v8 heap size: %f MB', v8_heap_size)
- self._OutputPerfGraphValue(description + 'V8HeapSize', v8_heap_size, 'MB',
- graph_name + '_v8_heap_size')
-
- def testAngryBirds(self):
- """Measures performance for Angry Birds."""
- self._RunLiveGamePerfTest('http://chrome.angrybirds.com', 'Angry Birds',
- 'AngryBirds', 'angry_birds')
-
-
-class BasePageCyclerTest(BasePerfTest):
- """Page class for page cycler tests.
-
- Derived classes must implement StartUrl().
-
- Environment Variables:
- PC_NO_AUTO: if set, avoids automatically loading pages.
- """
- MAX_ITERATION_SECONDS = 60
- TRIM_PERCENT = 20
- DEFAULT_USE_AUTO = True
-
- # Page Cycler lives in src/data/page_cycler rather than src/chrome/test/data
- DATA_PATH = os.path.abspath(
- os.path.join(BasePerfTest.DataDir(), os.pardir, os.pardir,
- os.pardir, 'data', 'page_cycler'))
-
- def setUp(self):
- """Performs necessary setup work before running each test."""
- super(BasePageCyclerTest, self).setUp()
- self.use_auto = 'PC_NO_AUTO' not in os.environ
-
- @classmethod
- def DataPath(cls, subdir):
- return os.path.join(cls.DATA_PATH, subdir)
-
- def ExtraChromeFlags(self):
- """Ensures Chrome is launched with custom flags.
-
- Returns:
- A list of extra flags to pass to Chrome when it is launched.
- """
- # Extra flags required to run these tests.
- # The first two are needed for the test.
- # The plugins argument is to prevent bad scores due to pop-ups from
- # running an old version of something (like Flash).
- return (super(BasePageCyclerTest, self).ExtraChromeFlags() +
- ['--js-flags="--expose_gc"',
- '--enable-file-cookies',
- '--allow-outdated-plugins'])
-
- def WaitUntilStarted(self, start_url):
- """Check that the test navigates away from the start_url."""
- js_is_started = """
- var is_started = document.location.href !== "%s";
- window.domAutomationController.send(JSON.stringify(is_started));
- """ % start_url
- self.assertTrue(
- self.WaitUntil(lambda: self.ExecuteJavascript(js_is_started) == 'true',
- timeout=10),
- msg='Timed out when waiting to leave start page.')
-
- def WaitUntilDone(self, url, iterations):
- """Check cookies for "__pc_done=1" to know the test is over."""
- def IsDone():
- cookies = self.GetCookie(pyauto.GURL(url)) # window 0, tab 0
- return '__pc_done=1' in cookies
- self.assertTrue(
- self.WaitUntil(
- IsDone,
- timeout=(self.MAX_ITERATION_SECONDS * iterations),
- retry_sleep=1),
- msg='Timed out waiting for page cycler test to complete.')
-
- def CollectPagesAndTimes(self, url):
- """Collect the results from the cookies."""
- pages, times = None, None
- cookies = self.GetCookie(pyauto.GURL(url)) # window 0, tab 0
- for cookie in cookies.split(';'):
- if '__pc_pages' in cookie:
- pages_str = cookie.split('=', 1)[1]
- pages = pages_str.split(',')
- elif '__pc_timings' in cookie:
- times_str = cookie.split('=', 1)[1]
- times = [float(t) for t in times_str.split(',')]
- self.assertTrue(pages and times,
- msg='Unable to find test results in cookies: %s' % cookies)
- return pages, times
-
- def IteratePageTimes(self, pages, times, iterations):
- """Regroup the times by the page.
-
- Args:
- pages: the list of pages
- times: e.g. [page1_iter1, page2_iter1, ..., page1_iter2, page2_iter2, ...]
- iterations: the number of times for each page
- Yields:
- (pageN, [pageN_iter1, pageN_iter2, ...])
- """
- num_pages = len(pages)
- num_times = len(times)
- expected_num_times = num_pages * iterations
- self.assertEqual(
- expected_num_times, num_times,
- msg=('num_times != num_pages * iterations: %s != %s * %s, times=%s' %
- (num_times, num_pages, iterations, times)))
- for i, page in enumerate(pages):
- yield page, list(itertools.islice(times, i, None, num_pages))
-
- def CheckPageTimes(self, pages, times, iterations):
- """Assert that all the times are greater than zero."""
- failed_pages = []
- for page, times in self.IteratePageTimes(pages, times, iterations):
- failed_times = [t for t in times if t <= 0.0]
- if failed_times:
- failed_pages.append((page, failed_times))
- if failed_pages:
- self.fail('Pages with unexpected times: %s' % failed_pages)
-
- def TrimTimes(self, times, percent):
- """Return a new list with |percent| number of times trimmed for each page.
-
- Removes the largest and smallest values.
- """
- iterations = len(times)
- times = sorted(times)
- num_to_trim = int(iterations * float(percent) / 100.0)
- logging.debug('Before trimming %d: %s' % (num_to_trim, times))
- a = num_to_trim / 2
- b = iterations - (num_to_trim / 2 + num_to_trim % 2)
- trimmed_times = times[a:b]
- logging.debug('After trimming: %s', trimmed_times)
- return trimmed_times
-
- def ComputeFinalResult(self, pages, times, iterations):
- """The final score that is calculated is a geometric mean of the
- arithmetic means of each page's load time, and we drop the
- upper/lower 20% of the times for each page so they don't skew the
- mean. The geometric mean is used for the final score because the
- time range for any given site may be very different, and we don't
- want slower sites to weight more heavily than others.
- """
- self.CheckPageTimes(pages, times, iterations)
- page_means = [
- Mean(self.TrimTimes(times, percent=self.TRIM_PERCENT))
- for _, times in self.IteratePageTimes(pages, times, iterations)]
- return GeometricMean(page_means)
-
- def StartUrl(self, test_name, iterations):
- """Return the URL to used to start the test.
-
- Derived classes must implement this.
- """
- raise NotImplemented
-
- def RunPageCyclerTest(self, name, description):
- """Runs the specified PageCycler test.
-
- Args:
- name: the page cycler test name (corresponds to a directory or test file)
- description: a string description for the test
- """
- iterations = self._num_iterations
- start_url = self.StartUrl(name, iterations)
- self.NavigateToURL(start_url)
- if self.use_auto:
- self.WaitUntilStarted(start_url)
- self.WaitUntilDone(start_url, iterations)
- pages, times = self.CollectPagesAndTimes(start_url)
- final_result = self.ComputeFinalResult(pages, times, iterations)
- logging.info('%s page cycler final result: %f' %
- (description, final_result))
- self._OutputPerfGraphValue(description + '_PageCycler', final_result,
- 'milliseconds', graph_name='PageCycler')
-
-
-class PageCyclerTest(BasePageCyclerTest):
- """Tests to run various page cyclers.
-
- Environment Variables:
- PC_NO_AUTO: if set, avoids automatically loading pages.
- """
-
- def _PreReadDataDir(self, subdir):
- """This recursively reads all of the files in a given url directory.
-
- The intent is to get them into memory before they are used by the benchmark.
-
- Args:
- subdir: a subdirectory of the page cycler data directory.
- """
- def _PreReadDir(dirname, names):
- for rfile in names:
- with open(os.path.join(dirname, rfile)) as fp:
- fp.read()
- for root, dirs, files in os.walk(self.DataPath(subdir)):
- _PreReadDir(root, files)
-
- def StartUrl(self, test_name, iterations):
- # Must invoke GetFileURLForPath before appending parameters to the URL,
- # otherwise those parameters will get quoted.
- start_url = self.GetFileURLForPath(self.DataPath(test_name), 'start.html')
- start_url += '?iterations=%d' % iterations
- if self.use_auto:
- start_url += '&auto=1'
- return start_url
-
- def RunPageCyclerTest(self, dirname, description):
- """Runs the specified PageCycler test.
-
- Args:
- dirname: directory containing the page cycler test
- description: a string description for the test
- """
- self._PreReadDataDir('common')
- self._PreReadDataDir(dirname)
- super(PageCyclerTest, self).RunPageCyclerTest(dirname, description)
-
- def testMoreJSFile(self):
- self.RunPageCyclerTest('morejs', 'MoreJSFile')
-
- def testAlexaFile(self):
- self.RunPageCyclerTest('alexa_us', 'Alexa_usFile')
-
- def testBloatFile(self):
- self.RunPageCyclerTest('bloat', 'BloatFile')
-
- def testDHTMLFile(self):
- self.RunPageCyclerTest('dhtml', 'DhtmlFile')
-
- def testIntl1File(self):
- self.RunPageCyclerTest('intl1', 'Intl1File')
-
- def testIntl2File(self):
- self.RunPageCyclerTest('intl2', 'Intl2File')
-
- def testMozFile(self):
- self.RunPageCyclerTest('moz', 'MozFile')
-
- def testMoz2File(self):
- self.RunPageCyclerTest('moz2', 'Moz2File')
-
-
-class MemoryTest(BasePerfTest):
- """Tests to measure memory consumption under different usage scenarios."""
-
- def ExtraChromeFlags(self):
- """Launches Chrome with custom flags.
-
- Returns:
- A list of extra flags to pass to Chrome when it is launched.
- """
- # Ensure Chrome assigns one renderer process to each tab.
- return super(MemoryTest, self).ExtraChromeFlags() + ['--process-per-tab']
-
- def _RecordMemoryStats(self, description, when, duration):
- """Outputs memory statistics to be graphed.
-
- Args:
- description: A string description for the test. Should not contain
- spaces. For example, 'MemCtrl'.
- when: A string description of when the memory stats are being recorded
- during test execution (since memory stats may be recorded multiple
- times during a test execution at certain "interesting" times). Should
- not contain spaces.
- duration: The number of seconds to sample data before outputting the
- memory statistics.
- """
- mem = self.GetMemoryStatsChromeOS(duration)
- measurement_types = [
- ('gem_obj', 'GemObj'),
- ('gtt', 'GTT'),
- ('mem_free', 'MemFree'),
- ('mem_available', 'MemAvail'),
- ('mem_shared', 'MemShare'),
- ('mem_cached', 'MemCache'),
- ('mem_anon', 'MemAnon'),
- ('mem_file', 'MemFile'),
- ('mem_slab', 'MemSlab'),
- ('browser_priv', 'BrowPriv'),
- ('browser_shared', 'BrowShar'),
- ('gpu_priv', 'GpuPriv'),
- ('gpu_shared', 'GpuShar'),
- ('renderer_priv', 'RendPriv'),
- ('renderer_shared', 'RendShar'),
- ]
- for type_key, type_string in measurement_types:
- if type_key not in mem:
- continue
- self._OutputPerfGraphValue(
- '%s-Min%s-%s' % (description, type_string, when),
- mem[type_key]['min'], 'KB', '%s-%s' % (description, type_string))
- self._OutputPerfGraphValue(
- '%s-Max%s-%s' % (description, type_string, when),
- mem[type_key]['max'], 'KB', '%s-%s' % (description, type_string))
- self._OutputPerfGraphValue(
- '%s-End%s-%s' % (description, type_string, when),
- mem[type_key]['end'], 'KB', '%s-%s' % (description, type_string))
-
- def _RunTest(self, tabs, description, duration):
- """Runs a general memory test.
-
- Args:
- tabs: A list of strings representing the URLs of the websites to open
- during this test.
- description: A string description for the test. Should not contain
- spaces. For example, 'MemCtrl'.
- duration: The number of seconds to sample data before outputting memory
- statistics.
- """
- self._RecordMemoryStats(description, '0Tabs0', duration)
-
- for iteration_num in xrange(2):
- for site in tabs:
- self.AppendTab(pyauto.GURL(site))
-
- self._RecordMemoryStats(description,
- '%dTabs%d' % (len(tabs), iteration_num + 1),
- duration)
-
- for _ in xrange(len(tabs)):
- self.CloseTab(tab_index=1)
-
- self._RecordMemoryStats(description, '0Tabs%d' % (iteration_num + 1),
- duration)
-
- def testOpenCloseTabsControl(self):
- """Measures memory usage when opening/closing tabs to about:blank."""
- tabs = ['about:blank'] * 10
- self._RunTest(tabs, 'MemCtrl', 15)
-
- def testOpenCloseTabsLiveSites(self):
- """Measures memory usage when opening/closing tabs to live sites."""
- tabs = [
- 'http://www.google.com/gmail',
- 'http://www.google.com/calendar',
- 'http://www.google.com/plus',
- 'http://www.google.com/youtube',
- 'http://www.nytimes.com',
- 'http://www.cnn.com',
- 'http://www.facebook.com/zuck',
- 'http://www.techcrunch.com',
- 'http://www.theverge.com',
- 'http://www.yahoo.com',
- ]
- # Log in to a test Google account to make connections to the above Google
- # websites more interesting.
- self._LoginToGoogleAccount()
- self._RunTest(tabs, 'MemLive', 20)
-
-
-class PerfTestServerRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
- """Request handler for the local performance test server."""
-
- def _IgnoreHandler(self, unused_args):
- """A GET request handler that simply replies with status code 200.
-
- Args:
- unused_args: A dictionary of arguments for the current GET request.
- The arguments are ignored.
- """
- self.send_response(200)
- self.end_headers()
-
- def _CreateFileOfSizeHandler(self, args):
- """A GET handler that creates a local file with the specified size.
-
- Args:
- args: A dictionary of arguments for the current GET request. Must
- contain 'filename' and 'mb' keys that refer to the name of the file
- to create and its desired size, respectively.
- """
- megabytes = None
- filename = None
- try:
- megabytes = int(args['mb'][0])
- filename = args['filename'][0]
- except (ValueError, KeyError, IndexError), e:
- logging.exception('Server error creating file: %s', e)
- assert megabytes and filename
- with open(os.path.join(self.server.docroot, filename), 'wb') as f:
- f.write('X' * 1024 * 1024 * megabytes)
- self.send_response(200)
- self.end_headers()
-
- def _DeleteFileHandler(self, args):
- """A GET handler that deletes the specified local file.
-
- Args:
- args: A dictionary of arguments for the current GET request. Must
- contain a 'filename' key that refers to the name of the file to
- delete, relative to the server's document root.
- """
- filename = None
- try:
- filename = args['filename'][0]
- except (KeyError, IndexError), e:
- logging.exception('Server error deleting file: %s', e)
- assert filename
- try:
- os.remove(os.path.join(self.server.docroot, filename))
- except OSError, e:
- logging.warning('OS error removing file: %s', e)
- self.send_response(200)
- self.end_headers()
-
- def _StartUploadHandler(self, args):
- """A GET handler to serve a page that uploads the given amount of data.
-
- When the page loads, the specified amount of data is automatically
- uploaded to the same local server that is handling the current request.
-
- Args:
- args: A dictionary of arguments for the current GET request. Must
- contain an 'mb' key that refers to the size of the data to upload.
- """
- megabytes = None
- try:
- megabytes = int(args['mb'][0])
- except (ValueError, KeyError, IndexError), e:
- logging.exception('Server error starting upload: %s', e)
- assert megabytes
- script = """
- <html>
- <head>
- <script type='text/javascript'>
- function startUpload() {
- var megabytes = %s;
- var data = Array((1024 * 1024 * megabytes) + 1).join('X');
- var boundary = '***BOUNDARY***';
- var xhr = new XMLHttpRequest();
-
- xhr.open('POST', 'process_upload', true);
- xhr.setRequestHeader(
- 'Content-Type',
- 'multipart/form-data; boundary="' + boundary + '"');
- xhr.setRequestHeader('Content-Length', data.length);
- xhr.onreadystatechange = function() {
- if (xhr.readyState == 4 && xhr.status == 200) {
- document.getElementById('upload_result').innerHTML =
- xhr.responseText;
- }
- };
- var body = '--' + boundary + '\\r\\n';
- body += 'Content-Disposition: form-data;' +
- 'file_contents=' + data;
- xhr.send(body);
- }
- </script>
- </head>
-
- <body onload="startUpload();">
- <div id='upload_result'>Uploading...</div>
- </body>
- </html>
- """ % megabytes
- self.send_response(200)
- self.end_headers()
- self.wfile.write(script)
-
- def _ProcessUploadHandler(self, form):
- """A POST handler that discards uploaded data and sends a response.
-
- Args:
- form: A dictionary containing posted form data, as returned by
- urlparse.parse_qs().
- """
- upload_processed = False
- file_size = 0
- if 'file_contents' in form:
- file_size = len(form['file_contents'][0])
- upload_processed = True
- self.send_response(200)
- self.end_headers()
- if upload_processed:
- self.wfile.write('Upload complete (%d bytes)' % file_size)
- else:
- self.wfile.write('No file contents uploaded')
-
- GET_REQUEST_HANDLERS = {
- 'create_file_of_size': _CreateFileOfSizeHandler,
- 'delete_file': _DeleteFileHandler,
- 'start_upload': _StartUploadHandler,
- 'favicon.ico': _IgnoreHandler,
- }
-
- POST_REQUEST_HANDLERS = {
- 'process_upload': _ProcessUploadHandler,
- }
-
- def translate_path(self, path):
- """Ensures files are served from the given document root.
-
- Overridden from SimpleHTTPServer.SimpleHTTPRequestHandler.
- """
- path = urlparse.urlparse(path)[2]
- path = posixpath.normpath(urllib.unquote(path))
- words = path.split('/')
- words = filter(None, words) # Remove empty strings from |words|.
- path = self.server.docroot
- for word in words:
- _, word = os.path.splitdrive(word)
- _, word = os.path.split(word)
- if word in (os.curdir, os.pardir):
- continue
- path = os.path.join(path, word)
- return path
-
- def do_GET(self):
- """Processes a GET request to the local server.
-
- Overridden from SimpleHTTPServer.SimpleHTTPRequestHandler.
- """
- split_url = urlparse.urlsplit(self.path)
- base_path = split_url[2]
- if base_path.startswith('/'):
- base_path = base_path[1:]
- args = urlparse.parse_qs(split_url[3])
- if base_path in self.GET_REQUEST_HANDLERS:
- self.GET_REQUEST_HANDLERS[base_path](self, args)
- else:
- SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
-
- def do_POST(self):
- """Processes a POST request to the local server.
-
- Overridden from SimpleHTTPServer.SimpleHTTPRequestHandler.
- """
- form = urlparse.parse_qs(
- self.rfile.read(int(self.headers.getheader('Content-Length'))))
- path = urlparse.urlparse(self.path)[2]
- if path.startswith('/'):
- path = path[1:]
- if path in self.POST_REQUEST_HANDLERS:
- self.POST_REQUEST_HANDLERS[path](self, form)
- else:
- self.send_response(200)
- self.send_header('Content-Type', 'text/plain')
- self.end_headers()
- self.wfile.write('No handler for POST request "%s".' % path)
-
-
-class ThreadedHTTPServer(SocketServer.ThreadingMixIn,
- BaseHTTPServer.HTTPServer):
- def __init__(self, server_address, handler_class):
- BaseHTTPServer.HTTPServer.__init__(self, server_address, handler_class)
-
-
-class PerfTestServer(object):
- """Local server for use by performance tests."""
-
- def __init__(self, docroot):
- """Initializes the performance test server.
-
- Args:
- docroot: The directory from which to serve files.
- """
- # The use of 0 means to start the server on an arbitrary available port.
- self._server = ThreadedHTTPServer(('', 0),
- PerfTestServerRequestHandler)
- self._server.docroot = docroot
- self._server_thread = threading.Thread(target=self._server.serve_forever)
-
- def Run(self):
- """Starts the server thread."""
- self._server_thread.start()
-
- def ShutDown(self):
- """Shuts down the server."""
- self._server.shutdown()
- self._server_thread.join()
-
- def GetPort(self):
- """Identifies the port number to which the server is currently bound.
-
- Returns:
- The numeric port number to which the server is currently bound.
- """
- return self._server.server_address[1]
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/perf/endure_graphs/config.js b/chrome/test/functional/perf/endure_graphs/config.js
deleted file mode 100644
index cb9fa3d..0000000
--- a/chrome/test/functional/perf/endure_graphs/config.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 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.
-
-var Config = {
- buildslave: 'Chrome Endure Bots',
- title: 'Chrome Endure Tests',
-};
diff --git a/chrome/test/functional/perf/endure_graphs/endure_plotter.html b/chrome/test/functional/perf/endure_graphs/endure_plotter.html
deleted file mode 100644
index 42072e7..0000000
--- a/chrome/test/functional/perf/endure_graphs/endure_plotter.html
+++ /dev/null
@@ -1,114 +0,0 @@
-<!--
- Copyright (c) 2012 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.
--->
-
-<!--
- HTML for a general Chrome Endure graph.
--->
-
-<html>
- <head>
- <style>
- body {
- font-family: sans-serif;
- }
- div#output {
- cursor: pointer;
- }
- div#switcher * {
- border: 1px solid black;
- border-radius: 4px 4px 0 0;
- padding-left: 0.5em;
- padding-right: 0.5em;
- }
- div#switcher a {
- background: #ddd;
- cursor: pointer;
- }
- canvas.plot {
- border: 1px solid black;
- }
- div.plot-coordinates {
- font-family: monospace;
- }
- iframe {
- display: none;
- width: 100%;
- height: 100%;
- border: none;
- }
- div.selected {
- border-left: none;
- }
- #explain {
- font-size: 0.75em;
- font-style: italic;
- color: rgb(100,100,100);
- }
- </style>
-
- <script src="js/common.js"></script>
- <script src="js/coordinates.js"></script>
- <script src="js/dom_utils.js"></script>
- <script src="js/graph_utils.js"></script>
- <script src="js/plotter.js"></script>
- <script src="config.js"></script>
-
- <script src="endure_plotter.js"></script>
- </head>
-
- <body>
- <div id="header_lookout" align="center">
- <font style='color: #0066FF; font-family: Arial, serif;
- font-size: 12pt; font-weight: bold;'>
- <script>
- document.write("<a target=\"_blank\" href=\"");
- document.write(get_url());
- document.write("\">");
- if ('graph' in params && params.graph != '')
- document.write(escape(params.graph));
- else
- document.write(Config.title);
- document.write("</a>");
- </script>
- </font>
- </div>
-
- <div id="header_text">
- Builds generated by the <i>
- <script>
- document.write(Config.buildslave);
- </script>
- </i> are run through <b>
- <script>
- document.write(Config.title);
- </script>
- </b> and the results of that test are charted here.
- </div>
-
- <div id="explain">
- More information about Chrome Endure can be found here:
- <a href="http://www.chromium.org/developers/testing/pyauto/perf/endure">
- http://www.chromium.org/developers/testing/pyauto/perf/endure</a>
- </div>
-
- <p></p>
-
- <div id="switcher"></div>
- <div id="output"></div> <br>
- <div id="revisions"></div> <br>
- <div id="comparisons"></div> <br>
- <div id="events"></div>
- <script>
- if ('lookout' in params) {
- document.getElementById("switcher").style.display = "none";
- document.getElementById("header_text").style.display = "none";
- document.getElementById("explain").style.display = "none";
- } else {
- document.getElementById("header_lookout").style.display = "none";
- }
- </script>
- </body>
-</html>
diff --git a/chrome/test/functional/perf/endure_graphs/endure_plotter.js b/chrome/test/functional/perf/endure_graphs/endure_plotter.js
deleted file mode 100644
index c7c90f7..0000000
--- a/chrome/test/functional/perf/endure_graphs/endure_plotter.js
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- Copyright (c) 2012 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.
-*/
-
-/**
- * @fileoverview Handles drawing a general Chrome Endure graph.
- */
-
-document.title = Config.title + ' - ' + Config.buildslave;
-
-var unitsX = 'unitsX';
-var unitsY = 'unitsY';
-var unitsYOther = null;
-var graphList = [];
-var revisionNumbers = [];
-var graphDataOtherRows = null;
-
-var eventRows = null;
-var eventTypes = [];
-var eventInfo = null;
-
-var params = ParseParams();
-
-/**
- * Encapsulates a *-summary.dat file.
- * @constructor
- *
- * @param {string} data Raw data from a *-summary.dat file.
- */
-function Rows(data) {
- this.rows = data.split('\n');
- this.length = this.rows.length;
-}
-
-/**
- * Returns the row at the given index.
- *
- * @param {number} i The index of a row of data from the *-summary.dat file.
- * @return {Object} An object representing a row of data from the input file.
- */
-Rows.prototype.get = function(i) {
- if (!this.rows[i].length) return null;
- var row = jsonToJs(this.rows[i]);
- row.revision = isNaN(row['rev']) ? row['rev'] : parseInt(row['rev']);
- return row;
-};
-
-/**
- * Gets the current URL, but without the 'lookout' parameter.
- *
- * @return {string} The current URL, but without the 'lookout' parameter.
- */
-function get_url() {
- new_url = window.location.href;
- new_url = new_url.replace(/\&lookout=1/, '');
- return new_url;
-}
-
-/**
- * Reports an error message on the webpage.
- *
- * @param {string} error An error message to display on the page.
- */
-function reportError(error) {
- document.getElementById('output').innerHTML = '<p>' + error + '</p>';
-}
-
-/**
- * Converts a JSON string into a Javascript object.
- *
- * @param {string} data A string in JSON format.
- * @return {Object} A Javascript object computed from the JSON string.
- */
-function jsonToJs(data) {
- return eval('(' + data + ')')
-}
-
-/**
- * Causes the page to navigate to another graph.
- *
- * @param {string} graph The name of the graph to which to navigate.
- */
-function goTo(graph) {
- params.graph = graph;
- window.location.href = MakeURL(params);
-}
-
-/**
- * Returns a function that will navigate the page to another graph.
- *
- * @param {string} graph The name of the graph to which to navigate.
- * @return {Function} A function that will navigate the page to another graph.
- */
-function goToClosure(graph) {
- return function(){goTo(graph)};
-}
-
-/**
- * Changes the event being overlayed on the graph.
- *
- * @param {string} eventName The name of the event to overlay on the graph.
- */
-function changeEventCompare(eventName) {
- delete params.revisionOther;
- delete params.graphOther;
- if (eventName == 'None') {
- delete params.event;
- window.location.href = MakeURL(params);
- } else {
- params.event = eventName;
- window.location.href = MakeURL(params);
- }
-}
-
-/**
- * Changes the other measurement being overlayed on top of an original line on
- * the graph.
- *
- * @param {string} graphName The name of the other graph to overlay on top of
- * the existing graph.
- */
-function changeMeasurementCompare(graphName) {
- delete params.revisionOther;
- delete params.event;
- if (graphName == 'None') {
- delete params.graphOther;
- window.location.href = MakeURL(params);
- } else {
- params.graphOther = graphName;
- window.location.href = MakeURL(params);
- }
-}
-
-/**
- * Changes the number of the other revision to compare against on the graph.
- *
- * @param {string} revision The revision number of the other line to plot on
- * the graph.
- */
-function changeRevisionCompare(revision) {
- delete params.graphOther;
- delete params.event;
- if (revision == 'None') {
- delete params.revisionOther;
- window.location.href = MakeURL(params);
- } else {
- params.revisionOther = revision;
- window.location.href = MakeURL(params);
- }
-}
-
-/**
- * Changes the displayed revision number of the graph line.
- *
- * @param {string} revision The revision number of the graph to display.
- */
-function changeRevision(revision) {
- delete params.revisionOther;
- delete params.graphOther;
- delete params.event;
- params.revision = revision;
- window.location.href = MakeURL(params);
-}
-
-/**
- * Initializes the UI for changing the revision number of the displayed graph.
- */
-function initRevisionOptions() {
- var html = '<table cellpadding=5><tr><td>';
- html += '<b>Chrome revision:</b>&nbsp;';
- html += '<select onchange=\"changeRevision(this.value)\">';
- for (var i = 0; i < revisionNumbers.length; ++i) {
- html += '<option id=\"r' + revisionNumbers[i] + '\"';
- if (revisionNumbers[i] == params.revision)
- html += 'selected=\"true\"';
- html += '>' + revisionNumbers[i] + '</option>';
- }
- html += '</select></td></tr></table>';
-
- document.getElementById('revisions').innerHTML = html;
-}
-
-/**
- * Initializes the UI for changing what is compared against the current line
- * on the displayed graph.
- */
-function initComparisonOptions() {
- var html = '<table cellpadding=5>';
- html += '<tr><td><b>Compare with (select one):</b></td></tr>';
-
- html += '<tr><td>&nbsp;&nbsp;&nbsp;Another run:&nbsp;';
- html += '<select onchange=\"changeRevisionCompare(this.value)\">';
- html += '<option selected=\"true\">None</option>';
- for (var i = 0; i < revisionNumbers.length; ++i) {
- html += '<option id=\"r' + revisionNumbers[i] + '\"';
- if (revisionNumbers[i] == params.revisionOther)
- html += 'selected=\"true\"';
- html += '>' + revisionNumbers[i] + '</option>';
- }
- html += '</select></td></tr>'
-
- html += '<tr><td>&nbsp;&nbsp;&nbsp;Another measurement of same run:&nbsp;';
- html += '<select onchange=\"changeMeasurementCompare(this.value)\">';
- html += '<option selected=\"true\">None</option>';
- for (var i = 0; i < graphList.length; ++i) {
- var graph = graphList[i];
- html += '<option id=\"r' + graph.name + '\"';
- if (graph.name == params.graphOther)
- html += 'selected=\"true\"';
- html += '>' + graph.name + '</option>';
- }
- html += '</select></td></tr>';
-
- html += '<tr><td>&nbsp;&nbsp;&nbsp;Event overlay:&nbsp;';
- if (eventTypes.length >= 1) {
- html += '<select onchange=\"changeEventCompare(this.value)\">';
- html += '<option selected=\"true\">None</option>';
- for (var i = 0; i < eventTypes.length; ++i) {
- var eventType = eventTypes[i];
- html += '<option id=\"' + eventType + '\"';
- if (eventType == params.event)
- html += 'selected=\"true\"';
- html += '>' + eventType + '</option>';
- }
- html += '</select>';
- } else {
- html += '&nbsp;<i><font size=-1>No events for this revision</font></i>';
- }
- html += '</td></tr></table>';
-
- document.getElementById('comparisons').innerHTML = html;
-}
-
-/**
- * Initializes the UI for the tabs at the top of a graph to change the displayed
- * line.
- */
-function initPlotSwitcher(tabs) {
- var switcher = document.getElementById('switcher');
- for (var i = 0; i < tabs.length; ++i) {
- var is_selected = tabs[i] == params.graph;
- var tab = document.createElement(is_selected ? 'span' : 'a');
- tab.appendChild(document.createTextNode(tabs[i] + ' '));
- if (!is_selected)
- tab.addEventListener('click', goToClosure(tabs[i]), false);
- switcher.appendChild(tab);
- }
-}
-
-/**
- * Adds data to existing arrays indicating what data should be plotted.
- *
- * @param {number} revisionNum The revision number of the data to plot.
- * @param {Rows} dataRows The |Rows| object containing the plot data.
- * @param {Array} plotData A list of data lines to plot, to which new data will
- * be appended.
- * @param {Array} dataDescriptions A list of string descriptions corresponding
- * to data lines in |plotData|, to which new data will be appended.
- * @return {Object} A row object specified by {@code revisionNum} on success,
- * otherwise returns null.
- */
-function addToPlotData(revisionNum, dataRows, plotData, dataDescriptions) {
- // Get data for the revision number(s) to plot.
- var found = false;
- for (var i = 0; i < dataRows.length; ++i) {
- var row = dataRows.get(i);
- if (row && row.revision == revisionNum) {
- found = true;
- break;
- }
- }
- if (!found) {
- return null;
- }
-
- if (row.stack) {
- if (!row.stack_order) {
- reportError('No stack order was specified.');
- return null;
- }
- var traceList = row.stack_order;
- } else {
- // Identify the (single) trace name associated with this revision.
- var traceName = null;
- for (var t in row.traces) {
- if (traceName) {
- reportError('Only one trace per revision is supported for ' +
- 'non-stacked graphs.');
- return null;
- }
- traceName = t;
- }
- var traceList = [traceName];
- }
-
- var lines = [];
- for (var i = 0, traceName; traceName = traceList[i]; ++i) {
- var trace = row.traces[traceName];
- if (!trace) {
- reportError('No specified trace was found.');
- return null;
- }
-
- var points = [];
- for (var j = 0, point; point = trace[j]; ++j) {
- points.push([parseFloat(point[0]), parseFloat(point[1])]);
- }
- lines.push(points);
- dataDescriptions.push(traceName + ' [r' + row.revision + ']');
- }
-
- if (row.stack) {
- lines = graphUtils.stackFrontToBack(graphUtils.interpolate(lines));
- }
-
- for (var i = 0, line; line = lines[i]; ++i) {
- plotData.push(line);
- }
-
- return row;
-}
-
-/**
- * Callback for when a *-summary.dat data file has been read.
- *
- * @param {string} data The string data from the inputted text file.
- * @param {string} error A string error message, in case an error occurred
- * during the file read.
- */
-function receivedSummary(data, error) {
- if (error) {
- reportError(error);
- return;
- }
-
- var errorMessages = '';
- var rows = new Rows(data);
-
- // Build and order a list of revision numbers.
- revisionNumbers = [];
- for (var i = 0; i < rows.length; ++i) {
- var row = rows.get(i);
- if (!row)
- continue;
- revisionNumbers.push(row.revision);
- }
- revisionNumbers.sort(
- function(a, b) { return parseInt(a, 10) - parseInt(b, 10) });
-
- // Get the revision number to plot.
- if (!('revision' in params) || params.revision == '') {
- if (revisionNumbers.length >= 2 && 'lookout' in params) {
- // Since the last graph (test run) might still be in progress, get the
- // second-to-last graph to display on the summary page. That one
- // is assumed to have finished running to completion.
- params.revision = revisionNumbers[revisionNumbers.length-2];
- } else {
- if (revisionNumbers.length >= 1) {
- params.revision = revisionNumbers[revisionNumbers.length-1];
- } else {
- reportError('No revision information to plot.');
- return;
- }
- }
- }
-
- var plotData = []; // plotData is a list of graph lines; each graph line is
- // a list of points; each point is a list of 2 values,
- // representing the (x, y) pair.
- var dataDescriptions = [];
-
- var row = addToPlotData(params.revision, rows, plotData, dataDescriptions);
- if (!row) {
- errorMessages += 'No data for the specified revision.<br>';
- }
- // From index {@code plotData.length} onwards, any graph lines in
- // {@code plotData} are considered to be part of a second set of graphs.
- var graphsOtherStartIndex = plotData.length;
-
- var rowOther = null;
- if ('revisionOther' in params) {
- rowOther = addToPlotData(params.revisionOther, rows, plotData,
- dataDescriptions);
- if (!rowOther)
- errorMessages += 'No data for the revision to compare against.<br>';
- }
-
- if ('graphOther' in params) {
- rowOther = addToPlotData(params.revision, graphDataOtherRows, plotData,
- dataDescriptions);
- if (rowOther) {
- for (var i = 0; i < graphList.length; ++i) {
- if (graphList[i].name == params.graphOther) {
- unitsYOther = graphList[i].units;
- break;
- }
- }
- } else {
- errorMessages += 'No data for the measurement to compare against.<br>';
- }
- }
-
- // Identify the events for the current revision.
- if (eventRows) {
- for (var index = 0; index < eventRows.length; ++index) {
- var info = eventRows.get(index);
- if (params.revision == info['rev']) {
- eventInfo = info;
- break;
- }
- }
- if (eventInfo != null) {
- for (var key in eventInfo['events']) {
- eventTypes.push(key);
- }
- }
- }
-
- // Get data for the events to display, if one was requested in the params.
- var eventNameToPlot = null;
- var eventInfoToPlot = null;
- if ('event' in params && eventInfo != null) {
- for (var key in eventInfo['events']) {
- if (key == params['event']) {
- eventInfoToPlot = eventInfo['events'][key];
- eventNameToPlot = key;
- }
- }
- }
-
- // Draw everything.
- if (errorMessages == '') {
- var plotter = new Plotter(
- plotData,
- dataDescriptions,
- eventNameToPlot, eventInfoToPlot,
- unitsX, unitsY, unitsYOther, graphsOtherStartIndex,
- document.getElementById('output'),
- 'lookout' in params,
- !!row.stack,
- rowOther && !!rowOther.stack);
-
- plotter.plot();
- } else {
- errorMessages = '<br><br><br><table border=2 cellpadding=5><tr><td>' +
- errorMessages + '</td></tr></table><br><br>';
- document.getElementById('output').innerHTML = errorMessages;
- }
-
- if (!('lookout' in params)) {
- initRevisionOptions();
- initComparisonOptions();
- }
-}
-
-/**
- * Callback for when a second *-summary.dat data file has been read, in the
- * event that a second graph line is being overlayed on top of an existing
- * graph line.
- *
- * @param {string} data The string data from the inputted text file.
- * @param {string} error A string error message, in case an error occurred
- * during the file read.
- */
-function receivedSummaryGraphOther(data, error) {
- if (error) {
- reportError(error);
- return;
- }
-
- graphDataOtherRows = new Rows(data);
- Fetch(escape(params.graph) + '-summary.dat', receivedSummary);
-}
-
-/**
- * Callback for when an event info file has been read.
- *
- * @param {string} data The string data from the inputted text file.
- * @param {string} error A string error message, in case an error occurred
- * during the file read.
- */
-function receivedEvents(data, error) {
- if (!error)
- eventRows = new Rows(data);
- fetchSummary();
-}
-
-/**
- * Callback for when a graphs.dat data file has been read.
- *
- * @param {string} data The string data from the inputted text file.
- * @param {string} error A string error message, in case an error occurred
- * during the file read.
- */
-function receivedGraphList(data, error) {
- if (error) {
- reportError(error);
- return;
- }
- graphList = jsonToJs(data);
-
- if (!('graph' in params) || params.graph == '')
- if (graphList.length > 0)
- params.graph = graphList[0].name
-
- // Add a selection tab for each graph, and find the units for the selected
- // one while we're at it.
- tabs = [];
- for (var index = 0; index < graphList.length; ++index) {
- var graph = graphList[index];
- tabs.push(graph.name);
- if (graph.name == params.graph) {
- unitsX = graph.units_x;
- unitsY = graph.units;
- }
- }
- initPlotSwitcher(tabs);
-
- fetchEvents();
-}
-
-/**
- * Starts fetching a *-summary.dat file.
- */
-function fetchSummary() {
- if ('graphOther' in params) {
- // We need to overlay a second graph over the first one, so we need to
- // fetch that summary data too. Do it first.
- Fetch(escape(params.graphOther) + '-summary.dat',
- receivedSummaryGraphOther);
- } else {
- Fetch(escape(params.graph) + '-summary.dat',
- receivedSummary);
- }
-}
-
-/**
- * Starts fetching an event info file.
- */
-function fetchEvents() {
- Fetch('_EVENT_-summary.dat', receivedEvents);
-}
-
-/**
- * Starts fetching a graphs.dat file.
- */
-function fetchGraphList() {
- Fetch('graphs.dat', receivedGraphList);
-}
-
-window.addEventListener('load', fetchGraphList, false);
diff --git a/chrome/test/functional/perf/endure_graphs/js/common.js b/chrome/test/functional/perf/endure_graphs/js/common.js
deleted file mode 100644
index 96399dc..0000000
--- a/chrome/test/functional/perf/endure_graphs/js/common.js
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- Copyright (c) 2012 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.
-*/
-
-/**
- * @fileoverview Common methods for performance-plotting Javascript.
- */
-
-/**
- * Fetches a URL asynchronously and invokes a callback when complete.
- *
- * @param {string} url URL to fetch.
- * @param {Function(string, string)} callback The function to invoke when the
- * results of the URL fetch are complete. The function should accept two
- * strings representing the URL data, and any errors, respectively.
- */
-function Fetch(url, callback) {
- var r = new XMLHttpRequest();
- r.open('GET', url, true);
- r.setRequestHeader('pragma', 'no-cache');
- r.setRequestHeader('cache-control', 'no-cache');
-
- r.onreadystatechange = function() {
- if (r.readyState == 4) {
- var text = r.responseText;
- var error;
- if (r.status != 200)
- error = url + ': ' + r.status + ': ' + r.statusText;
- else if (!text)
- error = url + ': null response';
- callback(text, error);
- }
- }
-
- r.send(null);
-}
-
-/**
- * Parses the parameters of the current page's URL.
- *
- * @return {Object} An object with properties given by the parameters specified
- * in the URL's query string.
- */
-function ParseParams() {
- var result = new Object();
-
- var query = window.location.search.substring(1)
- if (query.charAt(query.length - 1) == '/')
- query = query.substring(0, query.length - 1) // Strip trailing slash.
- var s = query.split('&');
-
- for (i = 0; i < s.length; ++i) {
- var v = s[i].split('=');
- var key = v[0];
- var value = unescape(v[1]);
- result[key] = value;
- }
-
- if ('history' in result) {
- result['history'] = parseInt(result['history']);
- result['history'] = Math.max(result['history'], 2);
- }
- if ('rev' in result) {
- result['rev'] = parseInt(result['rev']);
- result['rev'] = Math.max(result['rev'], -1);
- }
-
- return result;
-}
-
-/**
- * Creates the URL constructed from the current pathname and the given params.
- *
- * @param {Object} An object containing parameters for a URL query string.
- * @return {string} The URL constructed from the given params.
- */
-function MakeURL(params) {
- var url = window.location.pathname;
- var sep = '?';
- for (p in params) {
- if (!p)
- continue;
- url += sep + p + '=' + params[p];
- sep = '&';
- }
- return url;
-}
diff --git a/chrome/test/functional/perf/endure_graphs/js/coordinates.js b/chrome/test/functional/perf/endure_graphs/js/coordinates.js
deleted file mode 100644
index a1e4219..0000000
--- a/chrome/test/functional/perf/endure_graphs/js/coordinates.js
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- Copyright (c) 2012 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.
-*/
-
-/**
- * @fileoverview Class and functions to handle positioning of plot data points.
- */
-
-/**
- * Class that handles plot data positioning.
- * @constructor
- *
- * @param {Array} plotData Data that will be plotted. It is an array of lines,
- * where each line is an array of points, and each point is a length-2 array
- * representing an (x, y) pair.
- */
-function Coordinates(plotData) {
- this.plotData = plotData;
-
- height = window.innerHeight - 16;
- width = window.innerWidth - 16;
-
- this.widthMax = width;
- this.heightMax = Math.min(400, height - 85);
-
- this.processValues_('x');
- this.processValues_('y');
-}
-
-/**
- * Determines the min/max x or y values in the plot, accounting for some extra
- * buffer space.
- *
- * @param {string} type The type of value to process, either 'x' or 'y'.
- */
-Coordinates.prototype.processValues_ = function (type) {
- var merged = [];
- for (var i = 0; i < this.plotData.length; i++)
- for (var j = 0; j < this.plotData[i].length; j++) {
- if (type == 'x')
- merged.push(parseFloat(this.plotData[i][j][0])); // Index 0 is x value.
- else
- merged.push(parseFloat(this.plotData[i][j][1])); // Index 1 is y value.
- }
-
- min = merged[0];
- max = merged[0];
- for (var i = 1; i < merged.length; ++i) {
- if (isNaN(min) || merged[i] < min)
- min = merged[i];
- if (isNaN(max) || merged[i] > max)
- max = merged[i];
- }
-
- var bufferSpace = 0.02 * (max - min);
-
- if (type == 'x') {
- this.xBufferSpace_ = bufferSpace;
- this.xMinValue_ = min;
- this.xMaxValue_ = max;
- } else {
- this.yBufferSpace_ = bufferSpace;
- this.yMinValue_ = min;
- this.yMaxValue_ = max;
- }
-};
-
-/**
- * Difference between horizontal upper and lower limit values.
- *
- * @return {number} The x value range.
- */
-Coordinates.prototype.xValueRange = function() {
- return this.xUpperLimitValue() - this.xLowerLimitValue();
-};
-
-/**
- * Difference between vertical upper and lower limit values.
- *
- * @return {number} The y value range.
- */
-Coordinates.prototype.yValueRange = function() {
- return this.yUpperLimitValue() - this.yLowerLimitValue();
-};
-
-/**
- * Converts horizontal data value to pixel value on canvas.
- *
- * @param {number} value The x data value.
- * @return {number} The corresponding x pixel value on the canvas.
- */
-Coordinates.prototype.xPixel = function(value) {
- return this.widthMax *
- ((value - this.xLowerLimitValue()) / this.xValueRange());
-};
-
-/**
- * Converts vertical data value to pixel value on canvas.
- *
- * @param {number} value The y data value.
- * @return {number} The corresponding y pixel value on the canvas.
- */
-Coordinates.prototype.yPixel = function(value) {
- if (this.yValueRange() == 0) {
- // Completely horizontal lines should be centered horizontally.
- return this.heightMax / 2;
- } else {
- return this.heightMax -
- (this.heightMax *
- (value - this.yLowerLimitValue()) / this.yValueRange());
- }
-};
-
-/**
- * Converts x point on canvas to data value it represents.
- *
- * @param {number} position The x pixel value on the canvas.
- * @return {number} The corresponding x data value.
- */
-Coordinates.prototype.xValue = function(position) {
- return this.xLowerLimitValue() +
- (position / this.widthMax * this.xValueRange());
-};
-
-/**
- * Converts y point on canvas to data value it represents.
- *
- * @param {number} position The y pixel value on the canvas.
- * @return {number} The corresponding y data value.
- */
-Coordinates.prototype.yValue = function(position) {
- var ratio = this.heightMax / (this.heightMax - position);
- return this.yLowerLimitValue() + (this.yValueRange() / ratio);
-};
-
-/**
- * Returns the minimum x value of all the data points.
- *
- * @return {number} The minimum x value of all the data points.
- */
-Coordinates.prototype.xMinValue = function() {
- return this.xMinValue_;
-};
-
-/**
- * Returns the maximum x value of all the data points.
- *
- * @return {number} The maximum x value of all the data points.
- */
-Coordinates.prototype.xMaxValue = function() {
- return this.xMaxValue_;
-};
-
-/**
- * Returns the minimum y value of all the data points.
- *
- * @return {number} The minimum y value of all the data points.
- */
-Coordinates.prototype.yMinValue = function() {
- return this.yMinValue_;
-};
-
-/**
- * Returns the maximum y value of all the data points.
- *
- * @return {number} The maximum y value of all the data points.
- */
-Coordinates.prototype.yMaxValue = function() {
- return this.yMaxValue_;
-};
-
-/**
- * Returns the x value at the lower limit of the bounding box of the canvas.
- *
- * @return {number} The x value at the lower limit of the bounding box of
- * the canvas.
- */
-Coordinates.prototype.xLowerLimitValue = function() {
- return this.xMinValue_ - this.xBufferSpace_;
-};
-
-/**
- * Returns the x value at the upper limit of the bounding box of the canvas.
- *
- * @return {number} The x value at the upper limit of the bounding box of
- * the canvas.
- */
-Coordinates.prototype.xUpperLimitValue = function() {
- return this.xMaxValue_ + this.xBufferSpace_;
-};
-
-/**
- * Returns the y value at the lower limit of the bounding box of the canvas.
- *
- * @return {number} The y value at the lower limit of the bounding box of
- * the canvas.
- */
-Coordinates.prototype.yLowerLimitValue = function() {
- return this.yMinValue_ - this.yBufferSpace_;
-};
-
-/**
- * Returns the y value at the upper limit of the bounding box of the canvas.
- *
- * @return {number} The y value at the upper limit of the bounding box of
- * the canvas.
- */
-Coordinates.prototype.yUpperLimitValue = function() {
- return this.yMaxValue_ + this.yBufferSpace_;
-};
diff --git a/chrome/test/functional/perf/endure_graphs/js/dom_utils.js b/chrome/test/functional/perf/endure_graphs/js/dom_utils.js
deleted file mode 100644
index 09158c3..0000000
--- a/chrome/test/functional/perf/endure_graphs/js/dom_utils.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- Copyright (c) 2012 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.
-*/
-
-/**
- * @fileoverview Collection of functions which operate on DOM.
- */
-
-var domUtils = window['domUtils'] || {};
-
-/**
- * Returns pageX and pageY of the given element.
- *
- * @param {Element} element An element of which the top-left position is to be
- * returned in the coordinate system of the document page.
- * @return {Object} A point object which has {@code x} and {@code y} fields.
- */
-domUtils.pageXY = function(element) {
- var x = 0, y = 0;
- for (; element; element = element.offsetParent) {
- x += element.offsetLeft;
- y += element.offsetTop;
- }
- return {'x': x, 'y': y};
-};
-
-/**
- * Returns pageX and pageY of the given event.
- *
- * @param {Event} event An event of which the position is to be returned in
- * the coordinate system of the document page.
- * @return {Object} A point object which has {@code x} and {@code y} fields.
- */
-domUtils.pageXYOfEvent = function(event) {
- return (event.pageX != null && event.pageY != null) ?
- {'x': event.pageX, 'y': event.pageY} :
- {'x': event.clientX + document.body.scrollLeft +
- document.documentElement.scrollLeft,
- 'y': event.clientY + document.body.scrollTop +
- document.documentElement.scrollTop};
-};
diff --git a/chrome/test/functional/perf/endure_graphs/js/graph_utils.js b/chrome/test/functional/perf/endure_graphs/js/graph_utils.js
deleted file mode 100644
index ad5c83d..0000000
--- a/chrome/test/functional/perf/endure_graphs/js/graph_utils.js
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- Copyright (c) 2012 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.
-*/
-
-/**
- * @fileoverview Collection of functions which operate on graph data.
- */
-
-var graphUtils = window['graphUtils'] || {};
-
-/**
- * Interpolate given multiple lines of graphs, and returns the lines of
- * the graphs where each line has the same number of points and x coordinates.
- *
- * For example,
- * <pre>
- * [[[0, 1], [2, 3]], // 1st line
- * [[1, 3]]] // 2nd line
- * </pre>
- * will be converted to
- * <pre>
- * [[[0, 1], [1, 2], [2, 3]], // [1, 2] is interpolated.
- * [[0, 0], [1, 3], [2, 0]]] // [0, 0] and [2, 0] are interpolated.
- * </pre>
- * where every line has points at x=0, 1 and 2.
- * Interpolated data points are marked with a property
- * {@code point.interpolated == true}.
- *
- * @param {Array.<Array.<Array.<number>>>} plotData List of arrays that
- * represent individual lines. The line itself is an Array of points.
- * @return {Array.<Array.<Array.<number>>>} An interpolated {@code plotData}.
- * The original {@code plotData} is not affected.
- */
-graphUtils.interpolate = function(plotData) {
- var interpolated = []; // resulting interpolated {@code plotData}
- var unconsumed = []; // indices to unconsumed points in {@code plotData}
- for (var i = 0; i < plotData.length; ++i) {
- interpolated.push([]);
- unconsumed.push(0);
- }
-
- // Returns the next x-coordinate to interpolate if any, or null.
- function nextX() {
- var index = null;
- for (var i = 0; i < unconsumed.length; ++i) {
- if (0 <= unconsumed[i] && unconsumed[i] < plotData[i].length &&
- (index == null ||
- plotData[i][unconsumed[i]][0] <
- plotData[index][unconsumed[index]][0])) {
- index = i;
- }
- }
- return index == null ? null : plotData[index][unconsumed[index]][0];
- }
-
- for (var x = nextX(); x != null; x = nextX()) { // for all x
- for (var i = 0; i < plotData.length; ++i) { // for all lines
- var y = 0;
- var hasPoint = false;
- if (0 <= unconsumed[i] && unconsumed[i] < plotData[i].length) {
- var p = plotData[i][unconsumed[i]];
- if (p[0] <= x) {
- y = p[1]; // The original line has a point at x.
- hasPoint = true;
- } else if (unconsumed[i] == 0) {
- y = 0; // y = 0 before the first point
- } else {
- // Interpolate a point.
- var p0 = plotData[i][unconsumed[i] - 1];
- y = (x - p0[0]) / (p[0] - p0[0]) * (p[1] - p0[1]) + p0[1];
- }
- } // else y = 0 because it's out of range.
-
- var point = [x, y];
- if (!hasPoint) {
- point.interpolated = true;
- }
- interpolated[i].push(point);
- }
-
- // Consume {@code plotData} by incrementing indices in {@code unconsumed}.
- for (var i = 0; i < unconsumed.length; ++i) {
- if (0 <= unconsumed[i] && unconsumed[i] < plotData[i].length &&
- plotData[i][unconsumed[i]][0] <= x) {
- ++unconsumed[i];
- }
- }
- }
-
- return interpolated;
-};
-
-/**
- * Creates and returns a set of stacked graphs, assuming the given
- * {@code plotData} is interpolated by {@code graphUtils.interpolate}.
- *
- * For example,
- * <pre>
- * [[[0, 1], [1, 2]], // 1st line
- * [[0, 1], [1, 3]], // 2nd line
- * [[0, 2], [1, 1]]] // 3rd line
- * </pre>
- * will be converted to
- * <pre>
- * [[[0, 1], [1, 2]], // 1st
- * [[0, 2], [1, 5]], // 1st + 2nd
- * [[0, 4], [1, 6]]] // 1st + 2nd + 3rd
- * </pre>
- *
- * @param {Array.<Array.<Array.<number>>>} plotData List of arrays that
- * represent individual lines. The line itself is an Array of points.
- * @return {Array.<Array.<Array.<number>>>} A stacked {@code plotData}.
- * The original {@code plotData} is not affected.
- */
-graphUtils.stackFrontToBack = function(plotData) {
- if (!(plotData && plotData[0] && plotData[0].length > 0)) {
- return [];
- }
-
- var stacked = [];
- for (var i = 0; i < plotData.length; ++i) {
- stacked.push([]);
- }
-
- for (var j = 0; j < plotData[0].length; ++j) {
- for (var i = 0; i < plotData.length; ++i) {
- var point = [
- plotData[i][j][0],
- plotData[i][j][1] +
- (i == 0 ? 0 : stacked[i - 1][j][1])];
- if (plotData[i][j].interpolated) {
- point.interpolated = true;
- }
- stacked[i].push(point);
- }
- }
-
- return stacked;
-};
diff --git a/chrome/test/functional/perf/endure_graphs/js/plotter.js b/chrome/test/functional/perf/endure_graphs/js/plotter.js
deleted file mode 100644
index edbbf11..0000000
--- a/chrome/test/functional/perf/endure_graphs/js/plotter.js
+++ /dev/null
@@ -1,1199 +0,0 @@
-/*
- Copyright (c) 2012 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.
-*/
-
-/**
- * @fileoverview Collection of functions and classes used to plot data in a
- * <canvas>. Create a Plotter() to generate a plot.
- */
-
-/**
- * Adds commas to a given number.
- *
- * Examples:
- * 1234.56 => "1,234.56"
- * 99999 => "99,999"
- *
- * @param {string|number} number The number to format.
- * @return {string} String representation of |number| with commas for every
- * three digits to the left of a decimal point.
- */
-function addCommas(number) {
- number += ''; // Convert number to string if not already a string.
- var numberParts = number.split('.');
- var integralPart = numberParts[0];
- var fractionalPart = numberParts.length > 1 ? '.' + numberParts[1] : '';
- var reThreeDigits = /(\d+)(\d{3})/;
- while (reThreeDigits.test(integralPart))
- integralPart = integralPart.replace(reThreeDigits, '$1' + ',' + '$2');
- return integralPart + fractionalPart;
-}
-
-/**
- * Vertical marker to highlight data points that are being hovered over by the
- * mouse.
- *
- * @param {string} color The color to make the marker, e.g., 'rgb(100,80,240)'.
- * @return {Element} A div Element object representing the vertical marker.
- */
-function VerticalMarker(color) {
- var m = document.createElement('div');
- m.style.backgroundColor = color;
- m.style.opacity = '0.3';
- m.style.position = 'absolute';
- m.style.left = '-2px';
- m.style.top = '-2px';
- m.style.width = '0px';
- m.style.height = '0px';
- return m;
-}
-
-/**
- * Class representing a horizontal marker at the indicated mouse location.
- * @constructor
- *
- * @param {Element} canvasElement The canvas bounds.
- * @param {Number} yValue The data value corresponding to the vertical click
- * location.
- * @param {Number} yOtherValue If the plot is overlaying two coordinate systems,
- * this is the data value corresponding to the vertical click location in
- * the second coordinate system. Can be null.
- */
-function HorizontalMarker(canvasElement, yValue, yOtherValue) {
- var m = document.createElement('div');
- m.style.backgroundColor = HorizontalMarker.COLOR;
- m.style.opacity = '0.3';
- m.style.position = 'absolute';
- m.style.width = canvasElement.offsetWidth + 'px';
- m.style.height = HorizontalMarker.HEIGHT + 'px';
-
- this.markerDiv = m;
- this.value = yValue;
- this.otherValue = yOtherValue;
-}
-
-HorizontalMarker.HEIGHT = 5;
-HorizontalMarker.COLOR = 'rgb(0,100,100)';
-
-/**
- * Locates this element at a specified position.
- *
- * @param {Element} canvasElement The canvas element at which this element is
- * to be placed.
- * @param {number} y Y position relative to the canvas element.
- */
-HorizontalMarker.prototype.locateAt = function(canvasElement, y) {
- var div = this.markerDiv;
- div.style.left = domUtils.pageXY(canvasElement).x -
- domUtils.pageXY(div.offsetParent) + 'px';
- div.style.top = (y + domUtils.pageXY(canvasElement).y
- - domUtils.pageXY(div.offsetParent).y
- - (HorizontalMarker.HEIGHT / 2)) + 'px';
-};
-
-/**
- * Removes the horizontal marker from the graph.
- */
-HorizontalMarker.prototype.remove = function() {
- this.markerDiv.parentNode.removeChild(this.markerDiv);
-};
-
-/**
- * An information indicator hovering around the mouse cursor on the graph.
- * This class is used to show a legend near the mouse cursor.
- *
- * A set of legends under the graph is managed separately in
- * {@code Plotter.createLegendsSummaryElement_}.
- *
- * @constructor
- */
-function HoveringInfo() {
- this.containerDiv_ = document.createElement('div');
- this.containerDiv_.style.display = 'none';
- this.containerDiv_.style.position = 'absolute';
- this.containerDiv_.style.border = '1px solid #000';
- this.containerDiv_.style.padding = '0.12em';
- this.containerDiv_.style.backgroundColor = '#ddd';
- this.colorIndicator_ = document.createElement('div');
- this.colorIndicator_.style.display = 'inline-block';
- this.colorIndicator_.style.width = '1em';
- this.colorIndicator_.style.height = '1em';
- this.colorIndicator_.style.verticalAlign = 'text-bottom';
- this.colorIndicator_.style.margin = '0 0.24em 0 0';
- this.colorIndicator_.style.border = '1px solid #000';
- this.legendText_ = document.createElement('span');
- this.itemValueText_ = document.createElement('span');
-
- this.containerDiv_.appendChild(this.colorIndicator_);
- this.containerDiv_.appendChild(this.legendText_);
- var div = document.createElement('div');
- div.appendChild(this.itemValueText_);
- this.containerDiv_.appendChild(div);
-}
-
-/**
- * Returns the container element;
- *
- * @return {Element} The container element.
- */
-HoveringInfo.prototype.getElement = function() {
- return this.containerDiv_;
-};
-
-/**
- * Shows or hides the element.
- *
- * @param {boolean} show Shows the element if true, or hides it.
- */
-HoveringInfo.prototype.show = function(show) {
- this.containerDiv_.style.display = show ? 'block' : 'none';
-};
-
-/**
- * Returns the position of the container element in the page coordinate.
- *
- * @return {Object} A point object which has {@code x} and {@code y} fields.
- */
-HoveringInfo.prototype.pageXY = function() {
- return domUtils.pageXY(this.containerDiv_);
-};
-
-/**
- * Locates the element at the specified position.
- *
- * @param {number} x X position in the page coordinate.
- * @param {number} y Y position in the page coordinate.
- */
-HoveringInfo.prototype.locateAtPageXY = function(x, y) {
- var parentXY = domUtils.pageXY(this.containerDiv_.offsetParent);
- this.containerDiv_.style.left = x - parentXY.x + 'px';
- this.containerDiv_.style.top = y - parentXY.y + 'px';
-};
-
-/**
- * Returns the legend text.
- *
- * @return {?string} The legend text.
- */
-HoveringInfo.prototype.getLegendText = function() {
- return this.legendText_.textContent;
-};
-
-/**
- * Changes the legend text.
- *
- * @param {string} text The new text to be set.
- */
-HoveringInfo.prototype.setLegendText = function(text) {
- this.legendText_.textContent = text;
-};
-
-/**
- * Changes the item value.
- *
- * @param {number} value The new value to be shown.
- */
-HoveringInfo.prototype.setItemValue = function(value) {
- this.itemValueText_.textContent = 'Item value = ' + addCommas(value);
-};
-
-/**
- * Changes the color of the color indicator.
- *
- * @param {string} color The new color to be set.
- */
-HoveringInfo.prototype.setColorIndicator = function(color) {
- this.colorIndicator_.style.backgroundColor = color;
-};
-
-/**
- * Main class that does the actual plotting.
- *
- * Draws a chart using a canvas element. Takes an array of lines to draw.
- * @constructor
- *
- * @param {Array} plotData list of arrays that represent individual lines. The
- * line itself is an Array of points.
- * @param {Array} dataDescriptions list of data descriptions for each line in
- * |plotData|.
- * @param {string} eventName The string name of an event to overlay on the
- * graph. Should be 'null' if there are no events to overlay.
- * @param {Object} eventInfo If |eventName| is specified, an array of event
- * points to overlay on the graph. Each event point in the array is itself
- * a 2-element array, where the first element is the x-axis value at which
- * the event occurred during the test, and the second element is a
- * dictionary of kay/value pairs representing metadata associated with the
- * event.
- * @param {string} unitsX The x-axis units of the data being plotted.
- * @param {string} unitsY The y-axis units of the data being plotted.
- * @param {string} unitsYOther If another graph (with different y-axis units) is
- * being overlayed over the first graph, this represents the units of the
- * other graph. Otherwise, this should be 'null'.
- * @param {?number} graphsOtherStartIndex Specifies the starting index of
- * the second set of lines. {@code plotData} in the range of
- * [0, {@code graphsOtherStartIndex}) are treated as the first set of lines,
- * and ones in the range of
- * [{@code graphsOtherStartIndex}, {@code plotData.length}) are as
- * the second set. 0, {@code plotData.length} and {@code null} mean
- * no second set, i.e. all the data in {@code plotData} represent the single
- * set of lines.
- * @param {Element} resultNode A DOM Element object representing the DOM node to
- * which the plot should be attached.
- * @param {boolean} is_lookout Whether or not the graph should be drawn
- * in 'lookout' mode, which is a summarized view that is made for overview
- * pages when the graph is drawn in a more confined space.
- * @param {boolean} stackedGraph Whether or not the first set of lines is
- * a stacked graph.
- * @param {boolean} stackedGraphOther Whether or not the second set of lines is
- * a stacked graph.
- *
- * Example of the |plotData|:
- * [
- * [line 1 data],
- * [line 2 data]
- * ].
- * Line data looks like [[point one], [point two]].
- * And individual points are [x value, y value]
- */
-function Plotter(plotData, dataDescriptions, eventName, eventInfo, unitsX,
- unitsY, unitsYOther, graphsOtherStartIndex, resultNode,
- is_lookout, stackedGraph, stackedGraphOther) {
- this.plotData_ = plotData;
- this.dataDescriptions_ = dataDescriptions;
- this.eventName_ = eventName;
- this.eventInfo_ = eventInfo;
- this.unitsX_ = unitsX;
- this.unitsY_ = unitsY;
- this.unitsYOther_ = unitsYOther;
- this.graphsOtherStartIndex_ =
- (0 < graphsOtherStartIndex && graphsOtherStartIndex < plotData.length) ?
- graphsOtherStartIndex : null;
- this.resultNode_ = resultNode;
- this.is_lookout_ = is_lookout;
- this.stackedGraph_ = stackedGraph;
- this.stackedGraphOther_ = stackedGraphOther;
-
- this.dataColors_ = [];
-
- this.coordinates = null;
- this.coordinatesOther = null;
- if (this.unitsYOther_ && this.graphsOtherStartIndex_) {
- // Need two different coordinate systems to overlay on the same graph.
- this.coordinates = new Coordinates(
- this.plotData_.slice(0, this.graphsOtherStartIndex_));
- this.coordinatesOther = new Coordinates(
- this.plotData_.slice(this.graphsOtherStartIndex_));
- } else {
- this.coordinates = new Coordinates(this.plotData_);
- }
-
- // A color palette that's unambigous for normal and color-deficient viewers.
- // Values are (red, green, blue) on a scale of 255.
- // Taken from http://jfly.iam.u-tokyo.ac.jp/html/manuals/pdf/color_blind.pdf.
- this.colors = [[0, 114, 178], // Blue.
- [230, 159, 0], // Orange.
- [0, 158, 115], // Green.
- [204, 121, 167], // Purplish pink.
- [86, 180, 233], // Sky blue.
- [213, 94, 0], // Dark orange.
- [0, 0, 0], // Black.
- [240, 228, 66] // Yellow.
- ];
-
- for (var i = 0, colorIndex = 0; i < this.dataDescriptions_.length; ++i)
- this.dataColors_[i] = this.makeColor(colorIndex++);
-}
-
-/**
- * Generates a string representing a color corresponding to the given index
- * in a color array. Handles wrapping around the color array if necessary.
- *
- * @param {number} i An index into the |this.colors| array.
- * @return {string} A string representing a color in 'rgb(X,Y,Z)' format.
- */
-Plotter.prototype.makeColor = function(i) {
- var index = i % this.colors.length;
- return 'rgb(' + this.colors[index][0] + ',' +
- this.colors[index][1] + ',' +
- this.colors[index][2] + ')';
-};
-
-/**
- * Same as function makeColor above, but also takes a transparency value
- * indicating how transparent to make the color appear.
- *
- * @param {number} i An index into the |this.colors| array.
- * @param {number} transparencyPercent Percentage transparency to make the
- * color, e.g., 0.75.
- * @return {string} A string representing a color in 'rgb(X,Y,Z,A)' format,
- * where A is the percentage transparency.
- */
-Plotter.prototype.makeColorTransparent = function(i, transparencyPercent) {
- var index = i % this.colors.length;
- return 'rgba(' + this.colors[index][0] + ',' +
- this.colors[index][1] + ',' +
- this.colors[index][2] + ',' + transparencyPercent + ')';
-};
-
-/**
- * Gets the data color value associated with a specified color index.
- *
- * @param {number} i An index into the |this.colors| array.
- * @return {string} A string representing a color in 'rgb(X,Y,Z,A)' format,
- * where A is the percentage transparency.
- */
-Plotter.prototype.getDataColor = function(i) {
- if (this.dataColors_[i])
- return this.dataColors_[i];
- else
- return this.makeColor(i);
-};
-
-/**
- * Gets the fill color value associated with a specified color index.
- *
- * @param {number} i An index into the |this.colors| array.
- * @return {string} A string representing a color in 'rgba(R,G,B,A)' format,
- * where A is the percentage transparency.
- */
-Plotter.prototype.getFillColor = function(i) {
- return this.makeColorTransparent(i, 0.4);
-};
-
-/**
- * Does the actual plotting.
- */
-Plotter.prototype.plot = function() {
- var self = this;
-
- this.canvasElement_ = this.canvas_();
- this.rulerDiv_ = this.ruler_();
-
- // Markers for the result point(s)/events that the mouse is currently
- // hovering over.
- this.cursorDiv_ = new VerticalMarker('rgb(100,80,240)');
- this.cursorDivOther_ = new VerticalMarker('rgb(50,50,50)');
- this.eventDiv_ = new VerticalMarker('rgb(255, 0, 0)');
- this.hoveringInfo_ = new HoveringInfo();
-
- this.resultNode_.appendChild(this.canvasElement_);
- this.resultNode_.appendChild(this.coordinates_());
- this.resultNode_.appendChild(this.rulerDiv_);
- this.resultNode_.appendChild(this.cursorDiv_);
- this.resultNode_.appendChild(this.cursorDivOther_);
- this.resultNode_.appendChild(this.eventDiv_);
- this.resultNode_.appendChild(this.hoveringInfo_.getElement());
- this.attachEventListeners_();
-
- // Now draw the canvas.
- var ctx = this.canvasElement_.getContext('2d');
-
- // Clear it with white: otherwise canvas will draw on top of existing data.
- ctx.clearRect(0, 0, this.canvasElement_.width, this.canvasElement_.height);
-
- // Draw all data lines in the reverse order so the last graph appears on
- // the backmost and the first graph appears on the frontmost.
- function draw(plotData, coordinates, colorOffset, stack) {
- for (var i = plotData.length - 1; i >= 0; --i) {
- if (stack) {
- self.plotAreaUnderLine_(ctx, self.getFillColor(colorOffset + i),
- plotData[i], coordinates);
- }
- self.plotLine_(ctx, self.getDataColor(colorOffset + i),
- plotData[i], coordinates);
- }
- }
- draw(this.plotData_.slice(0,
- this.graphsOtherStartIndex_ ?
- this.graphsOtherStartIndex_ :
- this.plotData_.length),
- this.coordinates, 0, this.stackedGraph_);
- if (this.graphsOtherStartIndex_) {
- draw(this.plotData_.slice(this.graphsOtherStartIndex_),
- this.unitsYOther_ ? this.coordinatesOther : this.coordinates,
- this.graphsOtherStartIndex_, this.stackedGraphOther_);
- }
-
- // Draw events overlayed on graph if needed.
- if (this.eventName_ && this.eventInfo_)
- this.plotEvents_(ctx, 'rgb(255, 150, 150)', this.coordinates);
-
- this.graduation_divs_ = this.graduations_(this.coordinates, 0, false);
- if (this.unitsYOther_) {
- this.graduation_divs_ = this.graduation_divs_.concat(
- this.graduations_(this.coordinatesOther, 1, true));
- }
- for (var i = 0; i < this.graduation_divs_.length; ++i)
- this.resultNode_.appendChild(this.graduation_divs_[i]);
-};
-
-/**
- * Draws events overlayed on top of an existing graph.
- *
- * @param {Object} ctx A canvas element object for drawing.
- * @param {string} strokeStyles A string representing the drawing style.
- * @param {Object} coordinateSystem A Coordinates object representing the
- * coordinate system of the graph.
- */
-Plotter.prototype.plotEvents_ = function(ctx, strokeStyles, coordinateSystem) {
- ctx.strokeStyle = strokeStyles;
- ctx.fillStyle = strokeStyles;
- ctx.lineWidth = 1.0;
-
- ctx.beginPath();
- var data = this.eventInfo_;
- for (var index = 0; index < data.length; ++index) {
- var event_time = data[index][0];
- var x = coordinateSystem.xPixel(event_time);
- ctx.moveTo(x, 0);
- ctx.lineTo(x, this.canvasElement_.offsetHeight);
- }
- ctx.closePath();
- ctx.stroke();
-};
-
-/**
- * Draws a line on the graph.
- *
- * @param {Object} ctx A canvas element object for drawing.
- * @param {string} strokeStyles A string representing the drawing style.
- * @param {Array} data A list of [x, y] values representing the line to plot.
- * @param {Object} coordinateSystem A Coordinates object representing the
- * coordinate system of the graph.
- */
-Plotter.prototype.plotLine_ = function(ctx, strokeStyles, data,
- coordinateSystem) {
- ctx.strokeStyle = strokeStyles;
- ctx.fillStyle = strokeStyles;
- ctx.lineWidth = 2.0;
-
- ctx.beginPath();
- var initial = true;
- var allPoints = [];
- for (var i = 0; i < data.length; ++i) {
- var pointX = parseFloat(data[i][0]);
- var pointY = parseFloat(data[i][1]);
- var x = coordinateSystem.xPixel(pointX);
- var y = coordinateSystem.yPixel(0);
- if (isNaN(pointY)) {
- // Re-set 'initial' if we're at a gap in the data.
- initial = true;
- } else {
- y = coordinateSystem.yPixel(pointY);
- if (initial)
- initial = false;
- else
- ctx.lineTo(x, y);
- }
-
- ctx.moveTo(x, y);
- if (!data[i].interpolated) {
- allPoints.push([x, y]);
- }
- }
- ctx.closePath();
- ctx.stroke();
-
- if (!this.is_lookout_) {
- // Draw a small dot at each point.
- for (var i = 0; i < allPoints.length; ++i) {
- ctx.beginPath();
- ctx.arc(allPoints[i][0], allPoints[i][1], 3, 0, Math.PI*2, true);
- ctx.fill();
- }
- }
-};
-
-/**
- * Fills an area under the given line on the graph.
- *
- * @param {Object} ctx A canvas element object for drawing.
- * @param {string} fillStyle A string representing the drawing style.
- * @param {Array} data A list of [x, y] values representing the line to plot.
- * @param {Object} coordinateSystem A Coordinates object representing the
- * coordinate system of the graph.
- */
-Plotter.prototype.plotAreaUnderLine_ = function(ctx, fillStyle, data,
- coordinateSystem) {
- if (!data[0]) {
- return; // nothing to draw
- }
-
- ctx.beginPath();
- var x = coordinateSystem.xPixel(parseFloat(data[0][0]) || 0);
- var y = coordinateSystem.yPixel(parseFloat(data[0][1]) || 0);
- var y0 = coordinateSystem.yPixel(coordinateSystem.yMinValue());
- ctx.moveTo(x, y0);
- for (var point, i = 0; point = data[i]; ++i) {
- var pointX = parseFloat(point[0]);
- var pointY = parseFloat(point[1]);
- if (isNaN(pointX)) { continue; } // Skip an invalid point.
- if (isNaN(pointY)) {
- ctx.lineTo(x, y0);
- var yWasNaN = true;
- } else {
- x = coordinateSystem.xPixel(pointX);
- y = coordinateSystem.yPixel(pointY);
- if (yWasNaN) {
- ctx.lineTo(x, y0);
- yWasNaN = false;
- }
- ctx.lineTo(x, y);
- }
- }
- ctx.lineTo(x, y0);
-
- ctx.lineWidth = 0;
- // Clear the area with white color first.
- var COLOR_WHITE = 'rgb(255,255,255)';
- ctx.strokeStyle = COLOR_WHITE;
- ctx.fillStyle = COLOR_WHITE;
- ctx.fill();
- // Then, fill the area with the specified color.
- ctx.strokeStyle = fillStyle;
- ctx.fillStyle = fillStyle;
- ctx.fill();
-};
-
-/**
- * Attaches event listeners to DOM nodes.
- */
-Plotter.prototype.attachEventListeners_ = function() {
- var self = this;
- this.canvasElement_.parentNode.addEventListener(
- 'mousemove', function(evt) { self.onMouseMove_(evt); }, false);
- this.canvasElement_.parentNode.addEventListener(
- 'mouseover', function(evt) { self.onMouseOver_(evt); }, false);
- this.canvasElement_.parentNode.addEventListener(
- 'mouseout', function(evt) { self.onMouseOut_(evt); }, false);
- this.cursorDiv_.addEventListener(
- 'click', function(evt) { self.onMouseClick_(evt); }, false);
- this.cursorDivOther_.addEventListener(
- 'click', function(evt) { self.onMouseClick_(evt); }, false);
- this.eventDiv_.addEventListener(
- 'click', function(evt) { self.onMouseClick_(evt); }, false);
-};
-
-/**
- * Update the horizontal line that is following where the mouse is hovering.
- *
- * @param {Object} evt A mouse event object representing a mouse move event.
- */
-Plotter.prototype.updateRuler_ = function(evt) {
- var r = this.rulerDiv_;
- r.style.left = this.canvasElement_.offsetLeft + 'px';
- r.style.top = this.canvasElement_.offsetTop + 'px';
- r.style.width = this.canvasElement_.offsetWidth + 'px';
- var h = domUtils.pageXYOfEvent(evt).y -
- domUtils.pageXY(this.canvasElement_).y;
- if (h > this.canvasElement_.offsetHeight)
- h = this.canvasElement_.offsetHeight;
- r.style.height = h + 'px';
-};
-
-/**
- * Update the highlighted data point at the x value that the mouse is hovering
- * over.
- *
- * @param {Object} coordinateSystem A Coordinates object representing the
- * coordinate system of the graph.
- * @param {number} currentIndex The index into the |this.plotData| array of the
- * data point being hovered over, for a given line.
- * @param {Object} cursorDiv A DOM element div object representing the highlight
- * itself.
- * @param {number} dataIndex The index into the |this.plotData| array of the
- * line being hovered over.
- */
-Plotter.prototype.updateCursor_ = function(coordinateSystem, currentIndex,
- cursorDiv, dataIndex) {
- var c = cursorDiv;
- c.style.top = this.canvasElement_.offsetTop + 'px';
- c.style.height = this.canvasElement_.offsetHeight + 'px';
-
- // Left point is half-way to the previous x value, unless it's the first
- // point, in which case it's the x value of the current point.
- var leftPoint = null;
- if (currentIndex == 0) {
- leftPoint = this.canvasElement_.offsetLeft +
- coordinateSystem.xPixel(this.plotData_[dataIndex][0][0]);
- }
- else {
- var left_x = this.canvasElement_.offsetLeft +
- coordinateSystem.xPixel(this.plotData_[dataIndex][currentIndex - 1][0]);
- var curr_x = this.canvasElement_.offsetLeft +
- coordinateSystem.xPixel(this.plotData_[dataIndex][currentIndex][0]);
- leftPoint = (left_x + curr_x) / 2;
- }
- c.style.left = leftPoint;
-
- // Width is half-way to the next x value minus the left point, unless it's
- // the last point, in which case it's the x value of the current point minus
- // the left point.
- if (currentIndex == this.plotData_[dataIndex].length - 1) {
- var curr_x = this.canvasElement_.offsetLeft +
- coordinateSystem.xPixel(this.plotData_[dataIndex][currentIndex][0]);
- c.style.width = curr_x - leftPoint;
- }
- else {
- var next_x = this.canvasElement_.offsetLeft +
- coordinateSystem.xPixel(this.plotData_[dataIndex][currentIndex + 1][0]);
- var curr_x = this.canvasElement_.offsetLeft +
- coordinateSystem.xPixel(this.plotData_[dataIndex][currentIndex][0]);
- c.style.width = ((next_x + curr_x) / 2) - leftPoint;
- }
-};
-
-/**
- * Update the highlighted event at the x value that the mouse is hovering over.
- *
- * @param {number} x The x-value (pixel) at which to draw the event highlight
- * div.
- * @param {boolean} show Whether or not to show the highlight div.
- */
-Plotter.prototype.updateEventDiv_ = function(x, show) {
- var c = this.eventDiv_;
- c.style.top = this.canvasElement_.offsetTop + 'px';
- c.style.height = this.canvasElement_.offsetHeight + 'px';
-
- if (show) {
- c.style.left = this.canvasElement_.offsetLeft + (x - 2);
- c.style.width = 8;
- } else {
- c.style.width = 0;
- }
-};
-
-/**
- * Updates the hovering information.
- *
- * @param {Event} evt An event object, which specifies the position of the mouse
- * cursor.
- * @param {boolean} show Whether or not to show the hovering info. Even if it's
- * true, if the cursor position is out of the appropriate area, nothing will
- * be shown.
- */
-Plotter.prototype.updateHoveringInfo_ = function(evt, show) {
- var evtPageXY = domUtils.pageXYOfEvent(evt);
- var hoveringInfoPageXY = this.hoveringInfo_.pageXY();
- var canvasPageXY = domUtils.pageXY(this.canvasElement_);
-
- var coord = this.coordinates;
- // p = the mouse cursor position in value coordinates.
- var p = {'x': coord.xValue(evtPageXY.x - canvasPageXY.x),
- 'y': coord.yValue(evtPageXY.y - canvasPageXY.y)};
- if (!show ||
- !(this.stackedGraph_ || this.stackedGraphOther_) ||
- p.x < coord.xMinValue() || coord.xMaxValue() < p.x ||
- p.y < coord.yMinValue() || coord.yMaxValue() < p.y) {
- this.hoveringInfo_.show(false);
- return;
- } else {
- this.hoveringInfo_.show(true);
- }
-
- /**
- * Finds the closest lines (upside and downside of the cursor position).
- * Returns a set of upside/downside line indices and point index on success
- * or null.
- */
- function findClosestLines(lines, opt_startIndex, opt_endIndex) {
- var offsetIndex = opt_startIndex || 0;
- lines =
- opt_endIndex != null ? lines.slice(offsetIndex, opt_endIndex) :
- opt_startIndex != null ? lines.slice(offsetIndex) :
- lines;
-
- var upsideClosestLineIndex = null;
- var upsideClosestYDistance = coord.yValueRange();
- var downsideClosestLineIndex = null;
- var downsideClosestYDistance = coord.yValueRange();
- var upsideClosestPointIndex = null;
-
- for (var lineIndex = 0, line; line = lines[lineIndex]; ++lineIndex) {
- for (var i = 1; line[i]; ++i) {
- var p0 = line[i - 1], p1 = line[i];
- if (p0[0] <= p.x && p.x < p1[0]) {
- // Calculate y-value of the line at p.x, which is the cursor point.
- var y = (p.x - p0[0]) / (p1[0] - p0[0]) * (p1[1] - p0[1]) + p0[1];
- if (p.y < y && y - p.y < upsideClosestYDistance) {
- upsideClosestLineIndex = lineIndex;
- upsideClosestYDistance = y - p.y;
-
- if (p.x - p0[0] < p1[0] - p.x) {
- upsideClosestPointIndex = i - 1;
- } else {
- upsideClosestPointIndex = i;
- }
- } else if (y <= p.y && p.y - y < downsideClosestYDistance) {
- downsideClosestLineIndex = lineIndex;
- downsideClosestYDistance = p.y - y;
- }
- break;
- }
- }
- }
-
- return (upsideClosestLineIndex != null &&
- upsideClosestPointIndex != null) ?
- {'upsideLineIndex': offsetIndex + upsideClosestLineIndex,
- 'downsideLineIndex': downsideClosestYDistance == null ? null :
- offsetIndex + downsideClosestLineIndex,
- 'upsidePointIndex': offsetIndex + upsideClosestPointIndex} :
- null;
- }
-
- // Find the closest lines above and below the mouse cursor.
- var closest = null;
- // Since the other set of graphs are drawn over the first set, try to find
- // the closest lines from the other set of graphs first.
- if (this.graphsOtherStartIndex_ && this.stackedGraphOther_) {
- closest = findClosestLines(this.plotData_, this.graphsOtherStartIndex_);
- }
- if (!closest && this.stackedGraph_) {
- closest = this.graphsOtherStartIndex_ ?
- findClosestLines(this.plotData_, 0, this.graphsOtherStartIndex_) :
- findClosestLines(this.plotData_);
- }
- if (!closest) {
- this.hoveringInfo_.show(false);
- return;
- }
-
- // Update the contents of the hovering info box.
- // Color indicator, description and the value of the item.
- this.hoveringInfo_.setColorIndicator(
- this.getDataColor(closest.upsideLineIndex));
- this.hoveringInfo_.setLegendText(
- this.dataDescriptions_[closest.upsideLineIndex]);
- var y1 = this.plotData_[closest.upsideLineIndex][closest.upsidePointIndex][1];
- var y0 = closest.downsideLineIndex == null ?
- 0 :
- this.plotData_[closest.downsideLineIndex][closest.upsidePointIndex][1];
- this.hoveringInfo_.setItemValue(y1 - y0);
-
- // Locate the hovering info box near the mouse cursor.
- var DIV_X_OFFSET = 10, DIV_Y_OFFSET = -20;
- if (evtPageXY.x + this.hoveringInfo_.getElement().offsetWidth <
- canvasPageXY.x + this.canvasElement_.offsetWidth) {
- this.hoveringInfo_.locateAtPageXY(evtPageXY.x + DIV_X_OFFSET,
- evtPageXY.y + DIV_Y_OFFSET);
- } else { // If lacking space at the right side, locate it at the left side.
- this.hoveringInfo_.locateAtPageXY(
- evtPageXY.x - this.hoveringInfo_.getElement().offsetWidth - DIV_X_OFFSET,
- evtPageXY.y + DIV_Y_OFFSET);
- }
-};
-
-/**
- * Handle a mouse move event.
- *
- * @param {Object} evt A mouse event object representing a mouse move event.
- */
-Plotter.prototype.onMouseMove_ = function(evt) {
- var self = this;
-
- var canvas = evt.currentTarget.firstChild;
- var evtPageXY = domUtils.pageXYOfEvent(evt);
- var canvasPageXY = domUtils.pageXY(this.canvasElement_);
- var positionX = evtPageXY.x - canvasPageXY.x;
- var positionY = evtPageXY.y - canvasPageXY.y;
-
- // Identify the index of the x value that is closest to the mouse x value.
- var xValue = this.coordinates.xValue(positionX);
- var lineIndex = !this.stackedGraph_ ? 0 :
- this.graphsOtherStartIndex_ ? this.graphsOtherStartIndex_ - 1 :
- this.plotData_.length - 1;
- var line = this.plotData_[lineIndex];
- var min_diff = Math.abs(line[0][0] - xValue);
- indexValueX = 0;
- for (var i = 1; i < line.length; ++i) {
- var diff = Math.abs(line[i][0] - xValue);
- if (diff < min_diff) {
- min_diff = diff;
- indexValueX = i;
- }
- }
-
- // Identify the index of the x value closest to the mouse x value for the
- // other graph being overlayed on top of the original graph, if one exists.
- if (this.unitsYOther_) {
- var xValue = this.coordinatesOther.xValue(positionX);
- var lineIndexOther = !this.stackedGraphOther_ ?
- this.graphsOtherStartIndex_ : this.plotData_.length - 1;
- var lineOther = this.plotData_[lineIndexOther];
- var min_diff = Math.abs(lineOther[0][0] - xValue);
- var indexValueXOther = 0;
- for (var i = 1; i < lineOther.length; ++i) {
- var diff = Math.abs(lineOther[i][0] - xValue);
- if (diff < min_diff) {
- min_diff = diff;
- indexValueXOther = i;
- }
- }
- }
-
- // Update coordinate information displayed directly underneath the graph.
- function legendLabel(lineIndex, opt_labelText) {
- return '<span style="color:' + self.getDataColor(lineIndex) + '">' +
- (opt_labelText || self.dataDescriptions_[lineIndex]) +
- '</span>:&nbsp;&nbsp;';
- }
- function valuesAtCursor(lineIndex, pointIndex, unitsY, yValue) {
- return '<span style="color:' + self.getDataColor(lineIndex) + '">' +
- self.plotData_[lineIndex][pointIndex][0] + ' ' + self.unitsX_ + ': ' +
- addCommas(self.plotData_[lineIndex][pointIndex][1].toFixed(2)) + ' ' +
- unitsY + '</span> [hovering at ' + addCommas(yValue.toFixed(2)) +
- ' ' + unitsY + ']';
- }
-
- this.infoBox_.rows[0].label.innerHTML = legendLabel(lineIndex);
- this.infoBox_.rows[0].content.innerHTML = valuesAtCursor(
- lineIndex, indexValueX, this.unitsY_, this.coordinates.yValue(positionY));
- var row = this.infoBox_.rows[1];
- if (this.unitsYOther_) {
- row.label.innerHTML = legendLabel(lineIndexOther);
- row.content.innerHTML = valuesAtCursor(
- lineIndexOther, indexValueXOther, this.unitsYOther_,
- this.coordinatesOther.yValue(positionY));
- } else if (this.graphsOtherStartIndex_) {
- row.label.innerHTML = legendLabel(
- this.stackedGraphOther_ ?
- this.plotData_.length - 1 : this.graphsOtherStartIndex_);
- row.content.innerHTML = valuesAtCursor(
- this.stackedGraphOther_ ?
- this.plotData_.length - 1 : this.graphsOtherStartIndex_,
- indexValueX, this.unitsY_, this.coordinates.yValue(positionY));
- } else if (!this.stackedGraph_ && this.dataDescriptions_.length > 1) {
- row.label.innerHTML = legendLabel(1);
- row.content.innerHTML = valuesAtCursor(
- 1, indexValueX, this.unitsY_, this.coordinates.yValue(positionY));
- } else if (row) {
- row.label.innerHTML = '';
- row.content.innerHTML = '';
- }
-
- // If there is a horizontal marker, also display deltas relative to it.
- if (this.horizontal_marker_) {
- var baseline = this.horizontal_marker_.value;
- var delta = this.coordinates.yValue(positionY) - baseline;
- var fraction = delta / baseline; // Allow division by 0.
-
- var deltaStr = (delta >= 0 ? '+' : '') + delta.toFixed(0) + ' ' +
- this.unitsY_;
- var percentStr = (fraction >= 0 ? '+' : '') + (fraction * 100).toFixed(3) +
- '%';
-
- this.baselineDeltasTd_.innerHTML = deltaStr + ': ' + percentStr;
-
- if (this.unitsYOther_) {
- var baseline = this.horizontal_marker_.otherValue;
- var yValue2 = this.coordinatesOther.yValue(positionY);
- var delta = yValue2 - baseline;
- var fraction = delta / baseline; // Allow division by 0.
-
- var deltaStr = (delta >= 0 ? '+' : '') + delta.toFixed(0) + ' ' +
- this.unitsYOther_;
- var percentStr = (fraction >= 0 ? '+' : '') +
- (fraction * 100).toFixed(3) + '%';
- this.baselineDeltasTd_.innerHTML += '<br>' + deltaStr + ': ' + percentStr;
- }
- }
-
- this.updateRuler_(evt);
- this.updateCursor_(this.coordinates, indexValueX, this.cursorDiv_, 0);
- if (this.unitsYOther_ && this.graphsOtherStartIndex_) {
- this.updateCursor_(this.coordinatesOther, indexValueXOther,
- this.cursorDivOther_, this.graphsOtherStartIndex_);
- }
-
- // If there are events displayed, see if we're hovering close to an existing
- // event on the graph, and if so, display the metadata associated with it.
- if (this.eventName_ != null && this.eventInfo_ != null) {
- this.infoBox_.rows[1].label.innerHTML = 'Event "' + this.eventName_ +
- '":&nbsp;&nbsp;';
- var data = this.eventInfo_;
- var showed_event = false;
- var x = 0;
- for (var index = 0; index < data.length; ++index) {
- var event_time = data[index][0];
- x = this.coordinates.xPixel(event_time);
- if (positionX >= x - 10 && positionX <= x + 10) {
- var metadata = data[index][1];
- var metadata_str = "";
- for (var meta_key in metadata)
- metadata_str += meta_key + ': ' + metadata[meta_key] + ', ';
- metadata_str = metadata_str.substring(0, metadata_str.length - 2);
- this.infoBox_.rows[1].content.innerHTML = event_time + ' ' +
- this.unitsX_ + ': {' + metadata_str + '}';
- showed_event = true;
- this.updateEventDiv_(x, true);
- break;
- }
- }
- if (!showed_event) {
- this.coordinatesTdOther_.innerHTML =
- 'move mouse close to vertical event marker';
- this.updateEventDiv_(x, false);
- }
- }
-
- this.updateHoveringInfo_(evt, true);
-};
-
-/**
- * Handle a mouse over event.
- *
- * @param {Object} evt A mouse event object representing a mouse move event.
- */
-Plotter.prototype.onMouseOver_ = function(evt) {
- this.updateHoveringInfo_(evt, true);
-};
-
-/**
- * Handle a mouse out event.
- *
- * @param {Object} evt A mouse event object representing a mouse move event.
- */
-Plotter.prototype.onMouseOut_ = function(evt) {
- this.updateHoveringInfo_(evt, false);
-};
-
-/**
- * Handle a mouse click event.
- *
- * @param {Object} evt A mouse event object representing a mouse click event.
- */
-Plotter.prototype.onMouseClick_ = function(evt) {
- // Shift-click controls the horizontal reference line.
- if (evt.shiftKey) {
- if (this.horizontal_marker_)
- this.horizontal_marker_.remove();
-
- var canvasY = domUtils.pageXYOfEvent(evt).y -
- domUtils.pageXY(this.canvasElement_).y;
- this.horizontal_marker_ = new HorizontalMarker(
- this.canvasElement_,
- this.coordinates.yValue(canvasY),
- (this.coordinatesOther ? this.coordinatesOther.yValue(canvasY) : null));
- // Insert before cursor node, otherwise it catches clicks.
- this.cursorDiv_.parentNode.insertBefore(
- this.horizontal_marker_.markerDiv, this.cursorDiv_);
- this.horizontal_marker_.locateAt(this.canvasElement_, canvasY);
- }
-};
-
-/**
- * Generates and returns a list of div objects representing horizontal lines in
- * the graph that indicate y-axis values at a computed interval.
- *
- * @param {Object} coordinateSystem a Coordinates object representing the
- * coordinate system for which the graduations should be created.
- * @param {number} colorIndex An index into the |this.colors| array representing
- * the color to make the graduations in the event that two graphs with
- * different coordinate systems are being overlayed on the same plot.
- * @param {boolean} isRightSide Whether or not the graduations should have
- * right-aligned text (used when the graduations are for a second graph
- * that is being overlayed on top of another graph).
- * @return {Array} An array of DOM Element objects representing the divs.
- */
-Plotter.prototype.graduations_ = function(coordinateSystem, colorIndex,
- isRightSide) {
- // Don't allow a graduation in the bottom 5% of the chart or the number label
- // would overflow the chart bounds.
- var yMin = coordinateSystem.yLowerLimitValue() +
- .05 * coordinateSystem.yValueRange();
- var yRange = coordinateSystem.yUpperLimitValue() - yMin;
-
- // Use the largest scale that fits 3 or more graduations.
- // We allow scales of [...,500, 250, 100, 50, 25, 10,...].
- var scale = 5000000000;
- while (scale) {
- if (Math.floor(yRange / scale) > 2) break; // 5s.
- scale /= 2;
- if (Math.floor(yRange / scale) > 2) break; // 2.5s.
- scale /= 2.5;
- if (Math.floor(yRange / scale) > 2) break; // 1s.
- scale /= 2;
- }
-
- var graduationPosition = yMin + (scale - yMin % scale);
- var graduationDivs = [];
- while (graduationPosition < coordinateSystem.yUpperLimitValue() ||
- yRange == 0) {
- var graduation = document.createElement('div');
- var canvasPosition;
- if (yRange == 0) {
- // Center the graduation vertically.
- canvasPosition = this.canvasElement_.offsetHeight / 2;
- } else {
- canvasPosition = coordinateSystem.yPixel(graduationPosition);
- }
- if (this.unitsYOther_) {
- graduation.style.borderTop = '1px dashed ' +
- this.makeColorTransparent(colorIndex, 0.4)
- } else {
- graduation.style.borderTop = '1px dashed rgba(0,0,0,.08)';
- }
- graduation.style.position = 'absolute';
- graduation.style.left = this.canvasElement_.offsetLeft + 'px';
- graduation.style.top = canvasPosition + this.canvasElement_.offsetTop +
- 'px';
- graduation.style.width = this.canvasElement_.offsetWidth -
- this.canvasElement_.offsetLeft + 'px';
- graduation.style.paddingLeft = '4px';
- if (this.unitsYOther_)
- graduation.style.color = this.makeColorTransparent(colorIndex, 0.9)
- else
- graduation.style.color = 'rgba(0,0,0,.4)';
- graduation.style.fontSize = '9px';
- graduation.style.paddingTop = '0';
- graduation.style.zIndex = '-1';
- if (isRightSide)
- graduation.style.textAlign = 'right';
- if (yRange == 0)
- graduation.innerHTML = addCommas(yMin);
- else
- graduation.innerHTML = addCommas(graduationPosition);
- graduationDivs.push(graduation);
- if (yRange == 0)
- break;
- graduationPosition += scale;
- }
- return graduationDivs;
-};
-
-/**
- * Generates and returns a div object representing the horizontal line that
- * follows the mouse pointer around the plot.
- *
- * @return {Object} A DOM Element object representing the div.
- */
-Plotter.prototype.ruler_ = function() {
- var ruler = document.createElement('div');
- ruler.setAttribute('class', 'plot-ruler');
- ruler.style.borderBottom = '1px dotted black';
- ruler.style.position = 'absolute';
- ruler.style.left = '-2px';
- ruler.style.top = '-2px';
- ruler.style.width = '0px';
- ruler.style.height = '0px';
- return ruler;
-};
-
-/**
- * Generates and returns a canvas object representing the plot itself.
- *
- * @return {Object} A DOM Element object representing the canvas.
- */
-Plotter.prototype.canvas_ = function() {
- var canvas = document.createElement('canvas');
- canvas.setAttribute('id', '_canvas');
- canvas.setAttribute('class', 'plot');
- canvas.setAttribute('width', this.coordinates.widthMax);
- canvas.setAttribute('height', this.coordinates.heightMax);
- canvas.plotter = this;
- return canvas;
-};
-
-/**
- * Generates and returns a div object representing the coordinate information
- * displayed directly underneath a graph.
- *
- * @return {Object} A DOM Element object representing the div.
- */
-Plotter.prototype.coordinates_ = function() {
- var coordinatesDiv = document.createElement('div');
- var table_html = '<table border=0 width="100%"';
- if (this.is_lookout_) {
- table_html += ' style="font-size:0.8em"';
- }
- table_html += '><tbody><tr>';
- table_html += '<td><span class="legend_item"></span>' +
- '<span class="plot-coordinates"><i>move mouse over graph</i></span></td>';
- table_html += '<td align="right">x-axis is ' + this.unitsX_ + '</td>';
- table_html += '</tr><tr>';
- table_html += '<td><span class="legend_item"></span>' +
- '<span class="plot-coordinates"></span></td>';
-
- if (!this.is_lookout_) {
- table_html += '<td align="right" style="color: ' + HorizontalMarker.COLOR +
- '"><i>Shift-click to place baseline.</i></td>';
- }
- table_html += '</tr></tbody></table>';
- coordinatesDiv.innerHTML = table_html;
-
- var trs = coordinatesDiv.querySelectorAll('tr');
- this.infoBox_ = {rows: []};
- this.infoBox_.rows.push({
- label: trs[0].querySelector('span.legend_item'),
- content: trs[0].querySelector('span.plot-coordinates')});
- if (this.dataDescriptions_.length > 1 || this.eventName_) {
- this.infoBox_.rows.push({
- label: trs[1].querySelector('span.legend_item'),
- content: trs[1].querySelector('span.plot-coordinates')});
- }
-
- this.baselineDeltasTd_ = trs[1].childNodes[1];
-
- // Add a summary of legends in case of stacked graphs.
- if (this.stackedGraph_ || this.stackedGraphOther_) {
- var legendPane = document.createElement('div');
- legendPane.style.fontSize = '80%';
- coordinatesDiv.appendChild(legendPane);
-
- if (this.graphsOtherStartIndex_) {
- legendPane.appendChild(
- this.createLegendsSummaryElement_(
- this.dataDescriptions_.slice(0, this.graphsOtherStartIndex_),
- 0));
- legendPane.appendChild(
- this.createLegendsSummaryElement_(
- this.dataDescriptions_.slice(this.graphsOtherStartIndex_),
- this.graphsOtherStartIndex_));
- } else {
- legendPane.appendChild(
- this.createLegendsSummaryElement_(this.dataDescriptions_, 0));
- }
- }
-
- return coordinatesDiv;
-};
-
-/**
- * Creates and returns a DOM element which shows a summary of legends.
- *
- * @param {!Array.<string>} legendTexts An array of legend texts.
- * @param {number} colorIndexOffset Offset index for color. i-th legend text
- * has an indicator in {@code (colorIndexOffset + i)}-th color
- * @return {!Element} An element which shows a summary of legends.
- */
-Plotter.prototype.createLegendsSummaryElement_ = function(legendTexts,
- colorIndexOffset) {
- var containerElem = document.createElement('div');
-
- for (var i = 0, text; text = legendTexts[i]; ++i) {
- var colorIndicatorElem = document.createElement('div');
- colorIndicatorElem.style.display = 'inline-block';
- colorIndicatorElem.style.width = '1em';
- colorIndicatorElem.style.height = '1em';
- colorIndicatorElem.style.verticalAlign = 'text-bottom';
- colorIndicatorElem.style.margin = '0 0.24em 0 0';
- colorIndicatorElem.style.border = '1px solid #000';
- colorIndicatorElem.style.backgroundColor =
- this.getDataColor(colorIndexOffset + i);
- var legendTextElem = document.createElement('span');
- legendTextElem.textContent = text;
- var legendElem = document.createElement('span');
- legendElem.style.whiteSpace = 'nowrap';
- legendElem.appendChild(colorIndicatorElem);
- legendElem.appendChild(legendTextElem);
- legendElem.style.margin = '0 0.8em 0 0';
- containerElem.appendChild(legendElem);
- // Add a space to break lines if necessary.
- containerElem.appendChild(document.createTextNode(' '));
- }
-
- return containerElem;
-};
diff --git a/chrome/test/functional/perf/endure_result_parser.py b/chrome/test/functional/perf/endure_result_parser.py
deleted file mode 100755
index f477270..0000000
--- a/chrome/test/functional/perf/endure_result_parser.py
+++ /dev/null
@@ -1,824 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Script to parse perf data from Chrome Endure test executions, to be graphed.
-
-This script connects via HTTP to a buildbot master in order to scrape and parse
-perf data from Chrome Endure tests that have been run. The perf data is then
-stored in local text files to be graphed by the Chrome Endure graphing code.
-
-It is assumed that any Chrome Endure tests that show up on the waterfall have
-names that are of the following form:
-
-"endure_<webapp_name>-<test_name>"
-
-This script accepts either a URL or a local path as a buildbot location.
-It switches its behavior if a URL is given, or a local path is given.
-
-When a URL is given, it gets buildbot logs from the buildbot builders URL
-e.g. http://build.chromium.org/p/chromium.endure/builders/.
-
-When a local path is given, it gets buildbot logs from buildbot's internal
-files in the directory e.g. /home/chrome-bot/buildbot.
-"""
-
-import cPickle
-import getpass
-import logging
-import optparse
-import os
-import re
-import simplejson
-import socket
-import string
-import sys
-import time
-import urllib
-import urllib2
-
-
-CHROME_ENDURE_SLAVE_NAMES = [
- 'Linux QA Perf (0)',
- 'Linux QA Perf (1)',
- 'Linux QA Perf (2)',
- 'Linux QA Perf (3)',
- 'Linux QA Perf (4)',
- 'Linux QA Perf (dbg)(0)',
- 'Linux QA Perf (dbg)(1)',
- 'Linux QA Perf (dbg)(2)',
- 'Linux QA Perf (dbg)(3)',
- 'Linux QA Perf (dbg)(4)',
-]
-
-BUILDER_URL_BASE = 'http://build.chromium.org/p/chromium.endure/builders/'
-LAST_BUILD_NUM_PROCESSED_FILE = os.path.join(os.path.dirname(__file__),
- '_parser_last_processed.txt')
-LOCAL_GRAPH_DIR = '/home/%s/www/chrome_endure_clean' % getpass.getuser()
-MANGLE_TRANSLATION = string.maketrans(' ()', '___')
-
-def SetupBaseGraphDirIfNeeded(webapp_name, test_name, dest_dir):
- """Sets up the directory containing results for a particular test, if needed.
-
- Args:
- webapp_name: The string name of the webapp associated with the given test.
- test_name: The string name of the test.
- dest_dir: The name of the destination directory that needs to be set up.
- """
- if not os.path.exists(dest_dir):
- os.mkdir(dest_dir) # Test name directory.
- os.chmod(dest_dir, 0755)
-
- # Create config file.
- config_file = os.path.join(dest_dir, 'config.js')
- if not os.path.exists(config_file):
- with open(config_file, 'w') as f:
- f.write('var Config = {\n')
- f.write('buildslave: "Chrome Endure Bots",\n')
- f.write('title: "Chrome Endure %s Test: %s",\n' % (webapp_name.upper(),
- test_name))
- f.write('};\n')
- os.chmod(config_file, 0755)
-
- # Set up symbolic links to the real graphing files.
- link_file = os.path.join(dest_dir, 'index.html')
- if not os.path.exists(link_file):
- os.symlink('../../endure_plotter.html', link_file)
- link_file = os.path.join(dest_dir, 'endure_plotter.js')
- if not os.path.exists(link_file):
- os.symlink('../../endure_plotter.js', link_file)
- link_file = os.path.join(dest_dir, 'js')
- if not os.path.exists(link_file):
- os.symlink('../../js', link_file)
-
-
-def WriteToDataFile(new_line, existing_lines, revision, data_file):
- """Writes a new entry to an existing perf data file to be graphed.
-
- If there's an existing line with the same revision number, overwrite its data
- with the new line. Else, prepend the info for the new revision.
-
- Args:
- new_line: A dictionary representing perf information for the new entry.
- existing_lines: A list of string lines from the existing perf data file.
- revision: The string revision number associated with the new perf entry.
- data_file: The string name of the perf data file to which to write.
- """
- overwritten = False
- for i, line in enumerate(existing_lines):
- line_dict = simplejson.loads(line)
- if line_dict['rev'] == revision:
- existing_lines[i] = simplejson.dumps(new_line)
- overwritten = True
- break
- elif int(line_dict['rev']) < int(revision):
- break
- if not overwritten:
- existing_lines.insert(0, simplejson.dumps(new_line))
-
- with open(data_file, 'w') as f:
- f.write('\n'.join(existing_lines))
- os.chmod(data_file, 0755)
-
-
-def OutputPerfData(revision, graph_name, values, units, units_x, dest_dir,
- is_stacked=False, stack_order=[]):
- """Outputs perf data to a local text file to be graphed.
-
- Args:
- revision: The string revision number associated with the perf data.
- graph_name: The string name of the graph on which to plot the data.
- values: A dict which maps a description to a value. A value is either a
- single data value to be graphed, or a list of 2-tuples
- representing (x, y) points to be graphed for long-running tests.
- units: The string description for the y-axis units on the graph.
- units_x: The string description for the x-axis units on the graph. Should
- be set to None if the results are not for long-running graphs.
- dest_dir: The name of the destination directory to which to write.
- is_stacked: True to draw a "stacked" graph. First-come values are
- stacked at bottom by default.
- stack_order: A list that contains key strings in the order to stack values
- in the graph.
- """
- # Update graphs.dat, which contains metadata associated with each graph.
- existing_graphs = []
- graphs_file = os.path.join(dest_dir, 'graphs.dat')
- if os.path.exists(graphs_file):
- with open(graphs_file, 'r') as f:
- existing_graphs = simplejson.loads(f.read())
- is_new_graph = True
- for graph in existing_graphs:
- if graph['name'] == graph_name:
- is_new_graph = False
- break
- if is_new_graph:
- new_graph = {
- 'name': graph_name,
- 'units': units,
- 'important': False,
- }
- if units_x:
- new_graph['units_x'] = units_x
- existing_graphs.append(new_graph)
- existing_graphs = sorted(existing_graphs, key=lambda x: x['name'])
- with open(graphs_file, 'w') as f:
- f.write(simplejson.dumps(existing_graphs, indent=2))
- os.chmod(graphs_file, 0755)
-
- # Update summary data file, containing the actual data to be graphed.
- data_file_name = graph_name + '-summary.dat'
- existing_lines = []
- data_file = os.path.join(dest_dir, data_file_name)
- if os.path.exists(data_file):
- with open(data_file, 'r') as f:
- existing_lines = f.readlines()
- existing_lines = map(lambda x: x.strip(), existing_lines)
- new_traces = {}
- for description in values:
- value = values[description]
- if units_x:
- points = []
- for point in value:
- points.append([str(point[0]), str(point[1])])
- new_traces[description] = points
- else:
- new_traces[description] = [str(value), str(0.0)]
- new_line = {
- 'traces': new_traces,
- 'rev': revision
- }
- if is_stacked:
- new_line['stack'] = True
- new_line['stack_order'] = stack_order
-
- WriteToDataFile(new_line, existing_lines, revision, data_file)
-
-
-def OutputEventData(revision, event_dict, dest_dir):
- """Outputs event data to a local text file to be graphed.
-
- Args:
- revision: The string revision number associated with the event data.
- event_dict: A dict which maps a description to an array of tuples
- representing event data to be graphed.
- dest_dir: The name of the destination directory to which to write.
- """
- data_file_name = '_EVENT_-summary.dat'
- existing_lines = []
- data_file = os.path.join(dest_dir, data_file_name)
- if os.path.exists(data_file):
- with open(data_file, 'r') as f:
- existing_lines = f.readlines()
- existing_lines = map(lambda x: x.strip(), existing_lines)
-
- new_events = {}
- for description in event_dict:
- event_list = event_dict[description]
- value_list = []
- for event_time, event_data in event_list:
- value_list.append([str(event_time), event_data])
- new_events[description] = value_list
-
- new_line = {
- 'rev': revision,
- 'events': new_events
- }
-
- WriteToDataFile(new_line, existing_lines, revision, data_file)
-
-
-def UpdatePerfDataFromFetchedContent(
- revision, content, webapp_name, test_name, graph_dir, only_dmp=False):
- """Update perf data from fetched stdio data.
-
- Args:
- revision: The string revision number associated with the new perf entry.
- content: Fetched stdio data.
- webapp_name: A name of the webapp.
- test_name: A name of the test.
- graph_dir: A path to the graph directory.
- only_dmp: True if only Deep Memory Profiler results should be used.
- """
- perf_data_raw = []
-
- def AppendRawPerfData(graph_name, description, value, units, units_x,
- webapp_name, test_name, is_stacked=False):
- perf_data_raw.append({
- 'graph_name': graph_name,
- 'description': description,
- 'value': value,
- 'units': units,
- 'units_x': units_x,
- 'webapp_name': webapp_name,
- 'test_name': test_name,
- 'stack': is_stacked,
- })
-
- # First scan for short-running perf test results.
- for match in re.findall(
- r'RESULT ([^:]+): ([^=]+)= ([-\d\.]+) (\S+)', content):
- if (not only_dmp) or match[0].endswith('-DMP'):
- try:
- match2 = eval(match[2])
- except SyntaxError:
- match2 = None
- if match2:
- AppendRawPerfData(match[0], match[1], match2, match[3], None,
- webapp_name, webapp_name)
-
- # Next scan for long-running perf test results.
- for match in re.findall(
- r'RESULT ([^:]+): ([^=]+)= (\[[^\]]+\]) (\S+) (\S+)', content):
- if (not only_dmp) or match[0].endswith('-DMP'):
- try:
- match2 = eval(match[2])
- except SyntaxError:
- match2 = None
- # TODO(dmikurube): Change the condition to use stacked graph when we
- # determine how to specify it.
- if match2:
- AppendRawPerfData(match[0], match[1], match2, match[3], match[4],
- webapp_name, test_name, match[0].endswith('-DMP'))
-
- # Next scan for events in the test results.
- for match in re.findall(
- r'RESULT _EVENT_: ([^=]+)= (\[[^\]]+\])', content):
- try:
- match1 = eval(match[1])
- except SyntaxError:
- match1 = None
- if match1:
- AppendRawPerfData('_EVENT_', match[0], match1, None, None,
- webapp_name, test_name)
-
- # For each graph_name/description pair that refers to a long-running test
- # result or an event, concatenate all the results together (assume results
- # in the input file are in the correct order). For short-running test
- # results, keep just one if more than one is specified.
- perf_data = {} # Maps a graph-line key to a perf data dictionary.
- for data in perf_data_raw:
- key_graph = data['graph_name']
- key_description = data['description']
- if not key_graph in perf_data:
- perf_data[key_graph] = {
- 'graph_name': data['graph_name'],
- 'value': {},
- 'units': data['units'],
- 'units_x': data['units_x'],
- 'webapp_name': data['webapp_name'],
- 'test_name': data['test_name'],
- }
- perf_data[key_graph]['stack'] = data['stack']
- if 'stack_order' not in perf_data[key_graph]:
- perf_data[key_graph]['stack_order'] = []
- if (data['stack'] and
- data['description'] not in perf_data[key_graph]['stack_order']):
- perf_data[key_graph]['stack_order'].append(data['description'])
-
- if data['graph_name'] != '_EVENT_' and not data['units_x']:
- # Short-running test result.
- perf_data[key_graph]['value'][key_description] = data['value']
- else:
- # Long-running test result or event.
- if key_description in perf_data[key_graph]['value']:
- perf_data[key_graph]['value'][key_description] += data['value']
- else:
- perf_data[key_graph]['value'][key_description] = data['value']
-
- # Finally, for each graph-line in |perf_data|, update the associated local
- # graph data files if necessary.
- for perf_data_key in perf_data:
- perf_data_dict = perf_data[perf_data_key]
-
- dest_dir = os.path.join(graph_dir, perf_data_dict['webapp_name'])
- if not os.path.exists(dest_dir):
- os.mkdir(dest_dir) # Webapp name directory.
- os.chmod(dest_dir, 0755)
- dest_dir = os.path.join(dest_dir, perf_data_dict['test_name'])
-
- SetupBaseGraphDirIfNeeded(perf_data_dict['webapp_name'],
- perf_data_dict['test_name'], dest_dir)
- if perf_data_dict['graph_name'] == '_EVENT_':
- OutputEventData(revision, perf_data_dict['value'], dest_dir)
- else:
- OutputPerfData(revision, perf_data_dict['graph_name'],
- perf_data_dict['value'],
- perf_data_dict['units'], perf_data_dict['units_x'],
- dest_dir,
- perf_data_dict['stack'], perf_data_dict['stack_order'])
-
-
-def SlaveLocation(master_location, slave_info):
- """Returns slave location for |master_location| and |slave_info|."""
- if master_location.startswith('http://'):
- return master_location + urllib.quote(slave_info['slave_name'])
- else:
- return os.path.join(master_location,
- slave_info['slave_name'].translate(MANGLE_TRANSLATION))
-
-
-def GetRevisionAndLogs(slave_location, build_num):
- """Get a revision number and log locations.
-
- Args:
- slave_location: A URL or a path to the build slave data.
- build_num: A build number.
-
- Returns:
- A pair of the revision number and a list of strings that contain locations
- of logs. (False, []) in case of error.
- """
- if slave_location.startswith('http://'):
- location = slave_location + '/builds/' + str(build_num)
- else:
- location = os.path.join(slave_location, str(build_num))
-
- revision = False
- logs = []
- fp = None
- try:
- if location.startswith('http://'):
- fp = urllib2.urlopen(location)
- contents = fp.read()
- revisions = re.findall(r'<td class="left">got_revision</td>\s+'
- '<td>(\d+)</td>\s+<td>Source</td>', contents)
- if revisions:
- revision = revisions[0]
- logs = [location + link + '/text' for link
- in re.findall(r'(/steps/endure[^/]+/logs/stdio)', contents)]
- else:
- fp = open(location, 'rb')
- build = cPickle.load(fp)
- properties = build.getProperties()
- if properties.has_key('got_revision'):
- revision = build.getProperty('got_revision')
- candidates = os.listdir(slave_location)
- logs = [os.path.join(slave_location, filename)
- for filename in candidates
- if re.match(r'%d-log-endure[^/]+-stdio' % build_num, filename)]
-
- except urllib2.URLError, e:
- logging.exception('Error reading build URL "%s": %s', location, str(e))
- return False, []
- except (IOError, OSError), e:
- logging.exception('Error reading build file "%s": %s', location, str(e))
- return False, []
- finally:
- if fp:
- fp.close()
-
- return revision, logs
-
-
-def ExtractTestNames(log_location, is_dbg):
- """Extract test names from |log_location|.
-
- Returns:
- A dict of a log location, webapp's name and test's name. False if error.
- """
- if log_location.startswith('http://'):
- location = urllib.unquote(log_location)
- test_pattern = r'endure_([^_]+)(_test |-)([^/]+)/'
- else:
- location = log_location
- test_pattern = r'endure_([^_]+)(_test_|-)([^/]+)-stdio'
-
- match = match[0]
- webapp_name = match[0]
- webapp_name = webapp_name + '_dbg' if is_dbg else webapp_name
- test_name = match[2]
-
- return {
- 'location': log_location,
- 'webapp_name': webapp_name,
- 'test_name': test_name,
- }
-
-
-def GetStdioContents(stdio_location):
- """Gets appropriate stdio contents.
-
- Returns:
- A content string of the stdio log. None in case of error.
- """
- fp = None
- contents = ''
- try:
- if stdio_location.startswith('http://'):
- fp = urllib2.urlopen(stdio_location, timeout=60)
- # Since in-progress test output is sent chunked, there's no EOF. We need
- # to specially handle this case so we don't hang here waiting for the
- # test to complete.
- start_time = time.time()
- while True:
- data = fp.read(1024)
- if not data:
- break
- contents += data
- if time.time() - start_time >= 30: # Read for at most 30 seconds.
- break
- else:
- fp = open(stdio_location)
- data = fp.read()
- contents = ''
- index = 0
-
- # Buildbot log files are stored in the netstring format.
- # http://en.wikipedia.org/wiki/Netstring
- while index < len(data):
- index2 = index
- while data[index2].isdigit():
- index2 += 1
- if data[index2] != ':':
- logging.error('Log file is not in expected format: %s' %
- stdio_location)
- contents = None
- break
- length = int(data[index:index2])
- index = index2 + 1
- channel = int(data[index])
- index += 1
- if data[index+length-1] != ',':
- logging.error('Log file is not in expected format: %s' %
- stdio_location)
- contents = None
- break
- if channel == 0:
- contents += data[index:(index+length-1)]
- index += length
-
- except (urllib2.URLError, socket.error, IOError, OSError), e:
- # Issue warning but continue to the next stdio link.
- logging.warning('Error reading test stdio data "%s": %s',
- stdio_location, str(e))
- finally:
- if fp:
- fp.close()
-
- return contents
-
-
-def UpdatePerfDataForSlaveAndBuild(
- slave_info, build_num, graph_dir, master_location):
- """Process updated perf data for a particular slave and build number.
-
- Args:
- slave_info: A dictionary containing information about the slave to process.
- build_num: The particular build number on the slave to process.
- graph_dir: A path to the graph directory.
- master_location: A URL or a path to the build master data.
-
- Returns:
- True if the perf data for the given slave/build is updated properly, or
- False if any critical error occurred.
- """
- if not master_location.startswith('http://'):
- # Source is a file.
- from buildbot.status import builder
-
- slave_location = SlaveLocation(master_location, slave_info)
- logging.debug(' %s, build %d.', slave_info['slave_name'], build_num)
- is_dbg = '(dbg)' in slave_info['slave_name']
-
- revision, logs = GetRevisionAndLogs(slave_location, build_num)
- if not revision:
- return False
-
- stdios = []
- for log_location in logs:
- stdio = ExtractTestNames(log_location, is_dbg)
- if not stdio:
- return False
- stdios.append(stdio)
-
- for stdio in stdios:
- stdio_location = stdio['location']
- contents = GetStdioContents(stdio_location)
-
- if contents:
- UpdatePerfDataFromFetchedContent(revision, contents,
- stdio['webapp_name'],
- stdio['test_name'],
- graph_dir, is_dbg)
-
- return True
-
-
-def GetMostRecentBuildNum(master_location, slave_name):
- """Gets the most recent buld number for |slave_name| in |master_location|."""
- most_recent_build_num = None
-
- if master_location.startswith('http://'):
- slave_url = master_location + urllib.quote(slave_name)
-
- url_contents = ''
- fp = None
- try:
- fp = urllib2.urlopen(slave_url, timeout=60)
- url_contents = fp.read()
- except urllib2.URLError, e:
- logging.exception('Error reading builder URL: %s', str(e))
- return None
- finally:
- if fp:
- fp.close()
-
- matches = re.findall(r'/(\d+)/stop', url_contents)
- if matches:
- most_recent_build_num = int(matches[0])
- else:
- matches = re.findall(r'#(\d+)</a></td>', url_contents)
- if matches:
- most_recent_build_num = sorted(map(int, matches), reverse=True)[0]
-
- else:
- slave_path = os.path.join(master_location,
- slave_name.translate(MANGLE_TRANSLATION))
- files = os.listdir(slave_path)
- number_files = [int(filename) for filename in files if filename.isdigit()]
- if number_files:
- most_recent_build_num = sorted(number_files, reverse=True)[0]
-
- if most_recent_build_num:
- logging.debug('%s most recent build number: %s',
- slave_name, most_recent_build_num)
- else:
- logging.error('Could not identify latest build number for slave %s.',
- slave_name)
-
- return most_recent_build_num
-
-
-def UpdatePerfDataFiles(graph_dir, master_location):
- """Updates the Chrome Endure graph data files with the latest test results.
-
- For each known Chrome Endure slave, we scan its latest test results looking
- for any new test data. Any new data that is found is then appended to the
- data files used to display the Chrome Endure graphs.
-
- Args:
- graph_dir: A path to the graph directory.
- master_location: A URL or a path to the build master data.
-
- Returns:
- True if all graph data files are updated properly, or
- False if any error occurred.
- """
- slave_list = []
- for slave_name in CHROME_ENDURE_SLAVE_NAMES:
- slave_info = {}
- slave_info['slave_name'] = slave_name
- slave_info['most_recent_build_num'] = None
- slave_info['last_processed_build_num'] = None
- slave_list.append(slave_info)
-
- # Identify the most recent build number for each slave.
- logging.debug('Searching for latest build numbers for each slave...')
- for slave in slave_list:
- slave_name = slave['slave_name']
- slave['most_recent_build_num'] = GetMostRecentBuildNum(
- master_location, slave_name)
-
- # Identify the last-processed build number for each slave.
- logging.debug('Identifying last processed build numbers...')
- if not os.path.exists(LAST_BUILD_NUM_PROCESSED_FILE):
- for slave_info in slave_list:
- slave_info['last_processed_build_num'] = 0
- else:
- with open(LAST_BUILD_NUM_PROCESSED_FILE, 'r') as fp:
- file_contents = fp.read()
- for match in re.findall(r'([^:]+):(\d+)', file_contents):
- slave_name = match[0].strip()
- last_processed_build_num = match[1].strip()
- for slave_info in slave_list:
- if slave_info['slave_name'] == slave_name:
- slave_info['last_processed_build_num'] = int(
- last_processed_build_num)
- for slave_info in slave_list:
- if not slave_info['last_processed_build_num']:
- slave_info['last_processed_build_num'] = 0
- logging.debug('Done identifying last processed build numbers.')
-
- # For each Chrome Endure slave, process each build in-between the last
- # processed build num and the most recent build num, inclusive. To process
- # each one, first get the revision number for that build, then scan the test
- # result stdio for any performance data, and add any new performance data to
- # local files to be graphed.
- for slave_info in slave_list:
- logging.debug('Processing %s, builds %d-%d...',
- slave_info['slave_name'],
- slave_info['last_processed_build_num'],
- slave_info['most_recent_build_num'])
- curr_build_num = slave_info['last_processed_build_num']
- while curr_build_num <= slave_info['most_recent_build_num']:
- if not UpdatePerfDataForSlaveAndBuild(slave_info, curr_build_num,
- graph_dir, master_location):
- # Do not give up. The first files might be removed by buildbot.
- logging.warning('Logs do not exist in buildbot for #%d of %s.' %
- (curr_build_num, slave_info['slave_name']))
- curr_build_num += 1
-
- # Log the newly-processed build numbers.
- logging.debug('Logging the newly-processed build numbers...')
- with open(LAST_BUILD_NUM_PROCESSED_FILE, 'w') as f:
- for slave_info in slave_list:
- f.write('%s:%s\n' % (slave_info['slave_name'],
- slave_info['most_recent_build_num']))
-
- return True
-
-
-def GenerateIndexPage(graph_dir):
- """Generates a summary (landing) page for the Chrome Endure graphs.
-
- Args:
- graph_dir: A path to the graph directory.
- """
- logging.debug('Generating new index.html page...')
-
- # Page header.
- page = """
- <html>
-
- <head>
- <title>Chrome Endure Overview</title>
- <script language="javascript">
- function DisplayGraph(name, graph) {
- document.write(
- '<td><iframe scrolling="no" height="438" width="700" src="');
- document.write(name);
- document.write('"></iframe></td>');
- }
- </script>
- </head>
-
- <body>
- <center>
-
- <h1>
- Chrome Endure
- </h1>
- """
- # Print current time.
- page += '<p>Updated: %s</p>\n' % (
- time.strftime('%A, %B %d, %Y at %I:%M:%S %p %Z'))
-
- # Links for each webapp.
- webapp_names = [x for x in os.listdir(graph_dir) if
- x not in ['js', 'old_data', '.svn', '.git'] and
- os.path.isdir(os.path.join(graph_dir, x))]
- webapp_names = sorted(webapp_names)
-
- page += '<p> ['
- for i, name in enumerate(webapp_names):
- page += '<a href="#%s">%s</a>' % (name.upper(), name.upper())
- if i < len(webapp_names) - 1:
- page += ' | '
- page += '] </p>\n'
-
- # Print out the data for each webapp.
- for webapp_name in webapp_names:
- page += '\n<h1 id="%s">%s</h1>\n' % (webapp_name.upper(),
- webapp_name.upper())
-
- # Links for each test for this webapp.
- test_names = [x for x in
- os.listdir(os.path.join(graph_dir, webapp_name))]
- test_names = sorted(test_names)
-
- page += '<p> ['
- for i, name in enumerate(test_names):
- page += '<a href="#%s">%s</a>' % (name, name)
- if i < len(test_names) - 1:
- page += ' | '
- page += '] </p>\n'
-
- # Print out the data for each test for this webapp.
- for test_name in test_names:
- # Get the set of graph names for this test.
- graph_names = [x[:x.find('-summary.dat')] for x in
- os.listdir(os.path.join(graph_dir,
- webapp_name, test_name))
- if '-summary.dat' in x and '_EVENT_' not in x]
- graph_names = sorted(graph_names)
-
- page += '<h2 id="%s">%s</h2>\n' % (test_name, test_name)
- page += '<table>\n'
-
- for i, graph_name in enumerate(graph_names):
- if i % 2 == 0:
- page += ' <tr>\n'
- page += (' <script>DisplayGraph("%s/%s?graph=%s&lookout=1");'
- '</script>\n' % (webapp_name, test_name, graph_name))
- if i % 2 == 1:
- page += ' </tr>\n'
- if len(graph_names) % 2 == 1:
- page += ' </tr>\n'
- page += '</table>\n'
-
- # Page footer.
- page += """
- </center>
- </body>
-
- </html>
- """
-
- index_file = os.path.join(graph_dir, 'index.html')
- with open(index_file, 'w') as f:
- f.write(page)
- os.chmod(index_file, 0755)
-
-
-def main():
- parser = optparse.OptionParser()
- parser.add_option(
- '-v', '--verbose', action='store_true', default=False,
- help='Use verbose logging.')
- parser.add_option(
- '-s', '--stdin', action='store_true', default=False,
- help='Input from stdin instead of slaves for testing this script.')
- parser.add_option(
- '-b', '--buildbot', dest='buildbot', metavar="BUILDBOT",
- default=BUILDER_URL_BASE,
- help='Use log files in a buildbot at BUILDBOT. BUILDBOT can be a '
- 'buildbot\'s builder URL or a local path to a buildbot directory. '
- 'Both an absolute path and a relative path are available, e.g. '
- '"/home/chrome-bot/buildbot" or "../buildbot". '
- '[default: %default]')
- parser.add_option(
- '-g', '--graph', dest='graph_dir', metavar="DIR", default=LOCAL_GRAPH_DIR,
- help='Output graph data files to DIR. [default: %default]')
- options, _ = parser.parse_args(sys.argv)
-
- logging_level = logging.DEBUG if options.verbose else logging.INFO
- logging.basicConfig(level=logging_level,
- format='[%(asctime)s] %(levelname)s: %(message)s')
-
- if options.stdin:
- content = sys.stdin.read()
- UpdatePerfDataFromFetchedContent(
- '12345', content, 'webapp', 'test', options.graph_dir)
- else:
- if options.buildbot.startswith('http://'):
- master_location = options.buildbot
- else:
- build_dir = os.path.join(options.buildbot, 'build')
- third_party_dir = os.path.join(build_dir, 'third_party')
- sys.path.append(third_party_dir)
- sys.path.append(os.path.join(third_party_dir, 'buildbot_8_4p1'))
- sys.path.append(os.path.join(third_party_dir, 'twisted_10_2'))
- master_location = os.path.join(build_dir, 'masters',
- 'master.chromium.endure')
- success = UpdatePerfDataFiles(options.graph_dir, master_location)
- if not success:
- logging.error('Failed to update perf data files.')
- sys.exit(0)
-
- GenerateIndexPage(options.graph_dir)
- logging.debug('All done!')
-
-
-if __name__ == '__main__':
- main()
diff --git a/chrome/test/functional/perf/endure_server.py b/chrome/test/functional/perf/endure_server.py
deleted file mode 100755
index ae4cd0f..0000000
--- a/chrome/test/functional/perf/endure_server.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Start an HTTP server which serves Chrome Endure graphs.
-
-Usage:
- python endure_server.py [options]
-
-To view Chrome Endure graphs from a browser,
-run this script to start a local HTTP server that serves the directory
-where graph code and test results are located. A port will be automatically
-picked. You can then view the graphs via http://localhost:<GIVEN_PORT>.
-
-Examples:
- >python endure_server.py
- Start a server which serves the default location
- <CURRENT_WORKING_DIR>/chrome_graph.
-
- >python endure_server.py --graph-dir=/home/user/Document/graph_dir
- Start a server which serves /home/user/Document/graph_dir which
- is where your graph code and test results are.
-"""
-
-import BaseHTTPServer
-import logging
-import optparse
-import os
-import SimpleHTTPServer
-import sys
-
-
-class HelpFormatter(optparse.IndentedHelpFormatter):
- """Format the help message of this script."""
-
- def format_description(self, description):
- """Override to keep original format of the description."""
- return description + '\n' if description else ''
-
-
-def _ParseArgs(argv):
- parser = optparse.OptionParser(
- usage='%prog [options]',
- formatter=HelpFormatter(),
- description=__doc__)
- parser.add_option(
- '-g', '--graph-dir', type='string',
- default=os.path.join(os.getcwd(), 'chrome_graph'),
- help='The directory that contains graph code ' \
- 'and data files of test results. Default value is ' \
- '<CURRENT_WORKING_DIR>/chrome_graph')
- return parser.parse_args(argv)
-
-
-def Run(argv):
- """Start an HTTP server which serves Chrome Endure graphs."""
- logging.basicConfig(format='[%(levelname)s] %(message)s', level=logging.DEBUG)
- options, _ = _ParseArgs(argv)
- graph_dir = os.path.abspath(options.graph_dir)
- cur_dir = os.getcwd()
- os.chdir(graph_dir)
- httpd = BaseHTTPServer.HTTPServer(
- ('', 0), SimpleHTTPServer.SimpleHTTPRequestHandler)
- try:
- logging.info('Serving %s at port %d', graph_dir, httpd.server_port)
- logging.info('View graphs at http://localhost:%d', httpd.server_port)
- logging.info('Press Ctrl-C to stop the server.')
- httpd.serve_forever()
- except KeyboardInterrupt:
- logging.info('Shutting down ...')
- httpd.shutdown()
- finally:
- os.chdir(cur_dir)
- return 0
-
-
-if '__main__' == __name__:
- sys.exit(Run(sys.argv[1:]))
diff --git a/chrome/test/functional/perf/endure_setup.py b/chrome/test/functional/perf/endure_setup.py
deleted file mode 100755
index dba1df4..0000000
--- a/chrome/test/functional/perf/endure_setup.py
+++ /dev/null
@@ -1,337 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Automate the setup process of Chrome Endure environment.
-
-Usage:
- python endure_setup.py [option]
-
-We use <ENDURE_DIR> to refer to the root directory in which Chrome Endure
-is set up. By default, <ENDURE_DIR> is the current working directory.
-
-First, run:
- >python endure_setup.py
-This command will automatically setup Chrome Endure in <ENDURE_DIR>.
-
-Next, run your first endure test by:
- >TEST_LENGTH=30 LOCAL_PERF_DIR="<ENDURE_DIR>/chrome_graph" \\
- python <ENDURE_DIR>/src/chrome/test/functional/perf_endure.py \\
- perf_endure.ChromeEndureGmailTest.testGmailComposeDiscard \\
-The above commands runs a Chrome Endure test for 30 seconds and saves
-the results to <ENDURE_DIR>/chrome_graph.
-
-Last, to view the graphs, run another script endure_server.py
-within <ENDURE_DIR> to start a local HTTP server that serves
-the graph directory, see endure_server.py for details.
-
-Use python endure_setup.py --help for more options.
-
-This script depends on the following modules
-(which will be downloaded automatically):
- depot_tools
- src/chrome/test/pyautolib/fetch_prebuilt_pyauto.py
-
-Supported platforms: Linux and Linux_x64.
-"""
-
-import logging
-import optparse
-import os
-import platform
-import shutil
-import subprocess
-import sys
-import urllib
-import urllib2
-import zipfile
-
-URLS = {'depot_tools': ('http://src.chromium.org'
- '/chrome/trunk/tools/depot_tools'),
- 'pyauto': ('https://src.chromium.org/'
- 'chrome/trunk/src/chrome/test/functional.DEPS'),
- 'binary': ('http://commondatastorage.googleapis.com/'
- 'chromium-browser-continuous/{os_type}/{revision}'),
- }
-
-
-class SetupError(Exception):
- """Catch errors in setting up Chrome Endure."""
- pass
-
-
-class HelpFormatter(optparse.IndentedHelpFormatter):
- """Format the help message of this script."""
-
- def format_description(self, description):
- """Override to keep the original format of the description."""
- return description + '\n' if description else ''
-
-
-def Main(argv):
- """Fetch Chrome Endure.
-
- Usage:
- python endure_setup.py [options]
-
- Examples:
- >python endure_setup.py
- Fetch the latest version of Chrome Endure to the current
- working directory.
-
- >python endure_setup.py --endure-dir=/home/user/endure_dir
- Fetch the latest version of Chrome Endure to /home/user/endure_dir.
- """
- parser = optparse.OptionParser(
- formatter=HelpFormatter(), description=Main.__doc__)
- parser.add_option(
- '-d', '--endure-dir', type='string', default=os.getcwd(),
- help='Directory in which to setup or update. ' \
- 'Default value is the current working directory.')
- # TODO(fdeng): remove this option once the Chrome Endure
- # graphing code is checked into chrome tree.
- parser.add_option(
- '-g', '--graph-zip-url', type='string', default=None,
- help='URL to a zip file containing the chrome graphs.')
- os_type = GetCurrentOSType()
- if not os_type.startswith('Linux'):
- raise SetupError('Only support Linux or Linux_x64, %s found'
- % os_type)
- options, _ = parser.parse_args(argv)
- endure_dir = os.path.abspath(options.endure_dir)
- depot_dir = os.path.join(endure_dir, 'depot_tools')
- gclient = os.path.join(depot_dir, 'gclient')
- fetch_py = os.path.join(endure_dir, 'src', 'chrome',
- 'test', 'pyautolib',
- 'fetch_prebuilt_pyauto.py')
- binary_dir = os.path.join(endure_dir, 'src', 'out', 'Release')
- graph_zip_url = options.graph_zip_url
- graph_dir = os.path.join(endure_dir, 'chrome_graph')
-
- if not os.path.isdir(endure_dir):
- os.makedirs(endure_dir)
-
- logging.info('Fetching depot tools...')
- FetchDepot(depot_dir)
- logging.info('Fetching PyAuto (python code)...')
- FetchPyAuto(gclient, endure_dir)
- logging.info('Fetching binaries(chrome, pyautolib, chrome driver)...')
- FetchBinaries(fetch_py, binary_dir, os_type)
- # TODO(fdeng): remove this after it is checked into the chrome tree.
- logging.info('Fetching chrome graphing files...')
- FetchGraph(graph_zip_url, graph_dir)
- return 0
-
-
-def FetchDepot(depot_dir):
- """Fetch depot_tools.
-
- Args:
- depot_dir: The directory where depot_tools will be checked out.
-
- Raises:
- SetupError: If fail.
- """
- if subprocess.call(['svn', 'co', URLS['depot_tools'], depot_dir]) != 0:
- raise SetupError('Error found when checking out depot_tools.')
- if not CheckDepot(depot_dir):
- raise SetupError('Could not get depot_tools.')
-
-
-def CheckDepot(depot_dir):
- """Check that some expected depot_tools files exist.
-
- Args:
- depot_dir: The directory where depot_tools are checked out.
-
- Returns:
- True if check passes otherwise False.
- """
- gclient = os.path.join(depot_dir, 'gclient')
- gclient_py = os.path.join(depot_dir, 'gclient.py')
- files = [gclient, gclient_py]
- for f in files:
- if not os.path.exists(f):
- return False
- try:
- subprocess.call([gclient, '--version'])
- except OSError:
- return False
- return True
-
-
-def FetchPyAuto(gclient, endure_dir):
- """Use gclient to fetch python code.
-
- Args:
- gclient: The path to the gclient executable.
- endure_dir: Directory where Chrome Endure and
- its dependencies will be checked out.
-
- Raises:
- SetupError: if fails.
- """
- cur_dir = os.getcwd()
- os.chdir(endure_dir)
- config_cmd = [gclient, 'config', URLS['pyauto']]
- if subprocess.call(config_cmd) != 0:
- raise SetupError('Running "%s" failed.' % ' '.join(config_cmd))
- sync_cmd = [gclient, 'sync']
- if subprocess.call(sync_cmd) != 0:
- raise SetupError('Running "%s" failed.' % ' '.join(sync_cmd))
- CheckPyAuto(endure_dir)
- logging.info('Sync PyAuto python code done.')
- os.chdir(cur_dir)
-
-
-def CheckPyAuto(endure_dir):
- """Sanity check for Chrome Endure code.
-
- Args:
- endure_dir: Directory of Chrome Endure and its dependencies.
-
- Raises:
- SetupError: If fails.
- """
- fetch_py = os.path.join(endure_dir, 'src', 'chrome',
- 'test', 'pyautolib',
- 'fetch_prebuilt_pyauto.py')
- pyauto_py = os.path.join(endure_dir, 'src',
- 'chrome', 'test',
- 'pyautolib', 'pyauto.py')
- files = [fetch_py, pyauto_py]
- for f in files:
- if not os.path.exists(f):
- raise SetupError('Checking %s failed.' % f)
-
-
-def FetchBinaries(fetch_py, binary_dir, os_type):
- """Get the prebuilt binaries from continuous build archive.
-
- Args:
- fetch_py: Path to the script which fetches pre-built binaries.
- binary_dir: Directory of the pre-built binaries.
- os_type: 'Mac', 'Win', 'Linux', 'Linux_x64'.
-
- Raises:
- SetupError: If fails.
- """
- revision = GetLatestRevision(os_type)
- logging.info('Cleaning %s', binary_dir)
- if os.path.exists(binary_dir):
- shutil.rmtree(binary_dir)
- logging.info('Downloading binaries...')
- cmd = [fetch_py, '-d', binary_dir,
- URLS['binary'].format(
- os_type=os_type, revision=revision)]
- if subprocess.call(cmd) == 0 and os.path.exists(binary_dir):
- logging.info('Binaries at revision %s', revision)
- else:
- raise SetupError('Running "%s" failed.' % ' '.join(cmd))
-
-
-def FetchGraph(graph_zip_url, graph_dir):
- """Fetch graph code.
-
- Args:
- graph_zip_url: The url to a zip file containing the chrome graphs.
- graph_dir: Directory of the chrome graphs.
-
- Raises:
- SetupError: if unable to retrive the zip file.
- """
- # TODO(fdeng): remove this function once chrome graph
- # is checked into chrome tree.
- if not graph_zip_url:
- logging.info(
- 'Skip fetching chrome graphs' +
- ' since --graph-zip-url is not set.')
- return
- graph_zip = urllib.urlretrieve(graph_zip_url)[0]
- if graph_zip is None or not os.path.exists(graph_zip):
- raise SetupError('Unable to retrieve %s' % graph_zip_url)
- if not os.path.exists(graph_dir):
- os.mkdir(graph_dir)
- UnzipFilenameToDir(graph_zip, graph_dir)
- logging.info('Graph code is downloaded to %s', graph_dir)
-
-
-def GetCurrentOSType():
- """Get a string representation for the current OS.
-
- Returns:
- 'Mac', 'Win', 'Linux', or 'Linux_64'.
-
- Raises:
- RuntimeError: if OS can't be identified.
- """
- if sys.platform == 'darwin':
- os_type = 'Mac'
- if sys.platform == 'win32':
- os_type = 'Win'
- if sys.platform.startswith('linux'):
- os_type = 'Linux'
- if platform.architecture()[0] == '64bit':
- os_type += '_x64'
- else:
- raise RuntimeError('Unknown platform')
- return os_type
-
-
-def GetLatestRevision(os_type):
- """Figure out the latest revision number of the prebuilt binary archive.
-
- Args:
- os_type: 'Mac', 'Win', 'Linux', or 'Linux_64'.
-
- Returns:
- A string of latest revision number.
-
- Raises:
- SetupError: If unable to get the latest revision number.
- """
- last_change_url = ('http://commondatastorage.googleapis.com/'
- 'chromium-browser-continuous/%s/LAST_CHANGE' % os_type)
- response = urllib2.urlopen(last_change_url)
- last_change = response.read()
- if not last_change:
- raise SetupError('Unable to get the latest revision number from %s' %
- last_change_url)
- return last_change
-
-
-def UnzipFilenameToDir(filename, directory):
- """Unzip |filename| to directory |directory|.
-
- This works with as low as python2.4 (used on win).
- (Code is adapted from fetch_prebuilt_pyauto.py)
- """
- # TODO(fdeng): remove this function as soon as the Chrome Endure
- # graphing code is checked into the chrome tree.
- zf = zipfile.ZipFile(filename)
- pushd = os.getcwd()
- if not os.path.isdir(directory):
- os.mkdir(directory)
- os.chdir(directory)
- # Extract files.
- for info in zf.infolist():
- name = info.filename
- if name.endswith('/'): # dir
- if not os.path.isdir(name):
- os.makedirs(name)
- else: # file
- directory = os.path.dirname(name)
- if directory and not os.path.isdir(directory):
- os.makedirs(directory)
- out = open(name, 'wb')
- out.write(zf.read(name))
- out.close()
- # Set permissions. Permission info in external_attr is shifted 16 bits.
- os.chmod(name, info.external_attr >> 16L)
- os.chdir(pushd)
-
-
-if '__main__' == __name__:
- logging.basicConfig(format='[%(levelname)s] %(message)s', level=logging.DEBUG)
- sys.exit(Main(sys.argv[1:]))
diff --git a/chrome/test/functional/perf_endure.py b/chrome/test/functional/perf_endure.py
deleted file mode 100755
index e647435..0000000
--- a/chrome/test/functional/perf_endure.py
+++ /dev/null
@@ -1,776 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Performance tests for Chrome Endure (long-running perf tests on Chrome).
-
-This module accepts the following environment variable inputs:
- TEST_LENGTH: The number of seconds in which to run each test.
- PERF_STATS_INTERVAL: The number of seconds to wait in-between each sampling
- of performance/memory statistics.
-
-The following variables are related to the Deep Memory Profiler.
- DEEP_MEMORY_PROFILE: Enable the Deep Memory Profiler if it's set to 'True'.
- DEEP_MEMORY_PROFILE_SAVE: Don't clean up dump files if it's set to 'True'.
- DEEP_MEMORY_PROFILE_UPLOAD: Upload dumped files if the variable has a Google
- Storage bucket like gs://chromium-endure/. The 'gsutil' script in $PATH
- is used by default, or set a variable 'GSUTIL' to specify a path to the
- 'gsutil' script. A variable 'REVISION' (or 'BUILDBOT_GOT_REVISION') is
- used as a subdirectory in the destination if it is set.
- GSUTIL: A path to the 'gsutil' script. Not mandatory.
- REVISION: A string that represents the revision or some build configuration.
- Not mandatory.
- BUILDBOT_GOT_REVISION: Similar to 'REVISION', but checked only if 'REVISION'
- is not specified. Not mandatory.
-"""
-
-from datetime import datetime
-import json
-import logging
-import os
-import re
-import subprocess
-import tempfile
-import time
-
-import perf
-import pyauto_functional # Must be imported before pyauto.
-import pyauto
-import pyauto_errors
-import pyauto_utils
-import remote_inspector_client
-import selenium.common.exceptions
-from selenium.webdriver.support.ui import WebDriverWait
-
-
-class NotSupportedEnvironmentError(RuntimeError):
- """Represent an error raised since the environment (OS) is not supported."""
- pass
-
-
-class DeepMemoryProfiler(object):
- """Controls Deep Memory Profiler (dmprof) for endurance tests."""
- DEEP_MEMORY_PROFILE = False
- DEEP_MEMORY_PROFILE_SAVE = False
- DEEP_MEMORY_PROFILE_UPLOAD = ''
-
- _WORKDIR_PATTERN = re.compile('endure\.[0-9]+\.[0-9]+\.[A-Za-z0-9]+')
- _SAVED_WORKDIRS = 8
-
- _DMPROF_DIR_PATH = os.path.abspath(os.path.join(
- os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
- 'tools', 'deep_memory_profiler'))
- _DMPROF_SCRIPT_PATH = os.path.join(_DMPROF_DIR_PATH, 'dmprof')
- _POLICIES = ['l0', 'l1', 'l2', 't0']
-
- def __init__(self):
- self._enabled = self.GetEnvironmentVariable(
- 'DEEP_MEMORY_PROFILE', bool, self.DEEP_MEMORY_PROFILE)
- self._save = self.GetEnvironmentVariable(
- 'DEEP_MEMORY_PROFILE_SAVE', bool, self.DEEP_MEMORY_PROFILE_SAVE)
- self._upload = self.GetEnvironmentVariable(
- 'DEEP_MEMORY_PROFILE_UPLOAD', str, self.DEEP_MEMORY_PROFILE_UPLOAD)
- if self._upload and not self._upload.endswith('/'):
- self._upload += '/'
-
- self._revision = ''
- self._gsutil = ''
- self._json_file = None
- self._last_json_filename = ''
- self._proc = None
- self._last_time = {}
- for policy in self._POLICIES:
- self._last_time[policy] = -1.0
-
- def __nonzero__(self):
- return self._enabled
-
- @staticmethod
- def GetEnvironmentVariable(env_name, converter, default):
- """Returns a converted environment variable for Deep Memory Profiler.
-
- Args:
- env_name: A string name of an environment variable.
- converter: A function taking a string to convert an environment variable.
- default: A value used if the environment variable is not specified.
-
- Returns:
- A value converted from the environment variable with 'converter'.
- """
- return converter(os.environ.get(env_name, default))
-
- def SetUp(self, is_linux, revision, gsutil):
- """Sets up Deep Memory Profiler settings for a Chrome process.
-
- It sets environment variables and makes a working directory.
- """
- if not self._enabled:
- return
-
- if not is_linux:
- raise NotSupportedEnvironmentError(
- 'Deep Memory Profiler is not supported in this environment (OS).')
-
- self._revision = revision
- self._gsutil = gsutil
-
- # Remove old dumped files with keeping latest _SAVED_WORKDIRS workdirs.
- # It keeps the latest workdirs not to miss data by failure in uploading
- # and other operations. Dumped files are no longer available if they are
- # removed. Re-execution doesn't generate the same files.
- tempdir = tempfile.gettempdir()
- saved_workdirs = 0
- for filename in sorted(os.listdir(tempdir), reverse=True):
- if self._WORKDIR_PATTERN.match(filename):
- saved_workdirs += 1
- if saved_workdirs > self._SAVED_WORKDIRS:
- fullpath = os.path.abspath(os.path.join(tempdir, filename))
- logging.info('Removing an old workdir: %s' % fullpath)
- pyauto_utils.RemovePath(fullpath)
-
- dir_prefix = 'endure.%s.' % datetime.today().strftime('%Y%m%d.%H%M%S')
- self._workdir = tempfile.mkdtemp(prefix=dir_prefix, dir=tempdir)
- os.environ['HEAPPROFILE'] = os.path.join(self._workdir, 'endure')
- os.environ['HEAP_PROFILE_MMAP'] = '1'
- os.environ['DEEP_HEAP_PROFILE'] = '1'
-
- def TearDown(self):
- """Tear down Deep Memory Profiler settings for the Chrome process.
-
- It removes the environment variables and the temporary directory.
- Call it after Chrome finishes. Chrome may dump last files at the end.
- """
- if not self._enabled:
- return
-
- del os.environ['DEEP_HEAP_PROFILE']
- del os.environ['HEAP_PROFILE_MMAP']
- del os.environ['HEAPPROFILE']
- if not self._save and self._workdir:
- pyauto_utils.RemovePath(self._workdir)
-
- def LogFirstMessage(self):
- """Logs first messages."""
- if not self._enabled:
- return
-
- logging.info('Running with the Deep Memory Profiler.')
- if self._save:
- logging.info(' Dumped files won\'t be cleaned.')
- else:
- logging.info(' Dumped files will be cleaned up after every test.')
-
- def StartProfiler(self, proc_info, is_last, webapp_name, test_description):
- """Starts Deep Memory Profiler in background."""
- if not self._enabled:
- return
-
- logging.info(' Profiling with the Deep Memory Profiler...')
-
- # Wait for a running dmprof process for last _GetPerformanceStat call to
- # cover last dump files.
- if is_last:
- logging.info(' Waiting for the last dmprof.')
- self._WaitForDeepMemoryProfiler()
-
- if self._proc and self._proc.poll() is None:
- logging.info(' Last dmprof is still running.')
- else:
- if self._json_file:
- self._last_json_filename = self._json_file.name
- self._json_file.close()
- self._json_file = None
- first_dump = ''
- last_dump = ''
- for filename in sorted(os.listdir(self._workdir)):
- if re.match('^endure.%05d.\d+.heap$' % proc_info['tab_pid'],
- filename):
- logging.info(' Profiled dump file: %s' % filename)
- last_dump = filename
- if not first_dump:
- first_dump = filename
- if first_dump:
- logging.info(' First dump file: %s' % first_dump)
- matched = re.match('^endure.\d+.(\d+).heap$', last_dump)
- last_sequence_id = matched.group(1)
- self._json_file = open(
- os.path.join(self._workdir,
- 'endure.%05d.%s.json' % (proc_info['tab_pid'],
- last_sequence_id)), 'w+')
- self._proc = subprocess.Popen(
- '%s json %s' % (self._DMPROF_SCRIPT_PATH,
- os.path.join(self._workdir, first_dump)),
- shell=True, stdout=self._json_file)
- if is_last:
- # Wait only when it is the last profiling. dmprof may take long time.
- self._WaitForDeepMemoryProfiler()
-
- # Upload the dumped files.
- if first_dump and self._upload and self._gsutil:
- if self._revision:
- destination_path = '%s%s/' % (self._upload, self._revision)
- else:
- destination_path = self._upload
- destination_path += '%s-%s-%s.zip' % (
- webapp_name,
- test_description,
- os.path.basename(self._workdir))
- gsutil_command = '%s upload --gsutil %s %s %s' % (
- self._DMPROF_SCRIPT_PATH,
- self._gsutil,
- os.path.join(self._workdir, first_dump),
- destination_path)
- logging.info('Uploading: %s' % gsutil_command)
- try:
- returncode = subprocess.call(gsutil_command, shell=True)
- logging.info(' Return code: %d' % returncode)
- except OSError, e:
- logging.error(' Error while uploading: %s', e)
- else:
- logging.info('Note that the dumped files are not uploaded.')
- else:
- logging.info(' No dump files.')
-
- def ParseResultAndOutputPerfGraphValues(
- self, webapp_name, test_description, output_perf_graph_value):
- """Parses Deep Memory Profiler result, and outputs perf graph values."""
- if not self._enabled:
- return
-
- results = {}
- for policy in self._POLICIES:
- if self._last_json_filename:
- json_data = {}
- with open(self._last_json_filename) as json_f:
- json_data = json.load(json_f)
- if json_data['version'] == 'JSON_DEEP_1':
- results[policy] = json_data['snapshots']
- elif json_data['version'] == 'JSON_DEEP_2':
- results[policy] = json_data['policies'][policy]['snapshots']
- for policy, result in results.iteritems():
- if result and result[-1]['second'] > self._last_time[policy]:
- started = False
- for legend in json_data['policies'][policy]['legends']:
- if legend == 'FROM_HERE_FOR_TOTAL':
- started = True
- elif legend == 'UNTIL_HERE_FOR_TOTAL':
- break
- elif started:
- output_perf_graph_value(
- legend.encode('utf-8'), [
- (int(round(snapshot['second'])), snapshot[legend] / 1024)
- for snapshot in result
- if snapshot['second'] > self._last_time[policy]],
- 'KB',
- graph_name='%s%s-%s-DMP' % (
- webapp_name, test_description, policy),
- units_x='seconds', is_stacked=True)
- self._last_time[policy] = result[-1]['second']
-
- def _WaitForDeepMemoryProfiler(self):
- """Waits for the Deep Memory Profiler to finish if running."""
- if not self._enabled or not self._proc:
- return
-
- self._proc.wait()
- self._proc = None
- if self._json_file:
- self._last_json_filename = self._json_file.name
- self._json_file.close()
- self._json_file = None
-
-
-class ChromeEndureBaseTest(perf.BasePerfTest):
- """Implements common functionality for all Chrome Endure tests.
-
- All Chrome Endure test classes should inherit from this class.
- """
-
- _DEFAULT_TEST_LENGTH_SEC = 60 * 60 * 6 # Tests run for 6 hours.
- _GET_PERF_STATS_INTERVAL = 60 * 5 # Measure perf stats every 5 minutes.
- # TODO(dennisjeffrey): Do we still need to tolerate errors?
- _ERROR_COUNT_THRESHOLD = 50 # Number of errors to tolerate.
- _REVISION = ''
- _GSUTIL = 'gsutil'
-
- def setUp(self):
- # The environment variables for the Deep Memory Profiler must be set
- # before perf.BasePerfTest.setUp() to inherit them to Chrome.
- self._dmprof = DeepMemoryProfiler()
- self._revision = str(os.environ.get('REVISION', self._REVISION))
- if not self._revision:
- self._revision = str(os.environ.get('BUILDBOT_GOT_REVISION',
- self._REVISION))
- self._gsutil = str(os.environ.get('GSUTIL', self._GSUTIL))
- if self._dmprof:
- self._dmprof.SetUp(self.IsLinux(), self._revision, self._gsutil)
-
- perf.BasePerfTest.setUp(self)
-
- self._test_length_sec = int(
- os.environ.get('TEST_LENGTH', self._DEFAULT_TEST_LENGTH_SEC))
- self._get_perf_stats_interval = int(
- os.environ.get('PERF_STATS_INTERVAL', self._GET_PERF_STATS_INTERVAL))
-
- logging.info('Running test for %d seconds.', self._test_length_sec)
- logging.info('Gathering perf stats every %d seconds.',
- self._get_perf_stats_interval)
-
- if self._dmprof:
- self._dmprof.LogFirstMessage()
-
- # Set up a remote inspector client associated with tab 0.
- logging.info('Setting up connection to remote inspector...')
- self._remote_inspector_client = (
- remote_inspector_client.RemoteInspectorClient())
- logging.info('Connection to remote inspector set up successfully.')
-
- self._test_start_time = 0
- self._num_errors = 0
- self._events_to_output = []
-
- def tearDown(self):
- logging.info('Terminating connection to remote inspector...')
- self._remote_inspector_client.Stop()
- logging.info('Connection to remote inspector terminated.')
-
- # Must be done at end of this function except for post-cleaning after
- # Chrome finishes.
- perf.BasePerfTest.tearDown(self)
-
- # Must be done after perf.BasePerfTest.tearDown()
- if self._dmprof:
- self._dmprof.TearDown()
-
- def ExtraChromeFlags(self):
- """Ensures Chrome is launched with custom flags.
-
- Returns:
- A list of extra flags to pass to Chrome when it is launched.
- """
- # The same with setUp, but need to fetch the environment variable since
- # ExtraChromeFlags is called before setUp.
- deep_memory_profile = DeepMemoryProfiler.GetEnvironmentVariable(
- 'DEEP_MEMORY_PROFILE', bool, DeepMemoryProfiler.DEEP_MEMORY_PROFILE)
-
- # Ensure Chrome enables remote debugging on port 9222. This is required to
- # interact with Chrome's remote inspector.
- # Also, enable the memory benchmarking V8 extension for heap dumps.
- extra_flags = ['--remote-debugging-port=9222',
- '--enable-memory-benchmarking']
- if deep_memory_profile:
- extra_flags.append('--no-sandbox')
- return perf.BasePerfTest.ExtraChromeFlags(self) + extra_flags
-
- def _OnTimelineEvent(self, event_info):
- """Invoked by the Remote Inspector Client when a timeline event occurs.
-
- Args:
- event_info: A dictionary containing raw information associated with a
- timeline event received from Chrome's remote inspector. Refer to
- chrome/src/third_party/WebKit/Source/WebCore/inspector/Inspector.json
- for the format of this dictionary.
- """
- elapsed_time = int(round(time.time() - self._test_start_time))
-
- if event_info['type'] == 'GCEvent':
- self._events_to_output.append({
- 'type': 'GarbageCollection',
- 'time': elapsed_time,
- 'data':
- {'collected_bytes': event_info['data']['usedHeapSizeDelta']},
- })
-
- def _RunEndureTest(self, webapp_name, tab_title_substring, test_description,
- do_scenario, frame_xpath=''):
- """The main test harness function to run a general Chrome Endure test.
-
- After a test has performed any setup work and has navigated to the proper
- starting webpage, this function should be invoked to run the endurance test.
-
- Args:
- webapp_name: A string name for the webapp being tested. Should not
- include spaces. For example, 'Gmail', 'Docs', or 'Plus'.
- tab_title_substring: A unique substring contained within the title of
- the tab to use, for identifying the appropriate tab.
- test_description: A string description of what the test does, used for
- outputting results to be graphed. Should not contain spaces. For
- example, 'ComposeDiscard' for Gmail.
- do_scenario: A callable to be invoked that implements the scenario to be
- performed by this test. The callable is invoked iteratively for the
- duration of the test.
- frame_xpath: The string xpath of the frame in which to inject javascript
- to clear chromedriver's cache (a temporary workaround until the
- WebDriver team changes how they handle their DOM node cache).
- """
- self._num_errors = 0
- self._test_start_time = time.time()
- last_perf_stats_time = time.time()
- if self._dmprof:
- self.HeapProfilerDump('renderer', 'Chrome Endure (first)')
- self._GetPerformanceStats(
- webapp_name, test_description, tab_title_substring)
- self._iteration_num = 0 # Available to |do_scenario| if needed.
-
- self._remote_inspector_client.StartTimelineEventMonitoring(
- self._OnTimelineEvent)
-
- while time.time() - self._test_start_time < self._test_length_sec:
- self._iteration_num += 1
-
- if self._num_errors >= self._ERROR_COUNT_THRESHOLD:
- logging.error('Error count threshold (%d) reached. Terminating test '
- 'early.' % self._ERROR_COUNT_THRESHOLD)
- break
-
- if time.time() - last_perf_stats_time >= self._get_perf_stats_interval:
- last_perf_stats_time = time.time()
- if self._dmprof:
- self.HeapProfilerDump('renderer', 'Chrome Endure')
- self._GetPerformanceStats(
- webapp_name, test_description, tab_title_substring)
-
- if self._iteration_num % 10 == 0:
- remaining_time = self._test_length_sec - (time.time() -
- self._test_start_time)
- logging.info('Chrome interaction #%d. Time remaining in test: %d sec.' %
- (self._iteration_num, remaining_time))
-
- do_scenario()
- # Clear ChromeDriver's DOM node cache so its growth doesn't affect the
- # results of Chrome Endure.
- # TODO(dennisjeffrey): Once the WebDriver team implements changes to
- # handle their DOM node cache differently, we need to revisit this. It
- # may no longer be necessary at that point to forcefully delete the cache.
- # Additionally, the Javascript below relies on an internal property of
- # WebDriver that may change at any time. This is only a temporary
- # workaround to stabilize the Chrome Endure test results.
- js = """
- (function() {
- delete document.$wdc_;
- window.domAutomationController.send('done');
- })();
- """
- try:
- self.ExecuteJavascript(js, frame_xpath=frame_xpath)
- except pyauto_errors.AutomationCommandTimeout:
- self._num_errors += 1
- logging.warning('Logging an automation timeout: delete chromedriver '
- 'cache.')
-
- self._remote_inspector_client.StopTimelineEventMonitoring()
-
- if self._dmprof:
- self.HeapProfilerDump('renderer', 'Chrome Endure (last)')
- self._GetPerformanceStats(
- webapp_name, test_description, tab_title_substring, is_last=True)
-
- def _GetProcessInfo(self, tab_title_substring):
- """Gets process info associated with an open browser/tab.
-
- Args:
- tab_title_substring: A unique substring contained within the title of
- the tab to use; needed for locating the tab info.
-
- Returns:
- A dictionary containing information about the browser and specified tab
- process:
- {
- 'browser_private_mem': integer, # Private memory associated with the
- # browser process, in KB.
- 'tab_private_mem': integer, # Private memory associated with the tab
- # process, in KB.
- 'tab_pid': integer, # Process ID of the tab process.
- }
- """
- browser_process_name = (
- self.GetBrowserInfo()['properties']['BrowserProcessExecutableName'])
- info = self.GetProcessInfo()
-
- # Get the information associated with the browser process.
- browser_proc_info = []
- for browser_info in info['browsers']:
- if browser_info['process_name'] == browser_process_name:
- for proc_info in browser_info['processes']:
- if proc_info['child_process_type'] == 'Browser':
- browser_proc_info.append(proc_info)
- self.assertEqual(len(browser_proc_info), 1,
- msg='Expected to find 1 Chrome browser process, but found '
- '%d instead.\nCurrent process info:\n%s.' % (
- len(browser_proc_info), self.pformat(info)))
-
- # Get the process information associated with the specified tab.
- tab_proc_info = []
- for browser_info in info['browsers']:
- for proc_info in browser_info['processes']:
- if (proc_info['child_process_type'] == 'Tab' and
- [x for x in proc_info['titles'] if tab_title_substring in x]):
- tab_proc_info.append(proc_info)
- self.assertEqual(len(tab_proc_info), 1,
- msg='Expected to find 1 %s tab process, but found %d '
- 'instead.\nCurrent process info:\n%s.' % (
- tab_title_substring, len(tab_proc_info),
- self.pformat(info)))
-
- browser_proc_info = browser_proc_info[0]
- tab_proc_info = tab_proc_info[0]
- return {
- 'browser_private_mem': browser_proc_info['working_set_mem']['priv'],
- 'tab_private_mem': tab_proc_info['working_set_mem']['priv'],
- 'tab_pid': tab_proc_info['pid'],
- }
-
- def _GetPerformanceStats(self, webapp_name, test_description,
- tab_title_substring, is_last=False):
- """Gets performance statistics and outputs the results.
-
- Args:
- webapp_name: A string name for the webapp being tested. Should not
- include spaces. For example, 'Gmail', 'Docs', or 'Plus'.
- test_description: A string description of what the test does, used for
- outputting results to be graphed. Should not contain spaces. For
- example, 'ComposeDiscard' for Gmail.
- tab_title_substring: A unique substring contained within the title of
- the tab to use, for identifying the appropriate tab.
- is_last: A boolean value which should be True if it's the last call of
- _GetPerformanceStats. The default is False.
- """
- logging.info('Gathering performance stats...')
- elapsed_time = int(round(time.time() - self._test_start_time))
-
- memory_counts = self._remote_inspector_client.GetMemoryObjectCounts()
- proc_info = self._GetProcessInfo(tab_title_substring)
-
- if self._dmprof:
- self._dmprof.StartProfiler(
- proc_info, is_last, webapp_name, test_description)
-
- # DOM node count.
- dom_node_count = memory_counts['DOMNodeCount']
- self._OutputPerfGraphValue(
- 'TotalDOMNodeCount', [(elapsed_time, dom_node_count)], 'nodes',
- graph_name='%s%s-Nodes-DOM' % (webapp_name, test_description),
- units_x='seconds')
-
- # Event listener count.
- event_listener_count = memory_counts['EventListenerCount']
- self._OutputPerfGraphValue(
- 'EventListenerCount', [(elapsed_time, event_listener_count)],
- 'listeners',
- graph_name='%s%s-EventListeners' % (webapp_name, test_description),
- units_x='seconds')
-
- # Browser process private memory.
- self._OutputPerfGraphValue(
- 'BrowserPrivateMemory',
- [(elapsed_time, proc_info['browser_private_mem'])], 'KB',
- graph_name='%s%s-BrowserMem-Private' % (webapp_name, test_description),
- units_x='seconds')
-
- # Tab process private memory.
- self._OutputPerfGraphValue(
- 'TabPrivateMemory',
- [(elapsed_time, proc_info['tab_private_mem'])], 'KB',
- graph_name='%s%s-TabMem-Private' % (webapp_name, test_description),
- units_x='seconds')
-
- # V8 memory used.
- v8_info = self.GetV8HeapStats() # First window, first tab.
- v8_mem_used = v8_info['v8_memory_used'] / 1024.0 # Convert to KB.
- self._OutputPerfGraphValue(
- 'V8MemoryUsed', [(elapsed_time, v8_mem_used)], 'KB',
- graph_name='%s%s-V8MemUsed' % (webapp_name, test_description),
- units_x='seconds')
-
- # V8 memory allocated.
- v8_mem_allocated = v8_info['v8_memory_allocated'] / 1024.0 # Convert to KB.
- self._OutputPerfGraphValue(
- 'V8MemoryAllocated', [(elapsed_time, v8_mem_allocated)], 'KB',
- graph_name='%s%s-V8MemAllocated' % (webapp_name, test_description),
- units_x='seconds')
-
- if self._dmprof:
- self._dmprof.ParseResultAndOutputPerfGraphValues(
- webapp_name, test_description, self._OutputPerfGraphValue)
-
- logging.info(' Total DOM node count: %d nodes' % dom_node_count)
- logging.info(' Event listener count: %d listeners' % event_listener_count)
- logging.info(' Browser process private memory: %d KB' %
- proc_info['browser_private_mem'])
- logging.info(' Tab process private memory: %d KB' %
- proc_info['tab_private_mem'])
- logging.info(' V8 memory used: %f KB' % v8_mem_used)
- logging.info(' V8 memory allocated: %f KB' % v8_mem_allocated)
-
- # Output any new timeline events that have occurred.
- if self._events_to_output:
- logging.info('Logging timeline events...')
- event_type_to_value_list = {}
- for event_info in self._events_to_output:
- if not event_info['type'] in event_type_to_value_list:
- event_type_to_value_list[event_info['type']] = []
- event_type_to_value_list[event_info['type']].append(
- (event_info['time'], event_info['data']))
- for event_type, value_list in event_type_to_value_list.iteritems():
- self._OutputEventGraphValue(event_type, value_list)
- self._events_to_output = []
- else:
- logging.info('No new timeline events to log.')
-
- def _GetElement(self, find_by, value):
- """Gets a WebDriver element object from the webpage DOM.
-
- Args:
- find_by: A callable that queries WebDriver for an element from the DOM.
- value: A string value that can be passed to the |find_by| callable.
-
- Returns:
- The identified WebDriver element object, if found in the DOM, or
- None, otherwise.
- """
- try:
- return find_by(value)
- except selenium.common.exceptions.NoSuchElementException:
- return None
-
- def _ClickElementByXpath(self, driver, xpath):
- """Given the xpath for a DOM element, clicks on it using WebDriver.
-
- Args:
- driver: A WebDriver object, as returned by self.NewWebDriver().
- xpath: The string xpath associated with the DOM element to click.
-
- Returns:
- True, if the DOM element was found and clicked successfully, or
- False, otherwise.
- """
- try:
- self.WaitForDomNode(xpath)
- except (pyauto_errors.JSONInterfaceError,
- pyauto_errors.JavascriptRuntimeError) as e:
- logging.exception('PyAuto exception: %s' % e)
- return False
-
- try:
- element = self._GetElement(driver.find_element_by_xpath, xpath)
- element.click()
- except (selenium.common.exceptions.StaleElementReferenceException,
- selenium.common.exceptions.TimeoutException) as e:
- logging.exception('WebDriver exception: %s' % e)
- return False
-
- return True
-
-
-class ChromeEndureControlTest(ChromeEndureBaseTest):
- """Control tests for Chrome Endure."""
-
- _WEBAPP_NAME = 'Control'
- _TAB_TITLE_SUBSTRING = 'Chrome Endure Control Test'
-
- def testControlAttachDetachDOMTree(self):
- """Continually attach and detach a DOM tree from a basic document."""
- test_description = 'AttachDetachDOMTree'
- url = self.GetHttpURLForDataPath('chrome_endure', 'endurance_control.html')
- self.NavigateToURL(url)
- loaded_tab_title = self.GetActiveTabTitle()
- self.assertTrue(self._TAB_TITLE_SUBSTRING in loaded_tab_title,
- msg='Loaded tab title does not contain "%s": "%s"' %
- (self._TAB_TITLE_SUBSTRING, loaded_tab_title))
-
- def scenario():
- # Just sleep. Javascript in the webpage itself does the work.
- time.sleep(5)
-
- self._RunEndureTest(self._WEBAPP_NAME, self._TAB_TITLE_SUBSTRING,
- test_description, scenario)
-
- def testControlAttachDetachDOMTreeWebDriver(self):
- """Use WebDriver to attach and detach a DOM tree from a basic document."""
- test_description = 'AttachDetachDOMTreeWebDriver'
- url = self.GetHttpURLForDataPath('chrome_endure',
- 'endurance_control_webdriver.html')
- self.NavigateToURL(url)
- loaded_tab_title = self.GetActiveTabTitle()
- self.assertTrue(self._TAB_TITLE_SUBSTRING in loaded_tab_title,
- msg='Loaded tab title does not contain "%s": "%s"' %
- (self._TAB_TITLE_SUBSTRING, loaded_tab_title))
-
- driver = self.NewWebDriver()
-
- def scenario(driver):
- # Click the "attach" button to attach a large DOM tree (with event
- # listeners) to the document, wait half a second, click "detach" to detach
- # the DOM tree from the document, wait half a second.
- self._ClickElementByXpath(driver, 'id("attach")')
- time.sleep(0.5)
- self._ClickElementByXpath(driver, 'id("detach")')
- time.sleep(0.5)
-
- self._RunEndureTest(self._WEBAPP_NAME, self._TAB_TITLE_SUBSTRING,
- test_description, lambda: scenario(driver))
-
-
-class IndexedDBOfflineTest(ChromeEndureBaseTest):
- """Long-running performance tests for IndexedDB, modeling offline usage."""
-
- _WEBAPP_NAME = 'IndexedDBOffline'
- _TAB_TITLE_SUBSTRING = 'IndexedDB Offline'
-
- def setUp(self):
- ChromeEndureBaseTest.setUp(self)
-
- url = self.GetHttpURLForDataPath('indexeddb', 'endure', 'app.html')
- self.NavigateToURL(url)
- loaded_tab_title = self.GetActiveTabTitle()
- self.assertTrue(self._TAB_TITLE_SUBSTRING in loaded_tab_title,
- msg='Loaded tab title does not contain "%s": "%s"' %
- (self._TAB_TITLE_SUBSTRING, loaded_tab_title))
-
- self._driver = self.NewWebDriver()
-
- def testOfflineOnline(self):
- """Simulates user input while offline and sync while online.
-
- This test alternates between a simulated "Offline" state (where user
- input events are queued) and an "Online" state (where user input events
- are dequeued, sync data is staged, and sync data is unstaged).
- """
- test_description = 'OnlineOfflineSync'
-
- def scenario():
- # Click the "Online" button and let simulated sync run for 1 second.
- if not self._ClickElementByXpath(self._driver, 'id("online")'):
- self._num_errors += 1
- logging.warning('Logging an automation error: click "online" button.')
-
- try:
- self.WaitForDomNode('id("state")[text()="online"]')
- except (pyauto_errors.JSONInterfaceError,
- pyauto_errors.JavascriptRuntimeError):
- self._num_errors += 1
- logging.warning('Logging an automation error: wait for "online".')
-
- time.sleep(1)
-
- # Click the "Offline" button and let user input occur for 1 second.
- if not self._ClickElementByXpath(self._driver, 'id("offline")'):
- self._num_errors += 1
- logging.warning('Logging an automation error: click "offline" button.')
-
- try:
- self.WaitForDomNode('id("state")[text()="offline"]')
- except (pyauto_errors.JSONInterfaceError,
- pyauto_errors.JavascriptRuntimeError):
- self._num_errors += 1
- logging.warning('Logging an automation error: wait for "offline".')
-
- time.sleep(1)
-
- self._RunEndureTest(self._WEBAPP_NAME, self._TAB_TITLE_SUBSTRING,
- test_description, scenario)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/prefetch.py b/chrome/test/functional/prefetch.py
deleted file mode 100755
index f53751d..0000000
--- a/chrome/test/functional/prefetch.py
+++ /dev/null
@@ -1,141 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-"""This functional test spawns a web server, and runs chrome to point
-at that web server.
-
-The content served contains prefetch requests, and the tests assert that the
-webserver logs reflect that.
-
-Run like any functional test:
-$ python chrome/test/functional/prefetch.py
-in a repo with a built pyautolib
-
-The import of multiprocessing implies python 2.6 is required
-"""
-
-import os
-import time
-import multiprocessing
-import Queue
-import string
-from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-
-# this class handles IPC retrieving server "logs" from our integral
-# server. Each test should clear() the log, and then run asserts on
-# the retrieval list.
-
-# at startup, the server puts an int in the queue which is its port,
-# we store that for subsequent tests
-
-class ServerLog:
- def clear(self):
- self.log = {}
-
- def __init__(self,queue):
- self.clear()
- self.port = None
- self.queue = queue
-
- def _readQueue(self):
- try:
- while True:
- queueval = self.queue.get(False)
- if isinstance(queueval,int):
- self.port = queueval
- else:
- self.log[queueval] = True
- except Queue.Empty:
- return
-
- def getPort(self):
- if not self.port:
- self._readQueue()
- return self.port
-
- def isRetrieved(self,path):
- self._readQueue()
- try:
- return self.log[path]
- except KeyError:
- return None
-
-#
-# The next few classes run a simple web server that returns log information
-# via a multiprocessing.Queue.
-#
-class AbstractPrefetchServerHandler(BaseHTTPRequestHandler):
- content = {
- "prefetch-origin.html":
- (200, """<html><head>
-<link rel="prefetch" href="static-prefetch-target.html">
-<script type="text/javascript">
-function changeParagraph()
-{
- var newPara = document.createElement("p");
- newPara.innerHTML =
- "<link rel=\\"prefetch\\" href=\\"dynamic-prefetch-target.html\\">" +
- "<p>This paragraph contains a dynamic link prefetch. " +
- "The target of this prefetch is " +
- "<a href=\\"dynamic-prefetch-target.html\\">this document.</a>";
- var para = document.getElementById("p1");
- document.body.insertBefore(newPara,para);
-}
-</script>
-</head>
-<body onload="changeParagraph()">
-<p id="p1">This is a document that contains a link prefetch. The target of
-that prefetch is <a href="static-prefetch-target.html">this document.</a>
-</body>"""),
- "static-prefetch-target.html":
- (200, "<html><head></head><body>empty</body>"),
- "dynamic-prefetch-target.html":
- (200, "<html><head></head><body>empty</body>")}
-
- def do_GET(self):
- self.queue.put(self.path[1:])
- try:
- response_code, response = self.content[self.path[1:]]
- self.send_response(response_code)
- self.end_headers()
- self.wfile.write(response)
- except KeyError:
- self.send_response(404)
- self.end_headers()
-
-def run_web_server(queue_arg):
- class PrefetchServerHandler(AbstractPrefetchServerHandler):
- queue = queue_arg
- server = HTTPServer(('',0), PrefetchServerHandler)
- queue.put(server.server_port)
- server.serve_forever()
-
-#
-# Here's the test itself
-#
-queue = multiprocessing.Queue()
-server_log = ServerLog(queue)
-
-class PrefetchTest(pyauto.PyUITest):
- """Testcase for Prefetching"""
- def testBasic(self):
- server_log.clear()
- url = "http://localhost:%d/prefetch-origin.html" % server_log.getPort()
- self.NavigateToURL(url)
- self.assertEqual(True, server_log.isRetrieved("prefetch-origin.html"))
- time.sleep(0.1) # required since prefetches occur after onload
- self.assertEqual(True, server_log.isRetrieved(
- "static-prefetch-target.html"))
- self.assertEqual(True, server_log.isRetrieved(
- "dynamic-prefetch-target.html"))
-
-if __name__ == '__main__':
- web_server = multiprocessing.Process(target=run_web_server,args=(queue,))
- web_server.daemon = True
- web_server.start()
- pyauto_functional.Main()
diff --git a/chrome/test/functional/prefs.py b/chrome/test/functional/prefs.py
deleted file mode 100755
index 7dc95ae..0000000
--- a/chrome/test/functional/prefs.py
+++ /dev/null
@@ -1,238 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import logging
-import os
-import shutil
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-import test_utils
-
-from webdriver_pages import settings
-from webdriver_pages.settings import Behaviors, ContentTypes
-
-
-class PrefsTest(pyauto.PyUITest):
- """TestCase for Preferences."""
-
- INFOBAR_TYPE = 'rph_infobar'
-
- def setUp(self):
- pyauto.PyUITest.setUp(self)
- self._driver = self.NewWebDriver()
-
- def Debug(self):
- """Test method for experimentation.
-
- This method will not run automatically.
- """
- while True:
- raw_input('Interact with the browser and hit <enter> to dump prefs... ')
- self.pprint(self.GetPrefsInfo().Prefs())
-
- def testSessionRestore(self):
- """Test session restore preference."""
- url1 = 'http://www.google.com/'
- url2 = 'http://news.google.com/'
- self.NavigateToURL(url1)
- self.AppendTab(pyauto.GURL(url2))
- num_tabs = self.GetTabCount()
- # Set pref to restore session on startup.
- self.SetPrefs(pyauto.kRestoreOnStartup, 1)
- logging.debug('Setting %s to 1' % pyauto.kRestoreOnStartup)
- self.RestartBrowser(clear_profile=False)
- self.assertEqual(self.GetPrefsInfo().Prefs(pyauto.kRestoreOnStartup), 1)
- self.assertEqual(num_tabs, self.GetTabCount())
- self.ActivateTab(0)
- self.assertEqual(url1, self.GetActiveTabURL().spec())
- self.ActivateTab(1)
- self.assertEqual(url2, self.GetActiveTabURL().spec())
-
- def testNavigationStateOnSessionRestore(self):
- """Verify navigation state is preserved on session restore."""
- urls = ('http://www.google.com/',
- 'http://news.google.com/',
- 'http://dev.chromium.org/',)
- for url in urls:
- self.NavigateToURL(url)
- self.TabGoBack()
- self.assertEqual(self.GetActiveTabURL().spec(), urls[-2])
- self.SetPrefs(pyauto.kRestoreOnStartup, 1) # set pref to restore session
- self.RestartBrowser(clear_profile=False)
- # Verify that navigation state (forward/back state) is restored.
- self.TabGoBack()
- self.assertEqual(self.GetActiveTabURL().spec(), urls[0])
- for i in (-2, -1):
- tab.GoForward()
- self.assertEqual(self.GetActiveTabURL().spec(), urls[i])
-
- def testSessionRestoreURLs(self):
- """Verify restore URLs preference."""
- url1 = self.GetFileURLForPath(os.path.join(self.DataDir(), 'title1.html'))
- url2 = self.GetFileURLForPath(os.path.join(self.DataDir(), 'title2.html'))
- # Set pref to restore given URLs on startup
- self.SetPrefs(pyauto.kRestoreOnStartup, 4) # 4 is for restoring URLs
- self.SetPrefs(pyauto.kURLsToRestoreOnStartup, [url1, url2])
- self.RestartBrowser(clear_profile=False)
- # Verify
- self.assertEqual(self.GetPrefsInfo().Prefs(pyauto.kRestoreOnStartup), 4)
- self.assertEqual(2, self.GetTabCount())
- self.ActivateTab(0)
- self.assertEqual(url1, self.GetActiveTabURL().spec())
- self.ActivateTab(1)
- self.assertEqual(url2, self.GetActiveTabURL().spec())
-
- def testGeolocationPref(self):
- """Verify geolocation pref.
-
- Checks for the geolocation infobar.
- """
- # GetBrowserInfo() call seems to fail later on in this test. Call it early.
- # crbug.com/89000
- branding = self.GetBrowserInfo()['properties']['branding']
- url = self.GetFileURLForPath(os.path.join( # triggers geolocation
- self.DataDir(), 'geolocation', 'geolocation_on_load.html'))
- self.assertEqual(3, # default state
- self.GetPrefsInfo().Prefs(pyauto.kGeolocationDefaultContentSetting))
- self.NavigateToURL(url)
- self.assertTrue(self.WaitForInfobarCount(1))
- self.assertTrue(self.GetBrowserInfo()['windows'][0]['tabs'][0]['infobars'])
- # Disable geolocation
- self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 2)
- self.assertEqual(2,
- self.GetPrefsInfo().Prefs(pyauto.kGeolocationDefaultContentSetting))
- self.ReloadTab()
- # Fails on Win7/Vista Chromium bots. crbug.com/89000
- if (self.IsWin7() or self.IsWinVista()) and branding == 'Chromium':
- return
- behavior = self._driver.execute_async_script(
- 'triggerGeoWithCallback(arguments[arguments.length - 1]);')
- self.assertEqual(
- behavior, Behaviors.BLOCK,
- msg='Behavior is "%s" when it should be BLOCKED.' % behavior)
-
- def testAllowSelectedGeoTracking(self):
- """Verify hostname pattern and behavior for allowed tracking."""
- # Default location tracking option "Ask me".
- self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 3)
- self.NavigateToURL(
- self.GetHttpURLForDataPath('geolocation', 'geolocation_on_load.html'))
- self.assertTrue(self.WaitForInfobarCount(1))
- self.PerformActionOnInfobar('accept', infobar_index=0) # Allow tracking.
- # Get the hostname pattern (e.g. http://127.0.0.1:57622).
- hostname_pattern = (
- '/'.join(self.GetHttpURLForDataPath('').split('/')[0:3]))
- self.assertEqual(
- # Allow the hostname.
- {hostname_pattern+','+hostname_pattern: {'geolocation': 1}},
- self.GetPrefsInfo().Prefs(pyauto.kContentSettingsPatternPairs))
-
- def testDismissedInfobarSavesNoEntry(self):
- """Verify dismissing infobar does not save an exception entry."""
- # Default location tracking option "Ask me".
- self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 3)
- self.NavigateToURL(
- self.GetFileURLForDataPath('geolocation', 'geolocation_on_load.html'))
- self.assertTrue(self.WaitForInfobarCount(1))
- self.PerformActionOnInfobar('dismiss', infobar_index=0)
- self.assertEqual(
- {}, self.GetPrefsInfo().Prefs(pyauto.kContentSettingsPatternPairs))
-
- def testGeolocationBlockedWhenTrackingDenied(self):
- """Verify geolocations is blocked when tracking is denied.
-
- The test verifies the blocked hostname pattern entry on the Geolocations
- exceptions page.
- """
- # Ask for permission when site wants to track.
- self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 3)
- self.NavigateToURL(
- self.GetHttpURLForDataPath('geolocation', 'geolocation_on_load.html'))
- self.assertTrue(self.WaitForInfobarCount(1))
- self.PerformActionOnInfobar('cancel', infobar_index=0) # Deny tracking.
- behavior = self._driver.execute_async_script(
- 'triggerGeoWithCallback(arguments[arguments.length - 1]);')
- self.assertEqual(
- behavior, Behaviors.BLOCK,
- msg='Behavior is "%s" when it should be BLOCKED.' % behavior)
- # Get the hostname pattern (e.g. http://127.0.0.1:57622).
- hostname_pattern = (
- '/'.join(self.GetHttpURLForDataPath('').split('/')[0:3]))
- self.assertEqual(
- # Block the hostname.
- {hostname_pattern+','+hostname_pattern: {'geolocation': 2}},
- self.GetPrefsInfo().Prefs(pyauto.kContentSettingsPatternPairs))
-
- def _CheckForVisibleImage(self, tab_index=0, windex=0):
- """Checks whether or not an image is visible on the webpage.
-
- Args:
- tab_index: Tab index. Defaults to 0 (first tab).
- windex: Window index. Defaults to 0 (first window).
-
- Returns:
- True if image is loaded, otherwise returns False if image is not loaded.
- """
- # Checks whether an image is loaded by checking the area (width
- # and height) of the image. If the area is non zero then the image is
- # visible. If the area is zero then the image is not loaded.
- # Chrome zeros the |naturalWidth| and |naturalHeight|.
- script = """
- for (i=0; i < document.images.length; i++) {
- if ((document.images[i].naturalWidth != 0) &&
- (document.images[i].naturalHeight != 0)) {
- window.domAutomationController.send(true);
- }
- }
- window.domAutomationController.send(false);
- """
- return self.ExecuteJavascript(script, windex=windex, tab_index=tab_index)
-
- def testBlockImagesForHostname(self):
- """Verify images blocked for defined hostname pattern."""
- url = 'http://www.google.com'
- page = settings.ManageExceptionsPage.FromNavigation(
- self._driver, ContentTypes.IMAGES)
- pattern, behavior = (url, Behaviors.BLOCK)
- # Add an exception BLOCK for hostname pattern 'www.google.com'.
- page.AddNewException(pattern, behavior)
- self.NavigateToURL(url)
- self.assertFalse(self._CheckForVisibleImage(),
- msg='At least one visible image found.')
-
- def testAllowImagesForHostname(self):
- """Verify images allowed for defined hostname pattern."""
- url = 'http://www.google.com'
- page = settings.ManageExceptionsPage.FromNavigation(
- self._driver, ContentTypes.IMAGES)
- pattern, behavior = (url, Behaviors.ALLOW)
- # Add an exception ALLOW for hostname pattern 'www.google.com'.
- page.AddNewException(pattern, behavior)
- self.NavigateToURL(url)
- self.assertTrue(self._CheckForVisibleImage(),
- msg='No visible images found.')
-
- def testProtocolHandlerRegisteredCorrectly(self):
- """Verify sites that ask to be default handlers registers correctly."""
- url = self.GetHttpURLForDataPath('settings', 'protocol_handler.html')
- self.NavigateToURL(url)
- # Returns a dictionary with the custom handler.
- asked_handler_dict = self._driver.execute_script(
- 'return registerCustomHandler()')
- self.PerformActionOnInfobar(
- 'accept', infobar_index=test_utils.WaitForInfobarTypeAndGetIndex(
- self, self.INFOBAR_TYPE))
- self._driver.find_element_by_id('test_protocol').click()
- self.assertTrue(
- self._driver.execute_script(
- 'return doesQueryConformsToProtocol("%s", "%s")'
- % (asked_handler_dict['query_key'],
- asked_handler_dict['query_value'])),
- msg='Protocol did not register correctly.')
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/prefs_ui.py b/chrome/test/functional/prefs_ui.py
deleted file mode 100755
index a4f0c03..0000000
--- a/chrome/test/functional/prefs_ui.py
+++ /dev/null
@@ -1,343 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import time
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-import test_utils
-
-from webdriver_pages import settings
-from webdriver_pages.settings import Behaviors, ContentTypes
-from webdriver_pages.settings import RestoreOnStartupType
-
-
-class PrefsUITest(pyauto.PyUITest):
- """TestCase for Preferences UI."""
-
- INFOBAR_TYPE = 'rph_infobar'
-
- def setUp(self):
- pyauto.PyUITest.setUp(self)
- self._driver = self.NewWebDriver()
-
- def Debug(self):
- """Test method for experimentation.
-
- This method will not run automatically.
- """
- driver = self.NewWebDriver()
- page = settings.ContentSettingsPage.FromNavigation(driver)
- import pdb
- pdb.set_trace()
-
- def _GetGeolocationContentSettingsBehavior(self):
- """Get the Content Settings behavior for Geolocation.
-
- Returns:
- The exceptions behavior for the specified content type.
- The content type is the available content setting available.
- """
- behavior_key = self.GetPrefsInfo().Prefs(
- pyauto.kGeolocationDefaultContentSetting)
- behaviors_dict = {1: 'ALLOW', 2: 'BLOCK', 3: 'ASK'}
- self.assertTrue(
- behavior_key in behaviors_dict,
- msg=('Invalid default behavior key "%s" for "geolocation" content' %
- behavior_key))
- return behaviors_dict[behavior_key]
-
- def _VerifyContentExceptionUI(self, content_type, hostname_pattern, behavior,
- incognito=False):
- """Find hostname pattern and behavior within UI on content exceptions page.
-
- Args:
- content_type: The string content settings type to manage.
- hostname_pattern: The URL or pattern associated with the behavior.
- behavior: The exception to allow or block the hostname.
- incognito: Incognito list displayed on exceptions settings page.
- Default to False.
- """
- page = settings.ManageExceptionsPage.FromNavigation(
- self._driver, content_type)
- self.assertTrue(page.GetExceptions(incognito).has_key(hostname_pattern),
- msg=('No displayed host name matches pattern "%s"'
- % hostname_pattern))
- self.assertEqual(behavior, page.GetExceptions(incognito)[hostname_pattern],
- msg=('Displayed behavior "%s" does not match behavior "%s"'
- % (page.GetExceptions(incognito)[hostname_pattern],
- behavior)))
-
- def testLocationSettingOptionsUI(self):
- """Verify the location options setting UI.
-
- Set the options through the UI using webdriver and verify the settings in
- pyAuto.
- """
- page = settings.ContentSettingsPage.FromNavigation(self._driver)
- page.SetContentTypeOption(ContentTypes.GEOLOCATION, Behaviors.ALLOW)
- self.assertEqual(
- 1, self.GetPrefsInfo().Prefs(pyauto.kGeolocationDefaultContentSetting))
- page.SetContentTypeOption(ContentTypes.GEOLOCATION, Behaviors.BLOCK)
- self.assertEqual(
- 2, self.GetPrefsInfo().Prefs(pyauto.kGeolocationDefaultContentSetting))
- page.SetContentTypeOption(ContentTypes.GEOLOCATION, Behaviors.ASK)
- self.assertEqual(
- 3, self.GetPrefsInfo().Prefs(pyauto.kGeolocationDefaultContentSetting))
-
- def testBehaviorValueCorrectlyDisplayed(self):
- """Verify the set behavior value is correctly displayed."""
- # Block all sites.
- self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 2)
- self.assertEqual(
- self._GetGeolocationContentSettingsBehavior(), Behaviors.BLOCK.upper(),
- msg='The behavior was incorrectly set.')
- # Allow all sites.
- self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 1)
- self.assertEqual(
- self._GetGeolocationContentSettingsBehavior(), Behaviors.ALLOW.upper(),
- msg='The behavior was incorrectly set.')
- # Ask for permission when site wants to track.
- self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 3)
- self.assertEqual(
- self._GetGeolocationContentSettingsBehavior(), Behaviors.ASK.upper(),
- msg='The behavior was incorrectly set.')
-
- def testExceptionsEntryCorrectlyDisplayed(self):
- """Verify the exceptions line entry is correctly displayed in the UI."""
- geo_exception = (
- {'http://maps.google.com:80,http://maps.google.com:80':
- {'geolocation': 2}})
- self.SetPrefs(pyauto.kContentSettingsPatternPairs, geo_exception)
- self._VerifyContentExceptionUI(
- ContentTypes.GEOLOCATION, 'http://maps.google.com:80',
- Behaviors.BLOCK)
- geo_exception = (
- {'http://maps.google.com:80,http://maps.google.com:80':
- {'geolocation': 1}})
- self.SetPrefs(pyauto.kContentSettingsPatternPairs, geo_exception)
- self._VerifyContentExceptionUI(
- ContentTypes.GEOLOCATION, 'http://maps.google.com:80',
- Behaviors.ALLOW)
- geo_exception = (
- {'http://maps.google.com:80,http://maps.google.com:80':
- {'geolocation': 3}})
- self.SetPrefs(pyauto.kContentSettingsPatternPairs, geo_exception)
- self._VerifyContentExceptionUI(
- ContentTypes.GEOLOCATION, 'http://maps.google.com:80', Behaviors.ASK)
-
- def testAddNewExceptionUI(self):
- """Verify new exception added for hostname pattern and behavior in UI."""
- content_type = ContentTypes.PLUGINS
- page = settings.ManageExceptionsPage.FromNavigation(
- self._driver, content_type)
-
- pattern, behavior = ('bing.com', Behaviors.BLOCK)
- page.AddNewException(pattern, behavior)
- self.assertEqual(page.GetExceptions()[pattern], Behaviors.BLOCK,
- msg='The behavior "%s" was not added for pattern "%s"'
- % (behavior, pattern))
-
- def testChangeExceptionBehaviorUI(self):
- """Verify behavior for hostname pattern is changed in the UI."""
- content_type = ContentTypes.PLUGINS
- page = settings.ManageExceptionsPage.FromNavigation(
- self._driver, content_type)
-
- pattern, behavior = ('bing.com', Behaviors.BLOCK)
- page.AddNewException(pattern, behavior)
- new_behavior = Behaviors.ALLOW
- page.SetBehaviorForPattern(pattern, new_behavior)
- self.assertEqual(page.GetExceptions()[pattern], Behaviors.ALLOW,
- msg='The behavior for "%s" did not change: "%s"'
- % (pattern, behavior))
-
- def testDeleteExceptionUI(self):
- """Verify exception deleted for hostname pattern and behavior in the UI."""
- content_type = ContentTypes.PLUGINS
- page = settings.ManageExceptionsPage.FromNavigation(
- self._driver, content_type)
-
- pattern, behavior = ('bing.com', Behaviors.BLOCK)
- page.AddNewException(pattern, behavior)
- self.assertEqual(page.GetExceptions()[pattern], Behaviors.BLOCK,
- msg='The behavior "%s" was not added for pattern "%s"'
- % (behavior, pattern))
- page.DeleteException(pattern)
- self.assertEqual(page.GetExceptions().get(pattern, KeyError), KeyError,
- msg='Pattern "%s" was not deleted' % pattern)
-
- def testNoInitialLineEntryInUI(self):
- """Verify no initial line entry is displayed in UI."""
- # Ask for permission when site wants to track.
- self.SetPrefs(pyauto.kGeolocationDefaultContentSetting, 3)
- self.assertEqual(
- 3, self.GetPrefsInfo().Prefs(pyauto.kGeolocationDefaultContentSetting))
- page = settings.ManageExceptionsPage.FromNavigation(
- self._driver, ContentTypes.GEOLOCATION)
- self.assertEqual(0, len(page.GetExceptions()))
-
- def testCorrectCookiesSessionInUI(self):
- """Verify exceptions for cookies in UI list entry."""
- # Block cookies for for a session for google.com.
- self.SetPrefs(pyauto.kContentSettingsPatternPairs,
- {'http://google.com:80': {'cookies': 2}})
- self._VerifyContentExceptionUI(
- ContentTypes.COOKIES, 'http://google.com:80', Behaviors.BLOCK)
-
- def testInitialLineEntryInIncognitoUI(self):
- """Verify initial line entry is displayed in Incognito UI."""
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW) # Display incognito list.
- page = settings.ManageExceptionsPage.FromNavigation(
- self._driver, ContentTypes.PLUGINS)
- self.assertEqual(1, len(page.GetExceptions(incognito=True)))
-
- def testIncognitoExceptionsEntryCorrectlyDisplayed(self):
- """Verify exceptions entry is correctly displayed in the incognito UI."""
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW) # Display incognito list.
- page = settings.ManageExceptionsPage.FromNavigation(
- self._driver, ContentTypes.PLUGINS)
- pattern, behavior = ('http://maps.google.com:80', Behaviors.BLOCK)
- page.AddNewException(pattern, behavior, incognito=True)
- self._VerifyContentExceptionUI(
- ContentTypes.PLUGINS, 'http://maps.google.com:80',
- Behaviors.BLOCK, incognito=True)
-
- def testSetCookieAndDeleteInContentSettings(self):
- """Verify a cookie can be deleted in the Content Settings UI."""
- # Create a cookie.
- cookie_dict = {
- 'name': 'test_cookie',
- 'value': 'test_value',
- 'expiry': time.time() + 30,
- }
- site = '127.0.0.1'
- self.NavigateToURL(self.GetHttpURLForDataPath('google', 'google.html'))
- self._driver.add_cookie(cookie_dict)
- page = settings.CookiesAndSiteDataSettings.FromNavigation(self._driver)
- page.DeleteSiteData(site)
- self.assertTrue(site not in page.GetSiteNameList(),
- 'Site "%s" was not deleted.' % site)
-
- def testRemoveMailProtocolHandler(self):
- """Verify the mail protocol handler is added and removed successfully."""
- url = self.GetHttpURLForDataPath('settings', 'protocol_handler.html')
- self.NavigateToURL(url)
- # Returns a dictionary with the mail handler that was asked for
- # registration.
- asked_handler_dict = self._driver.execute_script(
- 'return registerMailClient()')
- self.PerformActionOnInfobar(
- 'accept', infobar_index=test_utils.WaitForInfobarTypeAndGetIndex(
- self, self.INFOBAR_TYPE))
- self._driver.find_element_by_id('test_mail_protocol').click()
-
- protocol_handlers_list = (
- self.GetPrefsInfo().Prefs(pyauto.kRegisteredProtocolHandlers))
- registered_mail_handler = {}
- for handler_dict in protocol_handlers_list:
- if (handler_dict['protocol'] == 'mailto' and
- handler_dict['url'] == asked_handler_dict['url'] and
- handler_dict['title'] == asked_handler_dict['title'] and
- handler_dict.get('default')):
- registered_mail_handler = handler_dict
- break
- # Verify the mail handler is registered as asked.
- self.assertNotEqual(
- registered_mail_handler, {},
- msg='Mail protocol handler was not registered correctly.')
- # Verify the registered mail handler works as expected.
- self.assertTrue(
- self._driver.execute_script(
- 'return doesQueryConformsToProtocol("%s", "%s")'
- % (asked_handler_dict['query_key'],
- asked_handler_dict['query_value'])),
- msg='Mail protocol did not register correctly.')
-
- self._driver.get('chrome://settings-frame/handlers')
- # There are 3 DIVs in a handler entry. The last one acts as a remove button.
- # The remove button is also equivalent to setting the site to NONE.
- self._driver.find_element_by_id('handlers-list').\
- find_element_by_xpath('.//div[@role="listitem"]').\
- find_element_by_xpath('.//div[@class="handlers-site-column"]').\
- find_element_by_xpath('.//option[@value="-1"]').click()
-
- self._driver.get(url)
- self._driver.find_element_by_id('test_mail_protocol').click()
- self.assertEqual(url, self._driver.current_url,
- msg='Mail protocol still registered.')
-
-class BasicSettingsUITest(pyauto.PyUITest):
- """Testcases for uber page basic settings UI."""
-
- def setUp(self):
- pyauto.PyUITest.setUp(self)
- self._driver = self.NewWebDriver()
-
- def Debug(self):
- """chrome://plugins test debug method.
-
- This method will not run automatically.
- """
- driver = self.NewWebDriver()
- page = settings.BasicSettingsPage.FromNavigation(driver)
- import pdb
- pdb.set_trace()
-
- def testOnStartupSettings(self):
- """Verify user can set startup options."""
- page = settings.BasicSettingsPage.FromNavigation(self._driver)
- page.SetOnStartupOptions(RestoreOnStartupType.NEW_TAB_PAGE)
- self.assertEqual(RestoreOnStartupType.NEW_TAB_PAGE,
- self.GetPrefsInfo().Prefs(pyauto.kRestoreOnStartup))
- page.SetOnStartupOptions(RestoreOnStartupType.RESTORE_SESSION)
- self.assertEqual(RestoreOnStartupType.RESTORE_SESSION,
- self.GetPrefsInfo().Prefs(pyauto.kRestoreOnStartup))
- page.SetOnStartupOptions(RestoreOnStartupType.RESTORE_URLS)
- self.assertEqual(RestoreOnStartupType.RESTORE_URLS,
- self.GetPrefsInfo().Prefs(pyauto.kRestoreOnStartup))
-
- def testSetStartupPages(self):
- """Verify user can add urls for startup pages."""
- page = settings.BasicSettingsPage.FromNavigation(self._driver)
- for url in ['www.google.com', 'http://www.amazon.com', 'ebay.com']:
- page.AddStartupPage(url)
- self.assertEqual(RestoreOnStartupType.RESTORE_URLS,
- self.GetPrefsInfo().Prefs(pyauto.kRestoreOnStartup))
- startup_urls = self.GetPrefsInfo().Prefs(pyauto.kURLsToRestoreOnStartup)
- self.assertEqual(startup_urls[0], 'http://www.google.com/')
- self.assertEqual(startup_urls[1], 'http://www.amazon.com/')
- self.assertEqual(startup_urls[2], 'http://ebay.com/')
-
- def testUseCurrentPagesForStartup(self):
- """Verify user can start up browser using current pages."""
- page = settings.BasicSettingsPage.FromNavigation(self._driver)
- self.OpenNewBrowserWindow(True)
- url1 = self.GetHttpURLForDataPath('title2.html')
- url2 = self.GetHttpURLForDataPath('title3.html')
- self.NavigateToURL(url1, 1, 0)
- self.AppendTab(pyauto.GURL(url2), 1)
- title_list = ['Title Of Awesomeness',
- 'Title Of More Awesomeness']
- page.UseCurrentPageForStartup(title_list)
- page.VerifyStartupURLs(title_list)
- self.assertEqual(RestoreOnStartupType.RESTORE_URLS,
- self.GetPrefsInfo().Prefs(pyauto.kRestoreOnStartup))
- startup_urls = self.GetPrefsInfo().Prefs(pyauto.kURLsToRestoreOnStartup)
- self.assertEqual(len(startup_urls), 3)
- self.assertEqual(startup_urls[1], url1)
- self.assertEqual(startup_urls[2], url2)
-
- def testCancelStartupURLSetting(self):
- """Verify canceled start up URLs settings are not saved."""
- page = settings.BasicSettingsPage.FromNavigation(self._driver)
- for url in ['www.google.com', 'http://www.amazon.com']:
- page.CancelStartupURLSetting(url)
- startup_urls = self.GetPrefsInfo().Prefs(pyauto.kURLsToRestoreOnStartup)
- self.assertEqual(len(startup_urls), 0)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/pyauto_functional.py b/chrome/test/functional/pyauto_functional.py
deleted file mode 100755
index fa9b8a5..0000000
--- a/chrome/test/functional/pyauto_functional.py
+++ /dev/null
@@ -1,123 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Setup for PyAuto functional tests.
-
-Use the following in your scripts to run them standalone:
-
-# This should be at the top
-import pyauto_functional
-
-if __name__ == '__main__':
- pyauto_functional.Main()
-
-This script can be used as an executable to fire off other scripts, similar
-to unittest.py
- python pyauto_functional.py test_script
-"""
-
-import os
-import subprocess
-import sys
-
-
-def _LocatePyAutoDir():
- sys.path.append(os.path.join(os.path.dirname(__file__),
- os.pardir, 'pyautolib'))
-
-
-_LocatePyAutoDir()
-import pyauto_paths
-
-
-def RunWithCorrectPythonIfNecessary():
- """Runs this script with the correct version of python if necessary.
-
- Different platforms and versions of pyautolib use different python versions.
- Instead of requiring testers and infrastructure to handle choosing the right
- version (and architecture), this will rerun the script with the correct
- version of python.
-
- Note, this function will either return after doing nothing, or will exit with
- the subprocess's return code.
- """
- def RunAgain():
- """Run the script again with the correct version of python.
-
- Note, this function does not return, but exits with the return code of the
- child.
- """
- if sys.platform == 'cygwin' or sys.platform.startswith('win'):
- cmd = [sys.executable]
- elif sys.platform.startswith('darwin'):
- # Arch runs the specified architecture of a universal binary. Run
- # the 32 bit one.
- cmd = ['arch', '-i386', 'python2.6']
- elif sys.platform.startswith('linux'):
- cmd = ['python2.6']
-
- cmd.extend(sys.argv)
- print 'Running:', ' '.join(cmd)
- proc = subprocess.Popen(cmd)
- proc.wait()
- sys.exit(proc.returncode)
-
- def IsChromeOS():
- lsb_release = '/etc/lsb-release'
- if sys.platform.startswith('linux') and os.path.isfile(lsb_release):
- with open(lsb_release) as fp:
- contents = fp.read()
- return 'CHROMEOS_RELEASE_NAME=' in contents
- return False
-
- # Ensure this is the right python version (2.6 for chrome, 2.7 for chromeOS).
- if IsChromeOS():
- if sys.version_info[0:2] != (2, 7):
- cmd = ['python2.7'] + sys.argv
- print 'Running: ', ' '.join(cmd)
- proc = subprocess.Popen(cmd)
- proc.wait()
- else:
- if sys.version_info[0:2] != (2, 6):
- RunAgain()
-
- # Check this is the right bitness on mac.
- # platform.architecture() will not help us on mac, since multiple binaries
- # are stuffed inside the universal python binary.
- if sys.platform.startswith('darwin') and sys.maxint > 2**32:
- # User is running 64-bit python, but we should use 32-bit.
- RunAgain()
-
-
-# Do not attempt to figure out python versions if
-# DO_NOT_RESTART_PYTHON_FOR_PYAUTO is set.
-if os.getenv('DO_NOT_RESTART_PYTHON_FOR_PYAUTO') is None:
- RunWithCorrectPythonIfNecessary()
-else:
- print 'Will not try to restart with the correct version of python '\
- 'as DO_NOT_RESTART_PYTHON_FOR_PYAUTO is set.'
-
-
-try:
- import pyauto
-except ImportError:
- print >>sys.stderr, 'Cannot import pyauto from %s' % sys.path
- raise
-
-
-class Main(pyauto.Main):
- """Main program for running PyAuto functional tests."""
-
- def __init__(self):
- # Make scripts in this dir importable
- sys.path.append(os.path.dirname(__file__))
- pyauto.Main.__init__(self)
-
- def TestsDir(self):
- return os.path.dirname(__file__)
-
-
-if __name__ == '__main__':
- Main()
diff --git a/chrome/test/functional/pyauto_webdriver.py b/chrome/test/functional/pyauto_webdriver.py
deleted file mode 100755
index deb39c0..0000000
--- a/chrome/test/functional/pyauto_webdriver.py
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import pyauto_functional
-import pyauto
-
-
-class PyAutoWebDriverTest(pyauto.PyUITest):
- """Tests PyAuto-WebDriver integration."""
-
- def testTypeIntoTextBox(self):
- """Type into a text input box and verify its value."""
- driver = self.NewWebDriver()
- driver.get('about:blank')
- driver.execute_script('document.body.innerHTML = "<input type=\'text\'>"')
- input = driver.find_element_by_tag_name('input')
- self.assertEquals('', input.get_attribute('value'))
- input.send_keys('test')
- self.assertEquals('test', input.get_attribute('value'))
-
- def testCanConnectToRestartedBrowser(self):
- """Restart the browser and connect again with WebDriver."""
- driver = self.NewWebDriver()
- self.RestartBrowser()
- driver = self.NewWebDriver()
- driver.get('about:blank')
- self.assertEquals('about:blank', driver.title)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/remote_host_functional.py b/chrome/test/functional/remote_host_functional.py
deleted file mode 100755
index 4d9209d..0000000
--- a/chrome/test/functional/remote_host_functional.py
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import sys
-
-import pyauto_functional
-import pyauto
-import remote_host
-
-
-if __name__ == '__main__':
- pyauto_suite = pyauto.PyUITestSuite(sys.argv)
- remote_host.RemoteHost(('', 7410))
- del pyauto_suite
diff --git a/chrome/test/functional/rlz/rlztest.py b/chrome/test/functional/rlz/rlztest.py
deleted file mode 100755
index 3d89514..0000000
--- a/chrome/test/functional/rlz/rlztest.py
+++ /dev/null
@@ -1,270 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import chromium_proxy_server_ex
-import commands
-import logging
-import optparse
-import os
-import re
-import selenium.selenium
-import shutil
-import subprocess
-import sys
-import tempfile
-import time
-import unittest
-import _winreg
-import selenium.webdriver.common.keys
-
-from selenium import webdriver
-from selenium.webdriver.common.keys import Keys as Keys
-from selenium.webdriver.support.ui import WebDriverWait
-
-class RlzTest(unittest.TestCase):
-
- proxy_server_file = ''
- chrome_driver_path = ''
-
- def setUp(self):
- """Performs necessary setup work before running each test in this class."""
- # Delete RLZ key Folder
- self.deleteRegistryKey()
- # Launch Proxy Server
- print ('Serving clients: 127.0.0.1')
- self.proxy_server = subprocess.Popen([
- 'python',
- RlzTest.proxy_server_file,
- '--client=127.0.0.1',
- '--port=8080',
- '--urls=http://clients1.google.com/tools/pso/ping,www.google.com'])
- print('\nLaunching Chrome...')
- # Launch chrome and set proxy.
- self.temp_data_dir = tempfile.mkdtemp()
- self.launchChrome(self.temp_data_dir)
-
- def tearDown(self):
- """Kills the chrome driver after after the test method has been called."""
- # Terminate the chrome driver.
- print '\nTerminating Chrome Driver...'
- self.driver.quit()
-
- # Kill proxy server.
- print '\nKilling Proxy Server...'
- subprocess.Popen.kill(self.proxy_server)
-
- # Delete temp profile directory
- try:
- shutil.rmtree(self.temp_data_dir) # delete directory
- except OSError, e:
- if e.errno != 2: # code 2 - no such file or directory
- raise
-
- def launchChrome(self, data_directory):
- """Launch chrome using chrome driver.
-
- Args:
- data_directory: Temp directory to store preference data.
- """
- service = webdriver.chrome.service.Service(RlzTest.chrome_driver_path)
- service.start()
- self.driver = webdriver.Remote(
- service.service_url, {
- 'proxy': {'proxyType': 'manual', 'httpProxy': 'localhost:8080'},
- 'chrome.nativeEvents': True,
- 'chrome.switches': ['disable-extensions',
- r'user-data-dir=' + data_directory]})
-
- def deleteRegistryKey(self):
- """Delete RLZ key Folder from win registry."""
- try:
- hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER,
- 'Software\\Google\\Common\\Rlz')
- except _winreg.error, err:
- return True
- if(hkey):
- _winreg.DeleteKey(_winreg.HKEY_CURRENT_USER,
- 'Software\\Google\\Common\\Rlz\\Events\\C')
- _winreg.DeleteKey(_winreg.HKEY_CURRENT_USER,
- 'Software\\Google\\Common\\Rlz\\StatefulEvents\\C')
- _winreg.DeleteKey(_winreg.HKEY_CURRENT_USER,
- 'Software\\Google\\Common\\Rlz\\Events')
- _winreg.DeleteKey(_winreg.HKEY_CURRENT_USER,
- 'Software\\Google\\Common\\Rlz\\StatefulEvents')
- _winreg.DeleteKey(_winreg.HKEY_CURRENT_USER,
- 'Software\\Google\\Common\\Rlz\\PTimes')
- _winreg.DeleteKey(_winreg.HKEY_CURRENT_USER,
- 'Software\\Google\\Common\\Rlz\\RLZs')
- _winreg.DeleteKey(_winreg.HKEY_CURRENT_USER,
- 'Software\\Google\\Common\\Rlz')
-
- def GetKeyValueNames(self, key, subkey):
- """Get the values for particular subkey
-
- Args:
- key: Key is one of the predefined HKEY_* constants.
- subkey: It is a string that identifies the sub_key to delete.
- """
- list_names = []
- counter = 0
- try:
- hkey = _winreg.OpenKey(key, subkey)
- except _winreg.error, err:
- return -1
- while True:
- try:
- value = _winreg.EnumValue(hkey, counter)
- list_names.append(value[0])
- counter += 1
- except _winreg.error:
- break
- hkey.Close()
- return list_names
-
- def _AssertEventsInPing(self, log_file, excepted_event_list, readFile=1):
- """ Asserts events in ping appended.
-
- Args:
- contents: String variable contains contents of log file.
- excepted_event_list: List of expected events in ping.
- readFile: Reading order for file. Default is 1 (Top to Bottom).
- """
- for line in log_file[::readFile]:
- if(re.search('events=', line)):
- event_start = line.find('events=')
- event_end = line.find('&rep', event_start)
- events = line[event_start + 7 : event_end]
- events_List = events.split(',')
- print 'event_list',events_List
- break
- # Validate events in url ping.
- for event in excepted_event_list:
- self.assertTrue(event in events_List)
- # Validate brand code in url ping.
- self.assertTrue(re.search('CHMZ', line))
- # Print first chrome launch ping on Console.
- start = line.find('http://clients1.google.com/tools/'+
- 'pso/ping?as=chrome&brand=CHMZ')
- end = line.find('http://www', start)
- print '\nChrome Launch ping sent :\n', line[start:end]
-
-
- def _AssertEventsInRegistry(self, excepted_reg_keys):
- """ Asserts events reported in win registry.
-
- Args:
- excepted_reg_keys: List of expected events in win registry.
- """
- list_key=self.GetKeyValueNames(_winreg.HKEY_CURRENT_USER,
- 'Software\Google\Common\Rlz\StatefulEvents\C')
- print ('\nList of event reported to registry-'
- 'Software\Google\Common\Rlz\StatefulEvents:', list_key)
- for key in excepted_reg_keys:
- self.assertTrue(key in list_key)
-
- def _AssertRlzValues(self, log_file, readFile=1):
- """ Asserts RLZ values.
-
- Args:
- log_file: String variable contains contents of log file.
- readFile: Reading order for file. Default is 1 (Top to Bottom).
- """
- for line in log_file[::readFile]:
- if(re.search('events=', line)):
- event_start = line.find('rlz=')
- event_end = line.find('&id', event_start)
- events = line[event_start + 4 : event_end]
- events_List = events.split(',')
- self.assertTrue('C1:' in events_List)
- self.assertTrue('C2:' in events_List)
-
- def _searchFromOmnibox(self, searchString):
- """ Asserts RLZ values.
-
- Args:
- searchString: Input string to be searched.
- """
- self.driver.switch_to_active_element().send_keys(Keys.CONTROL + 'l')
- self.driver.switch_to_active_element().send_keys(searchString)
- self.driver.switch_to_active_element().send_keys(Keys.ENTER)
- time.sleep(2)
-
- def testRlzPingAtFirstChromeLaunch(self):
- """Test rlz ping when chrome is launched for first time."""
- # Wait for 100 sec till chrome sends ping to server.
- time.sleep(100)
- self.driver.get('http://www.google.com')
-
- # Open log file.
- log_file = open(
- os.getcwd() + '\chromium_proxy_server.log', 'r', 1).readlines()
-
- # Validate events first chrome launch(C1I,C2I,C1S) are appended in ping.
- excepted_events = ['C1S', 'C1I', 'C2I']
- self._AssertEventsInPing(log_file, excepted_events)
-
- # Validate events in win registry.
- excepted_reg_keys = ['C1I', 'C2I']
- self._AssertEventsInRegistry(excepted_reg_keys)
-
- def testRlzPingForFirstSearch(self):
- """Test rlz ping when first search is performed in chrome."""
- # Type search string in omnibox.
- self._searchFromOmnibox('java')
- print '\nCurrent Url before chrome ping sent:\n', self.driver.current_url
-
- # Assert brand code 'CHMZ' is not appended in search string.
- self.assertFalse(re.search('CHMZ', self.driver.current_url))
-
- # Wait for 100 sec till chrome sends ping to server.
- time.sleep(100)
-
- # Open log file.
- log_file = open(
- os.getcwd() + '\chromium_proxy_server.log', 'r', 1).readlines()
-
- # Validate events first chrome launch(C1I,C2I,C1S) and
- # first search(C1F) are appended in ping.
- excepted_events = ['C1S', 'C1I', 'C2I', 'C1F']
- self._AssertEventsInPing(log_file, excepted_events)
-
- # Assert C1, C2 rlz value appended in ping
- self._AssertRlzValues(log_file)
-
- # Type search string in omnibox after ping is sent to server.
- self._searchFromOmnibox('java')
- print '\nCurrent Url after chrome ping sent:\n', self.driver.current_url
-
- # Assert brand code 'CHMZ' is appended in search string.
- self.assertTrue(re.search('CHMZ', self.driver.current_url))
-
- # Validate events in win registry.
- excepted_reg_keys=['C1I', 'C2I', 'C1F']
- self._AssertEventsInRegistry(excepted_reg_keys)
-
- # Assert the log for search ping with query string/brand code appended.
- log_file = open(
- os.getcwd() + '\chromium_proxy_server.log', 'r', 1).readlines()
- searchStringFound = False
- for line in log_file[::-1]:
- if(re.search('search?', line)):
- self.assertTrue(re.search('java', line))
- self.assertTrue(re.search('CHMZ', line))
- print '\nChrome search ping send\n', line
- searchStringFound = True
- break
- self.assertTrue(searchStringFound, 'Search Query String Not Found')
-
-def rlzInput():
- proxy_server_file = raw_input("Enter Proxy Server File Name: ")
- chrome_driver_path = raw_input("Enter chrome driver path in"+
- "your system(c:\\chrome\\..):")
- return (proxy_server_file, chrome_driver_path)
-
-if __name__ == '__main__':
- server, driver = rlzInput()
- RlzTest.proxy_server_file = server
- RlzTest.chrome_driver_path = driver
- unittest.main()
diff --git a/chrome/test/functional/search_engines.py b/chrome/test/functional/search_engines.py
deleted file mode 100755
index 2fcf9e8..0000000
--- a/chrome/test/functional/search_engines.py
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import re
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-import test_utils
-
-
-class SearchEnginesTest(pyauto.PyUITest):
- """TestCase for Search Engines."""
-
- _localhost_prefix = 'http://localhost:1000/'
-
- def _GetSearchEngineWithKeyword(self, keyword):
- """Get search engine info and return an element that matches keyword.
-
- Args:
- keyword: Search engine keyword field.
-
- Returns:
- A search engine info dict or None.
- """
- match_list = ([x for x in self.GetSearchEngineInfo()
- if x['keyword'] == keyword])
- if match_list:
- return match_list[0]
- return None
-
- def Debug(self):
- """Test method for experimentation.
-
- This method will not run automatically.
- """
- while True:
- raw_input('Interact with the browser and hit <enter>')
- self.pprint(self.GetSearchEngineInfo())
-
- def testDiscoverSearchEngine(self):
- """Test that chrome discovers youtube search engine after searching."""
- # Take a snapshot of current search engine info.
- info = self.GetSearchEngineInfo()
- youtube = self._GetSearchEngineWithKeyword('youtube.com')
- self.assertFalse(youtube)
- # Use omnibox to invoke search engine discovery.
- # Navigating using NavigateToURL does not currently invoke this logic.
- self.SetOmniboxText('http://www.youtube.com')
- self.OmniboxAcceptInput()
- def InfoUpdated(old_info):
- new_info = self.GetSearchEngineInfo()
- if len(new_info) > len(old_info):
- return True
- return False
- self.WaitUntil(lambda: InfoUpdated(info))
- youtube = self._GetSearchEngineWithKeyword('youtube.com')
- self.assertTrue(youtube)
- self.assertTrue(re.search('youtube', youtube['short_name'],
- re.IGNORECASE))
- self.assertFalse(youtube['in_default_list'])
- self.assertFalse(youtube['is_default'])
-
- def testDeleteSearchEngine(self):
- """Test adding then deleting a search engine."""
- self.AddSearchEngine(title='foo',
- keyword='foo.com',
- url='http://foo/?q=%s')
- foo = self._GetSearchEngineWithKeyword('foo.com')
- self.assertTrue(foo)
- self.DeleteSearchEngine('foo.com')
- foo = self._GetSearchEngineWithKeyword('foo.com')
- self.assertFalse(foo)
-
- def testMakeSearchEngineDefault(self):
- """Test adding then making a search engine default."""
- self.AddSearchEngine(
- title='foo',
- keyword='foo.com',
- url=self._localhost_prefix + '?q=%s')
- foo = self._GetSearchEngineWithKeyword('foo.com')
- self.assertTrue(foo)
- self.assertFalse(foo['is_default'])
- self.MakeSearchEngineDefault('foo.com')
- foo = self._GetSearchEngineWithKeyword('foo.com')
- self.assertTrue(foo)
- self.assertTrue(foo['is_default'])
- self.SetOmniboxText('foobar')
- self.OmniboxAcceptInput()
- self.assertEqual(self._localhost_prefix + '?q=foobar',
- self.GetActiveTabURL().spec())
-
- def testDefaultSearchEngines(self):
- """Test that we have 3 default search options."""
- info = self.GetSearchEngineInfo()
- self.assertEqual(len(info), 3)
- # Verify that each can be used as the default search provider.
- default_providers = ['google.com', 'yahoo.com', 'bing.com']
- for keyword in default_providers:
- self.MakeSearchEngineDefault(keyword)
- search_engine = self._GetSearchEngineWithKeyword(keyword)
- self.assertTrue(search_engine['is_default'])
- self.SetOmniboxText('test search')
- self.OmniboxAcceptInput()
- self.assertTrue(re.search(keyword, self.GetActiveTabURL().spec()))
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/secure_shell.py b/chrome/test/functional/secure_shell.py
deleted file mode 100755
index d9e59a6..0000000
--- a/chrome/test/functional/secure_shell.py
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import glob
-import logging
-import os
-import time
-
-import pyauto_functional # must be imported before pyauto
-import pyauto
-
-
-class SecureShellTest(pyauto.PyUITest):
- """Tests for Secure Shell app.
-
- Uses app from chrome/test/data/extensions/secure_shell/.
- The test uses stable app by default.
- Set the env var SECURE_SHELL_USE_DEV=1 to make it use the dev one.
- """
-
- assert pyauto.PyUITest.IsChromeOS(), 'Works on ChromeOS only'
-
- def setUp(self):
- """Install secure shell app at startup."""
- pyauto.PyUITest.setUp(self)
-
- # Pick app from data dir.
- app_dir = os.path.join(os.path.abspath(
- self.DataDir()), 'extensions', 'secure_shell')
- channel = 'dev' if os.getenv('SECURE_SHELL_USE_DEV') else 'stable'
- files = glob.glob(os.path.join(app_dir, 'SecureShell-%s-*.crx' % channel))
- assert files, 'Secure Shell %s app missing in %s' % (channel, app_dir)
- app_path = files[0]
-
- # Install app.
- logging.debug('Using Secure shell app %s' % app_path)
- self._app_id = self.InstallExtension(app_path, from_webstore=True)
-
- def testInstall(self):
- """Install Secure Shell."""
- # Installation already done in setUp. Just verify.
- self.assertTrue(self._app_id)
- ssh_info = [x for x in self.GetExtensionsInfo()
- if x['id'] == self._app_id][0]
- self.assertTrue(ssh_info)
- # Uninstall.
- self.UninstallExtensionById(id=self._app_id)
- self.assertFalse([x for x in self.GetExtensionsInfo()
- if x['id'] == self._app_id],
- msg='Could not uninstall.')
-
- def testLaunch(self):
- """Launch Secure Shell and verify basic connect/exit flow.
-
- This basic flow also verifies that NaCl works since secure shell is based
- on it.
- """
- self.assertEqual(1, self.GetTabCount())
- then = time.time()
- self.LaunchApp(self._app_id)
- login_ui_frame = (
- '/descendant::iframe[contains(@src, "nassh_connect_dialog.html")]')
- # Wait for connection dialog iframe to load.
- self.WaitForDomNode(login_ui_frame, tab_index=1,
- msg='Secure shell login dialog did not show up')
- self.WaitForDomNode('id("field-description")', tab_index=1,
- attribute='placeholder',
- expected_value='username@hostname', # partial match
- frame_xpath=login_ui_frame,
- msg='Did not find secure shell username dialog')
- now = time.time()
- self.assertEqual(2, self.GetTabCount(), msg='Did not launch')
- logging.info('Launched Secure Shell in %.2f secs' % (now - then))
-
- # Fill in chronos@localhost using webdriver.
- driver = self.NewWebDriver()
- driver.switch_to_window(driver.window_handles[-1]) # last tab
- driver.switch_to_frame(1)
- user = 'chronos@localhost'
- driver.find_element_by_id('field-description').send_keys(user + '\n')
-
- # Verify yes/no prompt
- self.WaitForHtermText('continue connecting \(yes/no\)\?', tab_index=1,
- msg='Did not get the yes/no prompt')
- welcome_text = self.GetHtermRowsText(0, 8, tab_index=1)
- self.assertTrue('Welcome to Secure Shell' in welcome_text,
- msg='Did not get correct welcome message')
-
- # Type 'yes' and enter password
- self.SendKeysToHterm('yes\\n', tab_index=1)
- self.WaitForHtermText('Password:', tab_index=1,
- msg='Did not get password prompt')
- self.SendKeysToHterm('test0000\\n', tab_index=1)
- self.WaitForHtermText('chronos@localhost $', tab_index=1,
- msg='Did not get shell login prompt')
-
- # Type 'exit' and close the tab
- self.SendKeysToHterm('exit\\n', tab_index=1)
- # Check for only 'code 0' since that is what indicates that we exited
- # successfully. Checking for more stringage causes flakes since the exit
- # string does change at times.
- self.WaitForHtermText('code 0', tab_index=1,
- msg='Did not get correct exit message')
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/special_tabs.py b/chrome/test/functional/special_tabs.py
deleted file mode 100755
index b53d110..0000000
--- a/chrome/test/functional/special_tabs.py
+++ /dev/null
@@ -1,328 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import logging
-import os
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-import test_utils
-
-class SpecialTabsTest(pyauto.PyUITest):
- """TestCase for Special Tabs like about:version, chrome://history, etc."""
-
- @staticmethod
- def GetSpecialAcceleratorTabs():
- """Get a dict of accelerators and corresponding tab titles."""
- ret = {
- pyauto.IDC_SHOW_HISTORY: 'History',
- pyauto.IDC_MANAGE_EXTENSIONS: 'Extensions',
- pyauto.IDC_SHOW_DOWNLOADS: 'Downloads',
- }
- return ret
-
- special_url_redirects = {
- 'about:': 'chrome://version',
- 'about:about': 'chrome://about',
- 'about:appcache-internals': 'chrome://appcache-internals',
- 'about:credits': 'chrome://credits',
- 'about:dns': 'chrome://dns',
- 'about:histograms': 'chrome://histograms',
- 'about:plugins': 'chrome://plugins',
- 'about:sync': 'chrome://sync-internals',
- 'about:sync-internals': 'chrome://sync-internals',
- 'about:version': 'chrome://version',
- }
-
- special_url_tabs = {
- 'chrome://about': { 'title': 'Chrome URLs' },
- 'chrome://appcache-internals': { 'title': 'AppCache Internals' },
- 'chrome://blob-internals': { 'title': 'Blob Storage Internals' },
- 'chrome://feedback': {},
- 'chrome://chrome-urls': { 'title': 'Chrome URLs' },
- 'chrome://crashes': { 'title': 'Crashes' },
- 'chrome://credits': { 'title': 'Credits' },
- 'chrome://downloads': { 'title': 'Downloads' },
- 'chrome://dns': { 'title': 'About DNS' },
- 'chrome://extensions': { 'title': 'Extensions' },
- 'chrome://flags': {},
- 'chrome://flash': {},
- 'chrome://gpu-internals': {},
- 'chrome://invalidations': { 'title': 'Invalidations' },
- 'chrome://histograms': { 'title': 'About Histograms' },
- 'chrome://history': { 'title': 'History' },
- 'chrome://inspect': { 'title': 'Inspect with Chrome Developer Tools' },
- 'chrome://media-internals': { 'title': 'Media Internals' },
- 'chrome://memory-redirect': { 'title': 'About Memory' },
- 'chrome://net-internals': {},
- 'chrome://net-internals/help.html': {},
- 'chrome://newtab': { 'title': 'New Tab', 'CSP': False },
- 'chrome://plugins': { 'title': 'Plug-ins' },
- 'chrome://settings': { 'title': 'Settings' },
- 'chrome://settings/autofill': { 'title': 'Settings - Autofill settings' },
- 'chrome://settings/clearBrowserData':
- { 'title': 'Settings - Clear browsing data' },
- 'chrome://settings/content': { 'title': 'Settings - Content settings' },
- 'chrome://settings/languages':
- { 'title': 'Settings - Languages' },
- 'chrome://settings/passwords': { 'title': 'Settings - Passwords' },
- 'chrome://stats': {},
- 'chrome://sync': { 'title': 'Sync Internals' },
- 'chrome://sync-internals': { 'title': 'Sync Internals' },
- 'chrome://terms': {},
- 'chrome://version': { 'title': 'About Version' },
- 'chrome://view-http-cache': {},
- 'chrome://webrtc-internals': { 'title': 'WebRTC Internals' },
- }
- broken_special_url_tabs = {
- # crashed under debug when invoked from location bar (bug 88223).
- 'chrome://devtools': { 'CSP': False },
-
- # returns "not available" despite having an URL constant.
- 'chrome://dialog': { 'CSP': False },
-
- # separate window on mac, PC untested, not implemented elsewhere.
- 'chrome://ipc': { 'CSP': False },
-
- # race against redirects via meta-refresh.
- 'chrome://memory': { 'CSP': False },
- }
-
- chromeos_special_url_tabs = {
- 'chrome://choose-mobile-network': { 'title': 'undefined', 'CSP': True },
- 'chrome://flags': { 'CSP': True },
- 'chrome://imageburner': { 'title':'Create a Recovery Media', 'CSP': True },
- 'chrome://keyboardoverlay': { 'title': 'Keyboard Overlay', 'CSP': True },
- 'chrome://network': { 'title': 'About Network' },
- 'chrome://os-credits': { 'title': 'Credits', 'CSP': False },
- 'chrome://proxy-settings': { 'CSP': False },
- 'chrome://register': { 'CSP': False },
- 'chrome://settings/languages':
- { 'title': 'Settings - Languages and input' },
- 'chrome://sim-unlock': { 'title': 'Enter SIM card PIN', 'CSP': False },
- 'chrome://system': { 'title': 'About System', 'CSP': False },
-
- # OVERRIDE - title and page different on CrOS
- 'chrome://settings/accounts': { 'title': 'Settings - Users' },
- }
- broken_chromeos_special_url_tabs = {
- # returns "not available" page on chromeos=1 linux but has an URL constant.
- 'chrome://activationmessage': { 'CSP': False },
- 'chrome://cloudprintresources': { 'CSP': False },
- 'chrome://cloudprintsetup': { 'CSP': False },
- 'chrome://collected-cookies': { 'CSP': False },
- 'chrome://constrained-test': { 'CSP': False },
- 'chrome://enterprise-enrollment': { 'CSP': False },
- 'chrome://http-auth': { 'CSP': False },
- 'chrome://login-container': { 'CSP': False },
- 'chrome://media-player': { 'CSP': False },
- 'chrome://screenshots': { 'CSP': False },
- 'chrome://slideshow': { 'CSP': False },
- 'chrome://syncresources': { 'CSP': False },
- 'chrome://theme': { 'CSP': False },
- 'chrome://view-http-cache': { 'CSP': False },
-
- # crashes on chromeos=1 on linux, possibly missing real CrOS features.
- 'chrome://cryptohome': { 'CSP': False},
- 'chrome://mobilesetup': { 'CSP': False },
- 'chrome://print': { 'CSP': False },
- }
-
- linux_special_url_tabs = {
- 'chrome://linux-proxy-config': { 'title': 'Proxy Configuration Help' },
- 'chrome://tcmalloc': { 'title': 'tcmalloc stats' },
- 'chrome://sandbox': { 'title': 'Sandbox Status' },
- }
- broken_linux_special_url_tabs = {}
-
- mac_special_url_tabs = {
- 'chrome://settings/languages': { 'title': 'Settings - Languages' },
- }
- broken_mac_special_url_tabs = {}
-
- win_special_url_tabs = {
- 'chrome://conflicts': {},
- }
- broken_win_special_url_tabs = {
- # Sync on windows badly broken at the moment.
- 'chrome://sync': {},
- }
-
- google_special_url_tabs = {
- # OVERRIDE - different title for Google Chrome vs. Chromium.
- 'chrome://terms': {
- 'title': 'Google Chrome Terms of Service',
- },
- }
- broken_google_special_url_tabs = {}
-
- google_chromeos_special_url_tabs = {
- # OVERRIDE - different title for Google Chrome OS vs. Chromium OS.
- 'chrome://terms': {
- 'title': 'Google Chrome OS Terms',
- },
- }
- broken_google_chromeos_special_url_tabs = {}
-
- google_win_special_url_tabs = {}
- broken_google_win_special_url_tabs = {}
-
- google_mac_special_url_tabs = {}
- broken_google_mac_special_url_tabs = {}
-
- google_linux_special_url_tabs = {}
- broken_google_linux_special_url_tabs = {}
-
- def _VerifyAppCacheInternals(self):
- """Confirm about:appcache-internals contains expected content for Caches.
- Also confirms that the about page populates Application Caches."""
- # Navigate to html page to activate DNS prefetching.
- self.NavigateToURL('http://futtta.be/html5/offline.php')
- # Wait for page to load and display sucess or fail message.
- self.WaitUntil(
- lambda: self.GetDOMValue('document.getElementById("status").innerHTML'),
- expect_retval='cached')
- self.TabGoBack()
- test_utils.StringContentCheck(
- self, self.GetTabContents(),
- ['Manifest',
- 'http://futtta.be/html5/manifest.php'],
- [])
-
- def _VerifyAboutDNS(self):
- """Confirm about:dns contains expected content related to DNS info.
- Also confirms that prefetching DNS records propogate."""
- # Navigate to a page to activate DNS prefetching.
- self.NavigateToURL('http://www.google.com')
- self.TabGoBack()
- test_utils.StringContentCheck(self, self.GetTabContents(),
- ['Host name', 'How long ago', 'Motivation'],
- [])
-
- def _GetPlatformSpecialURLTabs(self):
- tabs = self.special_url_tabs.copy()
- broken_tabs = self.broken_special_url_tabs.copy()
- if self.IsChromeOS():
- tabs.update(self.chromeos_special_url_tabs)
- broken_tabs.update(self.broken_chromeos_special_url_tabs)
- elif self.IsLinux():
- tabs.update(self.linux_special_url_tabs)
- broken_tabs.update(self.broken_linux_special_url_tabs)
- elif self.IsMac():
- tabs.update(self.mac_special_url_tabs)
- broken_tabs.update(self.broken_mac_special_url_tabs)
- elif self.IsWin():
- tabs.update(self.win_special_url_tabs)
- broken_tabs.update(self.broken_win_special_url_tabs)
- for key, value in broken_tabs.iteritems():
- if key in tabs:
- del tabs[key]
- broken_tabs = {}
- if self.GetBrowserInfo()['properties']['branding'] == 'Google Chrome':
- tabs.update(self.google_special_url_tabs)
- broken_tabs.update(self.broken_google_special_url_tabs)
- if self.IsChromeOS():
- tabs.update(self.google_chromeos_special_url_tabs)
- broken_tabs.update(self.broken_google_chromeos_special_url_tabs)
- elif self.IsLinux():
- tabs.update(self.google_linux_special_url_tabs)
- broken_tabs.update(self.broken_google_linux_special_url_tabs)
- elif self.IsMac():
- tabs.update(self.google_mac_special_url_tabs)
- broken_tabs.update(self.broken_google_mac_special_url_tabs)
- elif self.IsWin():
- tabs.update(self.google_win_special_url_tabs)
- broken_tabs.update(self.broken_google_win_special_url_tabs)
- for key, value in broken_tabs.iteritems():
- if key in tabs:
- del tabs[key]
- return tabs
-
- def testSpecialURLRedirects(self):
- """Test that older about: URLs are implemented by newer chrome:// URLs.
- The location bar may not get updated in all cases, so checking the
- tab URL is misleading, instead check for the same contents as the
- chrome:// page."""
- tabs = self._GetPlatformSpecialURLTabs()
- for url, redirect in self.special_url_redirects.iteritems():
- if redirect in tabs:
- logging.debug('Testing redirect from %s to %s.' % (url, redirect))
- self.NavigateToURL(url)
- self.assertEqual(self.special_url_tabs[redirect]['title'],
- self.GetActiveTabTitle())
-
- def testSpecialURLTabs(self):
- """Test special tabs created by URLs like chrome://downloads,
- chrome://settings/extensionSettings, chrome://history etc.
- Also ensures they specify content-security-policy and not inline
- scripts for those pages that are expected to do so. Patches which
- break this test by including new inline javascript are security
- vulnerabilities and should be reverted."""
- tabs = self._GetPlatformSpecialURLTabs()
- for url, properties in tabs.iteritems():
- logging.debug('Testing URL %s.' % url)
- self.NavigateToURL(url)
- expected_title = 'title' in properties and properties['title'] or url
- actual_title = self.GetActiveTabTitle()
- self.assertTrue(self.WaitUntil(
- lambda: self.GetActiveTabTitle(), expect_retval=expected_title),
- msg='Title did not match for %s. Expected: %s. Got %s' % (
- url, expected_title, self.GetActiveTabTitle()))
- include_list = []
- exclude_list = []
- no_csp = 'CSP' in properties and not properties['CSP']
- if no_csp:
- exclude_list.extend(['Content-Security-Policy'])
- else:
- exclude_list.extend(['<script>', 'onclick=', 'onload=',
- 'onchange=', 'onsubmit=', 'javascript:'])
- if 'includes' in properties:
- include_list.extend(properties['includes'])
- if 'excludes' in properties:
- exclude_list.extend(properties['exlcudes'])
- test_utils.StringContentCheck(self, self.GetTabContents(),
- include_list, exclude_list)
- result = self.ExecuteJavascript("""
- var r = 'blocked';
- var f = 'executed';
- var s = document.createElement('script');
- s.textContent = 'r = f';
- document.body.appendChild(s);
- window.domAutomationController.send(r);
- """)
- logging.debug('has csp %s, result %s.' % (not no_csp, result))
- if no_csp:
- self.assertEqual(result, 'executed',
- msg='Got %s for %s' % (result, url))
- else:
- self.assertEqual(result, 'blocked',
- msg='Got %s for %s' % (result, url))
-
- # Restart browser so that every URL gets a fresh instance.
- self.RestartBrowser(clear_profile=True)
-
- def testAboutAppCacheTab(self):
- """Test App Cache tab to confirm about page populates caches."""
- self.NavigateToURL('about:appcache-internals')
- self._VerifyAppCacheInternals()
- self.assertEqual('AppCache Internals', self.GetActiveTabTitle())
-
- def testAboutDNSTab(self):
- """Test DNS tab to confirm DNS about page propogates records."""
- self.NavigateToURL('about:dns')
- self._VerifyAboutDNS()
- self.assertEqual('About DNS', self.GetActiveTabTitle())
-
- def testSpecialAcceratorTabs(self):
- """Test special tabs created by accelerators."""
- for accel, title in self.GetSpecialAcceleratorTabs().iteritems():
- self.RunCommand(accel)
- self.assertTrue(self.WaitUntil(
- self.GetActiveTabTitle, expect_retval=title),
- msg='Expected "%s", got "%s"' % (title, self.GetActiveTabTitle()))
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/stress.py b/chrome/test/functional/stress.py
deleted file mode 100755
index f9a4ffe..0000000
--- a/chrome/test/functional/stress.py
+++ /dev/null
@@ -1,806 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-
-"""
-Stess Tests for Google Chrome.
-
-This script runs 4 different stress tests:
-1. Plugin stress.
-2. Back and forward stress.
-3. Download stress.
-4. Preference stress.
-
-After every cycle (running all 4 stress tests) it checks for crashes.
-If there are any crashes, the script generates a report, uploads it to
-a server and mails about the crash and the link to the report on the server.
-Apart from this whenever the test stops on mac it looks for and reports
-zombies.
-
-Prerequisites:
-Test needs the following files/folders in the Data dir.
-1. A crash_report tool in "pyauto_private/stress/mac" folder for use on Mac.
-2. A "downloads" folder containing stress_downloads and all the files
- referenced in it.
-3. A pref_dict file in "pyauto_private/stress/mac" folder.
-4. A "plugin" folder containing doubleAnimation.xaml, flash.swf, FlashSpin.swf,
- generic.html, get_flash_player.gif, js-invoker.swf, mediaplayer.wmv,
- NavigatorTicker11.class, Plugins_page.html, sample5.mov, silverlight.xaml,
- silverlight.js, embed.pdf, plugins_page.html and test6.swf.
-5. A stress_pref file in "pyauto_private/stress".
-"""
-
-
-import commands
-import glob
-import logging
-import os
-import random
-import re
-import shutil
-import sys
-import time
-import urllib
-import test_utils
-import subprocess
-
-import pyauto_functional
-import pyauto
-import pyauto_utils
-
-
-CRASHES = 'crashes' # Name of the folder to store crashes
-
-
-class StressTest(pyauto.PyUITest):
- """Run all the stress tests."""
-
- flash_url1 = pyauto.PyUITest.GetFileURLForPath(
- os.path.join(pyauto.PyUITest.DataDir(), 'plugin', 'flash.swf'))
- flash_url2 = pyauto.PyUITest.GetFileURLForPath(
- os.path.join(pyauto.PyUITest.DataDir(),'plugin', 'js-invoker.swf'))
- flash_url3 = pyauto.PyUITest.GetFileURLForPath(
- os.path.join(pyauto.PyUITest.DataDir(), 'plugin', 'generic.html'))
- plugin_url = pyauto.PyUITest.GetFileURLForPath(
- os.path.join(pyauto.PyUITest.DataDir(), 'plugin', 'plugins_page.html'))
- empty_url = pyauto.PyUITest.GetFileURLForPath(
- os.path.join(pyauto.PyUITest.DataDir(), 'empty.html'))
- download_url1 = pyauto.PyUITest.GetFileURLForPath(
- os.path.join(pyauto.PyUITest.DataDir(), 'downloads', 'a_zip_file.zip'))
- download_url2 = pyauto.PyUITest.GetFileURLForPath(
- os.path.join(pyauto.PyUITest.DataDir(),'zip', 'test.zip'))
- file_list = pyauto.PyUITest.EvalDataFrom(
- os.path.join(pyauto.PyUITest.DataDir(), 'downloads', 'stress_downloads'))
- symbols_dir = os.path.join(os.getcwd(), 'Build_Symbols')
- stress_pref = pyauto.PyUITest.EvalDataFrom(
- os.path.join(pyauto.PyUITest.DataDir(), 'pyauto_private', 'stress',
- 'stress_pref'))
- breakpad_dir = None
- chrome_version = None
- bookmarks_list = []
-
-
- def _FuncDir(self):
- """Returns the path to the functional dir chrome/test/functional."""
- return os.path.dirname(__file__)
-
- def _DownloadSymbols(self):
- """Downloads the symbols for the build being tested."""
- download_location = os.path.join(os.getcwd(), 'Build_Symbols')
- if os.path.exists(download_location):
- shutil.rmtree(download_location)
- os.makedirs(download_location)
-
- url = self.stress_pref['symbols_dir'] + self.chrome_version
- # TODO: Add linux symbol_files
- if self.IsWin():
- url = url + '/win/'
- symbol_files = ['chrome.dll.pdb', 'chrome.exe.pdb']
- elif self.IsMac():
- url = url + '/mac/'
- symbol_files = map(urllib.quote,
- ['Google Chrome Framework.framework',
- 'Google Chrome Helper.app',
- 'Google Chrome.app',
- 'crash_inspector',
- 'crash_report_sender',
- 'ffmpegsumo.so',
- 'libplugin_carbon_interpose.dylib'])
- index = 0
- symbol_files = ['%s-%s-i386.breakpad' % (sym_file, self.chrome_version) \
- for sym_file in symbol_files]
- logging.info(symbol_files)
-
- for sym_file in symbol_files:
- sym_url = url + sym_file
- logging.info(sym_url)
- download_sym_file = os.path.join(download_location, sym_file)
- logging.info(download_sym_file)
- urllib.urlretrieve(sym_url, download_sym_file)
-
- def setUp(self):
- pyauto.PyUITest.setUp(self)
- self.breakpad_dir = self._CrashDumpFolder()
- self.chrome_version = self.GetBrowserInfo()['properties']['ChromeVersion']
-
- # Plugin stress functions
-
- def _CheckForPluginProcess(self, plugin_name):
- """Checks if a particular plugin process exists.
-
- Args:
- plugin_name : plugin process which should be running.
- """
- process = self.GetBrowserInfo()['child_processes']
- self.assertTrue([x for x in process
- if x['type'] == 'Plug-in' and
- x['name'] == plugin_name])
-
- def _GetPluginProcessId(self, plugin_name):
- """Get Plugin process id.
-
- Args:
- plugin_name: Plugin whose pid is expected.
- Eg: "Shockwave Flash"
-
- Returns:
- Process id if the plugin process is running.
- None otherwise.
- """
- for process in self.GetBrowserInfo()['child_processes']:
- if process['type'] == 'Plug-in' and \
- re.search(plugin_name, process['name']):
- return process['pid']
- return None
-
- def _CloseAllTabs(self):
- """Close all but one tab in first window."""
- tab_count = self.GetTabCount(0)
- for tab_index in xrange(tab_count - 1, 0, -1):
- self.CloseTab(tab_index)
-
- def _CloseAllWindows(self):
- """Close all windows except one."""
- win_count = self.GetBrowserWindowCount()
- for windex in xrange(win_count - 1, 0, -1):
- self.RunCommand(pyauto.IDC_CLOSE_WINDOW, windex)
-
- def _ReloadAllTabs(self):
- """Reload all the tabs in first window."""
- for tab_index in range(self.GetTabCount()):
- self.ReloadTab(tab_index)
-
- def _LoadFlashInMultipleTabs(self):
- """Load Flash in multiple tabs in first window."""
- self.NavigateToURL(self.empty_url)
- # Open 18 tabs with flash
- for _ in range(9):
- self.AppendTab(pyauto.GURL(self.flash_url1))
- self.AppendTab(pyauto.GURL(self.flash_url2))
-
- def _OpenAndCloseMultipleTabsWithFlash(self):
- """Stress test for flash in multiple tabs."""
- logging.info("In _OpenAndCloseMultipleWindowsWithFlash.")
- self._LoadFlashInMultipleTabs()
- self._CheckForPluginProcess('Shockwave Flash')
- self._CloseAllTabs()
-
- def _OpenAndCloseMultipleWindowsWithFlash(self):
- """Stress test for flash in multiple windows."""
- logging.info('In _OpenAndCloseMultipleWindowsWithFlash.')
- # Open 5 Normal and 4 Incognito windows
- for tab_index in range(1, 10):
- if tab_index < 6:
- self.OpenNewBrowserWindow(True)
- else:
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
- self.NavigateToURL(self.flash_url2, tab_index, 0)
- self.AppendTab(pyauto.GURL(self.flash_url2), tab_index)
- self._CloseAllWindows()
-
- def _OpenAndCloseMultipleTabsWithMultiplePlugins(self):
- """Stress test using multiple plugins in multiple tabs."""
- logging.info('In _OpenAndCloseMultipleTabsWithMultiplePlugins.')
- # Append 4 tabs with URL
- for _ in range(5):
- self.AppendTab(pyauto.GURL(self.plugin_url))
- self._CloseAllTabs()
-
- def _OpenAndCloseMultipleWindowsWithMultiplePlugins(self):
- """Stress test using multiple plugins in multiple windows."""
- logging.info('In _OpenAndCloseMultipleWindowsWithMultiplePlugins.')
- # Open 4 windows with URL
- for tab_index in range(1, 5):
- if tab_index < 6:
- self.OpenNewBrowserWindow(True)
- else:
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
- self.NavigateToURL(self.plugin_url, tab_index, 0)
- self._CloseAllWindows()
-
- def _KillAndReloadFlash(self):
- """Stress test by killing flash process and reloading tabs."""
- self._LoadFlashInMultipleTabs()
- flash_process_id1 = self._GetPluginProcessId('Shockwave Flash')
- self.Kill(flash_process_id1)
- self._ReloadAllTabs()
- self._CloseAllTabs()
-
- def _KillAndReloadRenderersWithFlash(self):
- """Stress test by killing renderer processes and reloading tabs."""
- logging.info('In _KillAndReloadRenderersWithFlash')
- self._LoadFlashInMultipleTabs()
- info = self.GetBrowserInfo()
- # Kill all renderer processes
- for tab_index in range(self.GetTabCount(0)):
- self.KillRendererProcess(
- info['windows'][0]['tabs'][tab_index]['renderer_pid'])
- self._ReloadAllTabs()
- self._CloseAllTabs()
-
- def _TogglePlugin(self, plugin_name):
- """Toggle plugin status.
-
- Args:
- plugin_name: Name of the plugin to toggle.
- """
- plugins = self.GetPluginsInfo().Plugins()
- for item in range(len(plugins)):
- if re.search(plugin_name, plugins[item]['name']):
- if plugins[item]['enabled']:
- self.DisablePlugin(plugins[item]['path'])
- else:
- self.EnablePlugin(plugins[item]['path'])
-
- def _ToggleAndReloadFlashPlugin(self):
- """Toggle flash and reload all tabs."""
- logging.info('In _ToggleAndReloadFlashPlugin')
- for _ in range(10):
- self.AppendTab(pyauto.GURL(self.flash_url3))
- # Disable Flash Plugin
- self._TogglePlugin('Shockwave Flash')
- self._ReloadAllTabs()
- # Enable Flash Plugin
- self._TogglePlugin('Shockwave Flash')
- self._ReloadAllTabs()
- self._CloseAllTabs()
-
- # Downloads stress functions
-
- def _LoadDownloadsInMultipleTabs(self):
- """Load Downloads in multiple tabs in the same window."""
- # Open 15 tabs with downloads
- logging.info('In _LoadDownloadsInMultipleTabs')
- for tab_index in range(15):
- # We open an empty tab and then downlad a file from it.
- self.AppendTab(pyauto.GURL(self.empty_url))
- self.NavigateToURL(self.download_url1, 0, tab_index + 1)
- self.AppendTab(pyauto.GURL(self.empty_url))
- self.NavigateToURL(self.download_url2, 0, tab_index + 2)
-
- def _OpenAndCloseMultipleTabsWithDownloads(self):
- """Download items in multiple tabs."""
- logging.info('In _OpenAndCloseMultipleTabsWithDownloads')
- self._LoadDownloadsInMultipleTabs()
- self._CloseAllTabs()
-
- def _OpenAndCloseMultipleWindowsWithDownloads(self):
- """Randomly have downloads in multiple windows."""
- logging.info('In _OpenAndCloseMultipleWindowsWithDownloads')
- # Open 15 Windows randomly on both regular and incognito with downloads
- for window_index in range(15):
- tick = round(random.random() * 100)
- if tick % 2 != 0:
- self.NavigateToURL(self.download_url2, 0, 0)
- else:
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
- self.AppendTab(pyauto.GURL(self.empty_url), 1)
- self.NavigateToURL(self.download_url2, 1, 1)
- self._CloseAllWindows()
-
- def _OpenAndCloseMultipleTabsWithMultipleDownloads(self):
- """Download multiple items in multiple tabs."""
- logging.info('In _OpenAndCloseMultipleTabsWithMultipleDownloads')
- self.NavigateToURL(self.empty_url)
- for _ in range(15):
- for file in self.file_list:
- count = 1
- url = self.GetFileURLForPath(
- os.path.join(self.DataDir(), 'downloads', file))
- self.AppendTab(pyauto.GURL(self.empty_url))
- self.NavigateToURL(url, 0, count)
- count = count + 1
- self._CloseAllTabs()
-
- def _OpenAndCloseMultipleWindowsWithMultipleDownloads(self):
- """Randomly multiple downloads in multiple windows."""
- logging.info('In _OpenAndCloseMultipleWindowsWithMultipleDownloads')
- for _ in range(15):
- for file in self.file_list:
- tick = round(random.random() * 100)
- url = self.GetFileURLForPath(
- os.path.join(self.DataDir(), 'downloads', file))
- if tick % 2!= 0:
- self.NavigateToURL(url, 0, 0)
- else:
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
- self.AppendTab(pyauto.GURL(self.empty_url), 1)
- self.NavigateToURL(url, 1, 1)
- self._CloseAllWindows()
-
- # Back and Forward stress functions
-
- def _BrowserGoBack(self, window_index):
- """Go back in the browser history.
-
- Chrome has limitation on going back and can only go back 49 pages.
-
- Args:
- window_index: the index of the browser window to work on.
- """
- for nback in range(48): # Go back 48 times.
- if nback % 4 == 0: # Bookmark every 5th url when going back.
- self._BookMarkEvery5thURL(window_index)
- self.TabGoBack(tab_index=0, windex=window_index)
-
- def _BrowserGoForward(self, window_index):
- """Go Forward in the browser history.
-
- Chrome has limitation on going back and can only go back 49 pages.
-
- Args:
- window_index: the index of the browser window to work on.
- """
- for nforward in range(48): # Go back 48 times.
- if nforward % 4 == 0: # Bookmark every 5th url when going Forward
- self._BookMarkEvery5thURL(window_index)
- self.TabGoForward(tab_index=0, windex=window_index)
-
- def _AddToListAndBookmark(self, newname, url):
- """Bookmark the url to bookmarkbar and to he list of bookmarks.
-
- Args:
- newname: the name of the bookmark.
- url: the url to bookmark.
- """
- bookmarks = self.GetBookmarkModel()
- bar_id = bookmarks.BookmarkBar()['id']
- self.AddBookmarkURL(bar_id, 0, newname, url)
- self.bookmarks_list.append(newname)
-
- def _RemoveFromListAndBookmarkBar(self, name):
- """Remove the bookmark bor and bookmarks list.
-
- Args:
- name: the name of bookmark to remove.
- """
- bookmarks = self.GetBookmarkModel()
- node = bookmarks.FindByTitle(name)
- self.RemoveBookmark(node[0]['id'])
- self.bookmarks_list.remove(name)
-
- def _DuplicateBookmarks(self, name):
- """Find duplicate bookmark in the bookmarks list.
-
- Args:
- name: name of the bookmark.
-
- Returns:
- True if it's a duplicate.
- """
- for index in (self.bookmarks_list):
- if index == name:
- return True
- return False
-
- def _BookMarkEvery5thURL(self, window_index):
- """Check for duplicate in list and bookmark current url.
- If its the first time and list is empty add the bookmark.
- If its a duplicate remove the bookmark.
- If its new tab page move over.
-
- Args:
- window_index: the index of the browser window to work on.
- """
- tab_title = self.GetActiveTabTitle(window_index) # get the page title
- url = self.GetActiveTabURL(window_index).spec() # get the page url
- if not self.bookmarks_list:
- self._AddToListAndBookmark(tab_title, url) # first run bookmark the url
- return
- elif self._DuplicateBookmarks(tab_title):
- self._RemoveFromListAndBookmarkBar(tab_title)
- return
- elif tab_title == 'New Tab': # new tab page pass over
- return
- else:
- # new bookmark add it to bookmarkbar
- self._AddToListAndBookmark(tab_title, url)
- return
-
- def _ReadFileAndLoadInNormalAndIncognito(self):
- """Read urls and load them in normal and incognito window.
- We load 96 urls only as we can go back and forth 48 times.
- Uses time to get different urls in normal and incognito window
- The source file is taken from stress folder in /data folder.
- """
- # URL source from stress folder in data folder
- data_file = os.path.join(self.DataDir(), 'pyauto_private', 'stress',
- 'urls_and_titles')
- url_data = self.EvalDataFrom(data_file)
- urls = url_data.keys()
- i = 0
- ticks = int(time.time()) # get the latest time.
- for url in urls:
- if i <= 96 : # load only 96 urls.
- if ticks % 2 == 0: # loading in Incognito and Normal window.
- self.NavigateToURL(url)
- else:
- self.NavigateToURL(url, 1, 0)
- else:
- break
- ticks = ticks - 1
- i += 1
- return
-
- def _StressTestNavigation(self):
- """ This is the method from where various navigations are called.
- First we load the urls then call navigete back and forth in
- incognito window then in normal window.
- """
- self._ReadFileAndLoadInNormalAndIncognito() # Load the urls.
- self._BrowserGoBack(1) # Navigate back in incognito window.
- self._BrowserGoForward(1) # Navigate forward in incognito window
- self._BrowserGoBack(0) # Navigate back in normal window
- self._BrowserGoForward(0) # Navigate forward in normal window
-
- # Preference stress functions
-
- def _RandomBool(self):
- """For any preferences bool value, it takes True or False value.
- We are generating random True or False value.
- """
- return random.randint(0, 1) == 1
-
- def _RandomURL(self):
- """Some of preferences take string url, so generating random url here."""
- # Site list
- site_list = ['test1.html', 'test2.html','test3.html','test4.html',
- 'test5.html', 'test7.html', 'test6.html']
- random_site = random.choice(site_list)
- # Returning a url of random site
- return self.GetFileURLForPath(os.path.join(self.DataDir(), random_site))
-
- def _RandomURLArray(self):
- """Returns a list of 10 random URLs."""
- return [self._RandomURL() for _ in range(10)]
-
- def _RandomInt(self, max_number):
- """Some of the preferences takes integer value.
- Eg: If there are three options, we generate random
- value for any option.
-
- Arg:
- max_number: The number of options that a preference has.
- """
- return random.randrange(1, max_number)
-
- def _RandomDownloadDir(self):
- """Returns a random download directory."""
- return random.choice(['dl_dir1', 'dl_dir2', 'dl_dir3',
- 'dl_dir4', 'dl_dir5'])
-
- def _SetPref(self):
- """Reads the preferences from file and
- sets the preferences to Chrome.
- """
- raw_dictionary = self.EvalDataFrom(os.path.join(self.DataDir(),
- 'pyauto_private', 'stress', 'pref_dict'))
- value_dictionary = {}
-
- for key, value in raw_dictionary.iteritems():
- if value == 'BOOL':
- value_dictionary[key] = self._RandomBool()
- elif value == 'STRING_URL':
- value_dictionary[key] = self._RandomURL()
- elif value == 'ARRAY_URL':
- value_dictionary[key] = self._RandomURLArray()
- elif value == 'STRING_PATH':
- value_dictionary[key] = self._RandomDownloadDir()
- elif value[0:3] == 'INT':
- # Normally we difine INT datatype with number of options,
- # so parsing number of options and selecting any of them
- # randomly.
- value_dictionary[key] = 1
- max_number = raw_dictionary[key][3:4]
- if not max_number == 1:
- value_dictionary[key]= self._RandomInt(int(max_number))
- self.SetPrefs(getattr(pyauto,key), value_dictionary[key])
-
- return value_dictionary
-
- # Crash reporting functions
-
- def _CrashDumpFolder(self):
- """Get the breakpad folder.
-
- Returns:
- The full path of the Crash Reports folder.
- """
- breakpad_folder = self.GetBrowserInfo()['properties']['DIR_CRASH_DUMPS']
- self.assertTrue(breakpad_folder, 'Cannot figure crash dir')
- return breakpad_folder
-
- def _DeleteDumps(self):
- """Delete all the dump files in teh Crash Reports folder."""
- # should be called at the start of stress run
- if os.path.exists(self.breakpad_dir):
- logging.info('xxxxxxxxxxxxxxxINSIDE DELETE DUMPSxxxxxxxxxxxxxxxxx')
- if self.IsMac():
- shutil.rmtree(self.breakpad_dir)
- elif self.IsWin():
- files = os.listdir(self.breakpad_dir)
- for file in files:
- os.remove(file)
-
- first_crash = os.path.join(os.getcwd(), '1stcrash')
- crashes_dir = os.path.join(os.getcwd(), 'crashes')
- if (os.path.exists(crashes_dir)):
- shutil.rmtree(crashes_dir)
- shutil.rmtree(first_crash)
-
- def _SymbolicateCrashDmp(self, dmp_file, symbols_dir, output_file):
- """Generate symbolicated crash report.
-
- Args:
- dmp_file: the dmp file to symbolicate.
- symbols_dir: the directory containing the symbols.
- output_file: the output file.
-
- Returns:
- Crash report text.
- """
- report = ''
- if self.IsWin():
- windbg_cmd = [
- os.path.join('C:', 'Program Files', 'Debugging Tools for Windows',
- 'windbg.exe'),
- '-Q',
- '-y',
- '\"',
- symbols_dir,
- '\"',
- '-c',
- '\".ecxr;k50;.logclose;q\"',
- '-logo',
- output_file,
- '-z',
- '\"',
- dmp_file,
- '\"']
- subprocess.call(windbg_cmd)
- # Since we are directly writing the info into output_file,
- # we just need to copy that in to report
- report = open(output_file, 'r').read()
-
- elif self.IsMac():
- crash_report = os.path.join(self.DataDir(), 'pyauto_private', 'stress',
- 'mac', 'crash_report')
- for i in range(5): # crash_report doesn't work sometimes. So we retry
- report = test_utils.Shell2(
- '%s -S "%s" "%s"' % (crash_report, symbols_dir, dmp_file))[0]
- if len(report) < 200:
- try_again = 'Try %d. crash_report didn\'t work out. Trying again', i
- logging.info(try_again)
- else:
- break
- open(output_file, 'w').write(report)
- return report
-
- def _SaveSymbols(self, symbols_dir, dump_dir=' ', multiple_dumps=True):
- """Save the symbolicated files for all crash dumps.
-
- Args:
- symbols_dir: the directory containing the symbols.
- dump_dir: Path to the directory holding the crash dump files.
- multiple_dumps: True if we are processing multiple dump files,
- False if we are processing only the first crash.
- """
- if multiple_dumps:
- dump_dir = self.breakpad_dir
-
- if not os.path.isdir(CRASHES):
- os.makedirs(CRASHES)
-
- # This will be sent to the method by the caller.
- dmp_files = glob.glob(os.path.join(dump_dir, '*.dmp'))
- for dmp_file in dmp_files:
- dmp_id = os.path.splitext(os.path.basename(dmp_file))[0]
- if multiple_dumps:
- report_folder = CRASHES
- else:
- report_folder = dump_dir
- report_fname = os.path.join(report_folder,
- '%s.txt' % (dmp_id))
- report = self._SymbolicateCrashDmp(dmp_file, symbols_dir,
- report_fname)
- if report == '':
- logging.info('Crash report is empty.')
- # This is for copying the original dumps.
- if multiple_dumps:
- shutil.copy2(dmp_file, CRASHES)
-
- def _GetFirstCrashDir(self):
- """Get first crash file in the crash folder.
- Here we create the 1stcrash directory which holds the
- first crash report, which will be attached to the mail.
- """
- breakpad_folder = self.breakpad_dir
- dump_list = glob.glob1(breakpad_folder,'*.dmp')
- dump_list.sort(key=lambda s: os.path.getmtime(os.path.join(
- breakpad_folder, s)))
- first_crash_file = os.path.join(breakpad_folder, dump_list[0])
-
- if not os.path.isdir('1stcrash'):
- os.makedirs('1stcrash')
- shutil.copy2(first_crash_file, '1stcrash')
- first_crash_dir = os.path.join(os.getcwd(), '1stcrash')
- return first_crash_dir
-
- def _GetFirstCrashFile(self):
- """Get first crash file in the crash folder."""
- first_crash_dir = os.path.join(os.getcwd(), '1stcrash')
- for each in os.listdir(first_crash_dir):
- if each.endswith('.txt'):
- first_crash_file = each
- return os.path.join(first_crash_dir, first_crash_file)
-
- def _ProcessOnlyFirstCrash(self):
- """ Process only the first crash report for email."""
- first_dir = self._GetFirstCrashDir()
- self._SaveSymbols(self.symbols_dir, first_dir, False)
-
- def _GetOSName(self):
- """Returns the OS type we are running this script on."""
- os_name = ''
- if self.IsMac():
- os_number = commands.getoutput('sw_vers -productVersion | cut -c 1-4')
- if os_number == '10.6':
- os_name = 'Snow_Leopard'
- elif os_number == '10.5':
- os_name = 'Leopard'
- elif self.IsWin():
- # TODO: Windows team need to find the way to get OS name
- os_name = 'Windows'
- if platform.version()[0] == '5':
- os_name = os_name + '_XP'
- else:
- os_name = os_name + '_Vista/Win7'
- return os_name
-
- def _ProcessUploadAndEmailCrashes(self):
- """Upload the crashes found and email the team about this."""
- logging.info('#########INSIDE _ProcessUploadAndEmailCrashes#########')
- try:
- build_version = self.chrome_version
- self._SaveSymbols(self.symbols_dir)
- self._ProcessOnlyFirstCrash()
- file_to_attach = self._GetFirstCrashFile()
- # removing the crash_txt for now,
- # since we are getting UnicodeDecodeError
- # crash_txt = open(file_to_attach).read()
- except ValueError:
- test_utils.SendMail(self.stress_pref['mailing_address'],
- self.stress_pref['mailing_address'],
- "We don't have build version",
- "BROWSER CRASHED, PLEASE CHECK",
- self.stress_pref['smtp'])
- # Move crash reports and dumps to server
- os_name = self._GetOSName()
- dest_dir = build_version + '_' + os_name
- if (test_utils.Shell2(self.stress_pref['script'] % (CRASHES, dest_dir))):
- logging.info('Copy Complete')
- upload_dir= self.stress_pref['upload_dir'] + dest_dir
- num_crashes = '\n \n Number of Crashes :' + \
- str(len(glob.glob1(self.breakpad_dir, '*.dmp')))
- mail_content = '\n\n Crash Report URL :' + upload_dir + '\n' + \
- num_crashes + '\n\n' # + crash_txt
- mail_subject = 'Stress Results :' + os_name + '_' + build_version
- # Sending mail with first crash report, # of crashes, location of upload
- test_utils.SendMail(self.stress_pref['mailing_address'],
- self.stress_pref['mailing_address'],
- mail_subject, mail_content,
- self.stress_pref['smtp'], file_to_attach)
-
- def _ReportCrashIfAny(self):
- """Check for browser crashes and report."""
- if os.path.isdir(self.breakpad_dir):
- listOfDumps = glob.glob(os.path.join(self.breakpad_dir, '*.dmp'))
- if len(listOfDumps) > 0:
- logging.info('========== INSIDE REPORT CRASH++++++++++++++')
- # inform a method to process the dumps
- self._ProcessUploadAndEmailCrashes()
-
- # Test functions
-
- def _PrefStress(self):
- """Stress preferences."""
- default_prefs = self.GetPrefsInfo()
- pref_dictionary = self._SetPref()
- for key, value in pref_dictionary.iteritems():
- self.assertEqual(value, self.GetPrefsInfo().Prefs(
- getattr(pyauto, key)))
-
- for key, value in pref_dictionary.iteritems():
- self.SetPrefs(getattr(pyauto, key),
- default_prefs.Prefs(getattr(pyauto, key)))
-
- def _NavigationStress(self):
- """Run back and forward stress in normal and incognito window."""
- self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
- self._StressTestNavigation()
-
- def _DownloadStress(self):
- """Run all the Download stress test."""
- org_download_dir = self.GetDownloadDirectory().value()
- new_dl_dir = os.path.join(org_download_dir, 'My+Downloads Folder')
- os.path.exists(new_dl_dir) and shutil.rmtree(new_dl_dir)
- os.makedirs(new_dl_dir)
- self.SetPrefs(pyauto.kDownloadDefaultDirectory, new_dl_dir)
- self._OpenAndCloseMultipleTabsWithDownloads()
- self._OpenAndCloseMultipleWindowsWithDownloads()
- self._OpenAndCloseMultipleTabsWithMultipleDownloads()
- self._OpenAndCloseMultipleWindowsWithMultipleDownloads()
- pyauto_utils.RemovePath(new_dl_dir) # cleanup
- self.SetPrefs(pyauto.kDownloadDefaultDirectory, org_download_dir)
-
- def _PluginStress(self):
- """Run all the plugin stress tests."""
- self._OpenAndCloseMultipleTabsWithFlash()
- self._OpenAndCloseMultipleWindowsWithFlash()
- self._OpenAndCloseMultipleTabsWithMultiplePlugins()
- self._OpenAndCloseMultipleWindowsWithMultiplePlugins()
- self._KillAndReloadRenderersWithFlash()
- self._ToggleAndReloadFlashPlugin()
-
- def testStress(self):
- """Run all the stress tests for 24 hrs."""
- if self.GetBrowserInfo()['properties']['branding'] != 'Google Chrome':
- logging.info('This is not a branded build, so stopping the stress')
- return 1
- self._DownloadSymbols()
- run_number = 1
- start_time = time.time()
- while True:
- logging.info('run %d...' % run_number)
- run_number = run_number + 1
- if (time.time() - start_time) >= 24*60*60:
- logging.info('Its been 24hrs, so we break now.')
- break
- try:
- methods = [self._NavigationStress, self._DownloadStress,
- self._PluginStress, self._PrefStress]
- random.shuffle(methods)
- for method in methods:
- method()
- logging.info('Method %s done' % method)
- except KeyboardInterrupt:
- logging.info('----------We got a KeyboardInterrupt-----------')
- except Exception, error:
- logging.info('-------------There was an ERROR---------------')
- logging.info(error)
-
- # Crash Reporting
- self._ReportCrashIfAny()
- self._DeleteDumps()
-
- if self.IsMac():
- zombie = 'ps -el | grep Chrom | grep -v grep | grep Z | wc -l'
- zombie_count = int(commands.getoutput(zombie))
- if zombie_count > 0:
- logging.info('WE HAVE ZOMBIES = %d' % zombie_count)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/test_pyauto.py b/chrome/test/functional/test_pyauto.py
deleted file mode 100755
index adf1f27..0000000
--- a/chrome/test/functional/test_pyauto.py
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import time
-import unittest
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-import pyauto_errors
-
-
-class PyAutoTest(pyauto.PyUITest):
- """Test functionality of the PyAuto framework."""
-
- _EXTRA_CHROME_FLAGS = [
- '--scooby-doo=123',
- '--donald-duck=cool',
- '--super-mario',
- '--marvin-the-martian',
- ]
-
- def ExtraChromeFlags(self):
- """Ensures Chrome is launched with some custom flags.
-
- Overrides the default list of extra flags passed to Chrome. See
- ExtraChromeFlags() in pyauto.py.
- """
- return pyauto.PyUITest.ExtraChromeFlags(self) + self._EXTRA_CHROME_FLAGS
-
- def testSetCustomChromeFlags(self):
- """Ensures that Chrome can be launched with custom flags."""
- self.NavigateToURL('about://version')
- for flag in self._EXTRA_CHROME_FLAGS:
- self.assertEqual(self.FindInPage(flag)['match_count'], 1,
- msg='Missing expected Chrome flag "%s"' % flag)
-
- def testCallOnInvalidWindow(self):
- """Verify that exception is raised when a browser is missing/invalid."""
- self.assertEqual(1, self.GetBrowserWindowCount())
- self.assertRaises(
- pyauto_errors.JSONInterfaceError,
- lambda: self.FindInPage('some text', windex=1)) # invalid window
-
- def testJSONInterfaceTimeout(self):
- """Verify that an exception is raised when the JSON interface times out."""
- self.ClearEventQueue()
- self.AddDomEventObserver('foo')
- self.assertRaises(
- pyauto_errors.AutomationCommandTimeout,
- lambda: self.GetNextEvent(timeout=2000)) # event queue is empty
-
- def testActionTimeoutChanger(self):
- """Verify that ActionTimeoutChanger works."""
- new_timeout = 1000 # 1 sec
- changer = pyauto.PyUITest.ActionTimeoutChanger(self, new_timeout)
- self.assertEqual(self._automation_timeout, new_timeout)
-
- # Verify the amount of time taken for automation timeout
- then = time.time()
- self.assertRaises(
- pyauto_errors.AutomationCommandTimeout,
- lambda: self.ExecuteJavascript('invalid js should timeout'))
- elapsed = time.time() - then
- self.assertTrue(elapsed < new_timeout / 1000.0 + 2, # margin of 2 secs
- msg='ActionTimeoutChanger did not work. '
- 'Automation timeout took %f secs' % elapsed)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/test_utils.py b/chrome/test/functional/test_utils.py
deleted file mode 100644
index 55d97c8..0000000
--- a/chrome/test/functional/test_utils.py
+++ /dev/null
@@ -1,401 +0,0 @@
-# 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.
-
-import copy
-import ctypes
-import email
-import logging
-import os
-import shutil
-import smtplib
-import subprocess
-import sys
-import types
-
-import pyauto_functional
-import pyauto
-import pyauto_utils
-import pyauto_errors
-
-
-"""Commonly used functions for PyAuto tests."""
-
-def CrashBrowser(test):
- """Crashes the browser by navigating to special URL."""
- try:
- test.NavigateToURL('chrome://inducebrowsercrashforrealz')
- except pyauto_errors.JSONInterfaceError:
- pass
- else:
- raise RuntimeError(
- 'Browser did not crash at chrome://inducebrowsercrashforrealz')
-
-
-def CopyFileFromDataDirToDownloadDir(test, file_path):
- """Copy a file from data directory to downloads directory.
-
- Args:
- test: derived from pyauto.PyUITest - base class for UI test cases.
- path: path of the file relative to the data directory
- """
- data_file = os.path.join(test.DataDir(), file_path)
- download_dir = test.GetDownloadDirectory().value()
- shutil.copy(data_file, download_dir)
-
-
-def CopyFileFromContentDataDirToDownloadDir(test, file_path):
- """Copy a file from content data directory to downloads directory.
-
- Args:
- test: derived from pyauto.PyUITest - base class for UI test cases.
- path: path of the file relative to the data directory
- """
- data_file = os.path.join(test.ContentDataDir(), file_path)
- download_dir = test.GetDownloadDirectory().value()
- shutil.copy(data_file, download_dir)
-
-
-def RemoveDownloadedTestFile(test, file_name):
- """Delete a file from the downloads directory.
-
- Arg:
- test: derived from pyauto.PyUITest - base class for UI test cases
- file_name: name of file to remove
- """
- downloaded_pkg = os.path.join(test.GetDownloadDirectory().value(),
- file_name)
- pyauto_utils.RemovePath(downloaded_pkg)
- pyauto_utils.RemovePath(downloaded_pkg + '.crdownload')
-
-
-def GoogleAccountsLogin(test, username, password,
- tab_index=0, windex=0, url=None):
- """Log into Google Accounts.
-
- Attempts to login to Google by entering the username/password into the google
- login page and click submit button.
-
- Args:
- test: derived from pyauto.PyUITest - base class for UI test cases.
- username: users login input.
- password: users login password input.
- tab_index: The tab index, default is 0.
- windex: The window index, default is 0.
- url: an alternative url for login page, if None, original one will be used.
- """
- url = url or 'https://accounts.google.com/'
- test.NavigateToURL(url, windex, tab_index)
- email_id = 'document.getElementById("Email").value = "%s"; ' \
- 'window.domAutomationController.send("done")' % username
- password = 'document.getElementById("Passwd").value = "%s"; ' \
- 'window.domAutomationController.send("done")' % password
- test.ExecuteJavascript(email_id, tab_index, windex)
- test.ExecuteJavascript(password, tab_index, windex)
- test.assertTrue(test.SubmitForm('gaia_loginform', tab_index, windex))
-
-
-def VerifyGoogleAccountCredsFilled(test, username, password, tab_index=0,
- windex=0):
- """Verify stored/saved user and password values to the values in the field.
-
- Args:
- test: derived from pyauto.PyUITest - base class for UI test cases.
- username: user log in input.
- password: user log in password input.
- tab_index: The tab index, default is 0.
- windex: The window index, default is 0.
- """
- email_value = test.GetDOMValue('document.getElementById("Email").value',
- tab_index, windex)
- passwd_value = test.GetDOMValue('document.getElementById("Passwd").value',
- tab_index, windex)
- test.assertEqual(email_value, username)
- # Not using assertEqual because if it fails it would end up dumping the
- # password (which is supposed to be private)
- test.assertTrue(passwd_value == password)
-
-
-def Shell2(cmd_string, bg=False):
- """Run a shell command.
-
- Args:
- cmd_string: command to run
- bg: should the process be run in background? Default: False
-
- Returns:
- Output, return code
- """
- if not cmd_string: return ('', 0)
- if bg:
- cmd_string += ' 1>/dev/null 2>&1 &'
- proc = os.popen(cmd_string)
- if bg: return ('Background process: %s' % cmd_string, 0)
- out = proc.read()
- retcode = proc.close()
- if not retcode: # Success
- retcode = 0
- return (out, retcode)
-
-
-def SendMail(send_from, send_to, subject, text, smtp, file_to_send=None):
- """Send mail to all the group to notify about the crash and uploaded data.
-
- Args:
- send_from: From mail id as a string.
- send_to: To mail id. Can be a string representing a single address, or a
- list of strings representing multiple addresses.
- subject: Mail subject as a string.
- text: Mail body as a string.
- smtp: The smtp to use, as a string.
- file_to_send: Attachments for the mail.
- """
- msg = email.MIMEMultipart.MIMEMultipart()
- msg['From'] = send_from
- if isinstance(send_to, list):
- msg['To'] = ','.join(send_to)
- else:
- msg['To'] = send_to
- msg['Date'] = email.Utils.formatdate(localtime=True)
- msg['Subject'] = subject
-
- # To send multiple files in one message, introduce for loop here for files.
- msg.attach(email.MIMEText.MIMEText(text))
- part = email.MIMEBase.MIMEBase('application', 'octet-stream')
- if file_to_send is not None:
- part.set_payload(open(file_to_send,'rb').read())
- email.Encoders.encode_base64(part)
- part.add_header('Content-Disposition',
- 'attachment; filename="%s"'
- % os.path.basename(file_to_send))
- msg.attach(part)
- smtp_obj = smtplib.SMTP(smtp)
- smtp_obj.sendmail(send_from, send_to, msg.as_string())
- smtp_obj.close()
-
-
-def GetFreeSpace(path):
- """Returns the free space (in bytes) on the drive containing |path|."""
- if sys.platform == 'win32':
- free_bytes = ctypes.c_ulonglong(0)
- ctypes.windll.kernel32.GetDiskFreeSpaceExW(
- ctypes.c_wchar_p(os.path.dirname(path)), None, None,
- ctypes.pointer(free_bytes))
- return free_bytes.value
- fs_stat = os.statvfs(path)
- return fs_stat.f_bsize * fs_stat.f_bavail
-
-
-def StripUnmatchedKeys(item_to_strip, reference_item):
- """Returns a copy of 'item_to_strip' where unmatched key-value pairs in
- every dictionary are removed.
-
- This will examine each dictionary in 'item_to_strip' recursively, and will
- remove keys that are not found in the corresponding dictionary in
- 'reference_item'. This is useful for testing equality of a subset of data.
-
- Items may contain dictionaries, lists, or primitives, but only corresponding
- dictionaries will be stripped. A corresponding entry is one which is found
- in the same index in the corresponding parent array or at the same key in the
- corresponding parent dictionary.
-
- Arg:
- item_to_strip: item to copy and remove all unmatched key-value pairs
- reference_item: item that serves as a reference for which keys-value pairs
- to strip from 'item_to_strip'
-
- Returns:
- a copy of 'item_to_strip' where all key-value pairs that do not have a
- matching key in 'reference_item' are removed
-
- Example:
- item_to_strip = {'tabs': 3,
- 'time': 5908}
- reference_item = {'tabs': 2}
- StripUnmatchedKeys(item_to_strip, reference_item) will return {'tabs': 3}
- """
- def StripList(list1, list2):
- return_list = copy.deepcopy(list2)
- for i in range(min(len(list1), len(list2))):
- return_list[i] = StripUnmatchedKeys(list1[i], list2[i])
- return return_list
-
- def StripDict(dict1, dict2):
- return_dict = {}
- for key in dict1:
- if key in dict2:
- return_dict[key] = StripUnmatchedKeys(dict1[key], dict2[key])
- return return_dict
-
- item_to_strip_type = type(item_to_strip)
- if item_to_strip_type is type(reference_item):
- if item_to_strip_type is types.ListType:
- return StripList(item_to_strip, reference_item)
- elif item_to_strip_type is types.DictType:
- return StripDict(item_to_strip, reference_item)
- return copy.deepcopy(item_to_strip)
-
-
-def StringContentCheck(test, content_string, have_list, nothave_list):
- """Check for the presence or absence of strings within content.
-
- Confirm all strings in |have_list| are found in |content_string|.
- Confirm all strings in |nothave_list| are not found in |content_string|.
-
- Args:
- content_string: string containing the content to check.
- have_list: list of strings expected to be found within the content.
- nothave_list: list of strings expected to not be found within the content.
- """
- for s in have_list:
- test.assertTrue(s in content_string,
- msg='"%s" missing from content.' % s)
- for s in nothave_list:
- test.assertTrue(s not in content_string,
- msg='"%s" unexpectedly contained in content.' % s)
-
-
-def CallFunctionWithNewTimeout(self, new_timeout, function):
- """Sets the timeout to |new_timeout| and calls |function|.
-
- This method resets the timeout before returning.
- """
- timeout_changer = pyauto.PyUITest.ActionTimeoutChanger(
- self, new_timeout)
- logging.info('Automation execution timeout has been changed to %d. '
- 'If the timeout is large the test might appear to hang.'
- % new_timeout)
- function()
- del timeout_changer
-
-
-def GetOmniboxMatchesFor(self, text, windex=0, attr_dict=None):
- """Fetch omnibox matches with the given attributes for the given query.
-
- Args:
- text: the query text to use
- windex: the window index to work on. Defaults to 0 (first window)
- attr_dict: the dictionary of properties to be satisfied
-
- Returns:
- a list of match items
- """
- self.SetOmniboxText(text, windex=windex)
- self.WaitUntilOmniboxQueryDone(windex=windex)
- if not attr_dict:
- matches = self.GetOmniboxInfo(windex=windex).Matches()
- else:
- matches = self.GetOmniboxInfo(windex=windex).MatchesWithAttributes(
- attr_dict=attr_dict)
- return matches
-
-
-def GetMemoryUsageOfProcess(pid):
- """Queries the system for the current memory usage of a specified process.
-
- This function only works in Linux and ChromeOS.
-
- Args:
- pid: The integer process identifier for the process to use.
-
- Returns:
- The memory usage of the process in MB, given as a float. If the process
- doesn't exist on the machine, then the value 0 is returned.
- """
- assert pyauto.PyUITest.IsLinux() or pyauto.PyUITest.IsChromeOS()
- process = subprocess.Popen('ps h -o rss -p %s' % pid, shell=True,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- stdout = process.communicate()[0]
- if stdout:
- return float(stdout.strip()) / 1024
- else:
- return 0
-
-
-def LoginToDevice(test, test_account='test_google_account'):
- """Login to the Chromeos device using the given test account.
-
- If no test account is specified, we use test_google_account as the default.
- You can choose test accounts from -
- chrome/test/data/pyauto_private/private_tests_info.txt
-
- Args:
- test_account: The account used to login to the Chromeos device.
- """
- if not test.GetLoginInfo()['is_logged_in']:
- credentials = test.GetPrivateInfo()[test_account]
- test.Login(credentials['username'], credentials['password'])
- login_info = test.GetLoginInfo()
- test.assertTrue(login_info['is_logged_in'], msg='Login failed.')
- else:
- test.fail(msg='Another user is already logged in. Please logout first.')
-
-def GetInfobarIndexByType(test, infobar_type, windex=0, tab_index=0):
- """Returns the index of the infobar of the given type.
-
- Args:
- test: Derived from pyauto.PyUITest - base class for UI test cases.
- infobar_type: The infobar type to look for.
- windex: Window index.
- tab_index: Tab index.
-
- Returns:
- Index of infobar for infobar type, or None if not found.
- """
- infobar_list = (
- test.GetBrowserInfo()['windows'][windex]['tabs'][tab_index] \
- ['infobars'])
- for infobar in infobar_list:
- if infobar_type == infobar['type']:
- return infobar_list.index(infobar)
- return None
-
-def WaitForInfobarTypeAndGetIndex(test, infobar_type, windex=0, tab_index=0):
- """Wait for infobar type to appear and returns its index.
-
- If the infobar never appears, an exception will be raised.
-
- Args:
- test: Derived from pyauto.PyUITest - base class for UI test cases.
- infobar_type: The infobar type to look for.
- windex: Window index. Defaults to 0 (first window).
- tab_index: Tab index. Defaults to 0 (first tab).
-
- Returns:
- Index of infobar for infobar type.
- """
- test.assertTrue(
- test.WaitUntil(lambda: GetInfobarIndexByType(
- test, infobar_type, windex, tab_index) is not None),
- msg='Infobar type for %s did not appear.' % infobar_type)
- # Return the infobar index.
- return GetInfobarIndexByType(test, infobar_type, windex, tab_index)
-
-def AssertInfobarTypeDoesNotAppear(test, infobar_type, windex=0, tab_index=0):
- """Check that the infobar type does not appear.
-
- This function waits 20s to assert that the infobar does not appear.
-
- Args:
- test: Derived from pyauto.PyUITest - base class for UI test cases.
- infobar_type: The infobar type to look for.
- windex: Window index. Defaults to 0 (first window).
- tab_index: Tab index. Defaults to 0 (first tab).
- """
- test.assertFalse(
- test.WaitUntil(lambda: GetInfobarIndexByType(
- test, infobar_type, windex, tab_index) is not None, timeout=20),
- msg=('Infobar type for %s appeared when it should be hidden.'
- % infobar_type))
-
-def OpenCroshVerification(self):
- """This test opens crosh.
-
- This function assumes that no browser windows are open.
- """
- self.assertEqual(0, self.GetBrowserWindowCount())
- self.OpenCrosh()
- self.assertEqual(1, self.GetBrowserWindowCount())
- self.assertEqual(1, self.GetTabCount(),
- msg='Could not open crosh')
- self.assertEqual('crosh', self.GetActiveTabTitle())
diff --git a/chrome/test/functional/tracing/pyauto_tracing.py b/chrome/test/functional/tracing/pyauto_tracing.py
deleted file mode 100755
index a009657..0000000
--- a/chrome/test/functional/tracing/pyauto_tracing.py
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import os
-import sys
-
-def _SetupPaths():
- """Setting path to find pyauto_functional.py."""
- tracing_dir = os.path.abspath(os.path.dirname(__file__))
- sys.path.append(tracing_dir)
- sys.path.append(os.path.normpath(os.path.join(tracing_dir, os.pardir)))
-
-_SetupPaths()
-
-
-from pyauto_functional import Main
-
-
-if __name__ == '__main__':
- Main()
diff --git a/chrome/test/functional/tracing/tab_tracker.py b/chrome/test/functional/tracing/tab_tracker.py
deleted file mode 100644
index 87e4886..0000000
--- a/chrome/test/functional/tracing/tab_tracker.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# Copyright (c) 2012 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.
-
-import uuid
-
-
-class TabTracker(object):
- """Uniquely track tabs within a window.
-
- This allows the creation of tabs whose indices can be
- determined even after lower indexed tabs have been closed, therefore changing
- that tab's index.
-
- This is accomplished via a containing window which is created and tracked via
- the window's index. As a result of this, all calls to open and close tabs in
- this TabTracker's window must go through the appropriate instance of the
- TabTracker. Also note that if a lower indexed window is closed after this
- TabTracker is instantiated, this TabTracker will lose track of its window
- """
-
- def __init__(self, browser, visible=False):
- """
- Args:
- browser: an instance of PyUITest
- visible: whether or not this TabTracker's window will be visible
- """
- # A binary search tree would be faster, but this is easier to write.
- # If this needs to become faster, understand that the important operations
- # here are append, arbitrary deletion and searching.
- self._uuids = [None]
- self._window_idx = browser.GetBrowserWindowCount()
- self._browser = browser
- browser.OpenNewBrowserWindow(visible)
- # We leave the 0'th tab empty to have something to close on __del__
-
- def __del__(self):
- self._browser.CloseBrowserWindow(self._window_idx)
-
- def CreateTab(self, url='about:blank'):
- """Create a tracked tab and return its uuid.
-
- Args:
- url: a URL to navigate to
-
- Returns:
- a uuid uniquely identifying that tab within this TabTracker
- """
- self._browser.AppendTab(url, self._window_idx)
- # We use uuids here rather than a monotonic integer to prevent confusion
- # with the tab index.
- tab_uuid = uuid.uuid4()
- self._uuids.append(tab_uuid)
- return tab_uuid
-
- def ReleaseTab(self, tab_uuid):
- """Release and close a tab tracked by this TabTracker.
-
- Args:
- tab_uuid: the uuid of the tab to close
- """
- idx = self.GetTabIndex(tab_uuid)
- self._browser.CloseTab(tab_index=idx, windex=self._window_idx)
- del self._uuids[idx]
-
- def GetTabIndex(self, tab_uuid):
- """Get the index of a tracked tab within this TabTracker's window.
-
- Args:
- tab_uuid: the uuid of the tab to close
-
- Returns:
- the index of the tab within this TabTracker's window
- """
- return self._uuids.index(tab_uuid)
-
- def GetWindowIndex(self):
- """Get the index of this TabTracker's window.
-
- Returns:
- the index of this TabTracker's window
- """
- return self._window_idx
diff --git a/chrome/test/functional/tracing/timeline_model.py b/chrome/test/functional/tracing/timeline_model.py
deleted file mode 100644
index 68573093..0000000
--- a/chrome/test/functional/tracing/timeline_model.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (c) 2012 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.
-
-import json
-import os
-
-
-class TimelineModel(object):
- """A proxy for about:tracing's TimelineModel class.
-
- Test authors should never need to know that this class is a proxy.
- """
- @staticmethod
- def _EscapeForQuotedJavascriptExecution(js):
- # Poor man's string escape.
- return js.replace('\'', '\\\'');
-
- def __init__(self, js_executor, shim_id):
- self._js_executor = js_executor
- self._shim_id = shim_id
-
- # Warning: The JSON serialization process removes cyclic references.
- # TODO(eatnumber): regenerate these cyclic references on deserialization.
- def _CallModelMethod(self, method_name, *args):
- result = self._js_executor(
- """window.timelineModelShims['%s'].invokeMethod('%s', '%s')""" % (
- self._shim_id,
- self._EscapeForQuotedJavascriptExecution(method_name),
- self._EscapeForQuotedJavascriptExecution(json.dumps(args))
- )
- )
- if result['success']:
- return result['data']
- # TODO(eatnumber): Make these exceptions more reader friendly.
- raise RuntimeError(result)
-
- def __del__(self):
- self._js_executor("""
- window.timelineModelShims['%s'] = undefined;
- window.domAutomationController.send('');
- """ % self._shim_id)
-
- def GetAllThreads(self):
- return self._CallModelMethod('getAllThreads')
-
- def GetAllCpus(self):
- return self._CallModelMethod('getAllCpus')
-
- def GetAllProcesses(self):
- return self._CallModelMethod('getAllProcesses')
-
- def GetAllCounters(self):
- return self._CallModelMethod('getAllCounters')
-
- def FindAllThreadsNamed(self, name):
- return self._CallModelMethod('findAllThreadsNamed', name);
diff --git a/chrome/test/functional/tracing/timeline_model_shim.js b/chrome/test/functional/tracing/timeline_model_shim.js
deleted file mode 100644
index be4fcdb..0000000
--- a/chrome/test/functional/tracing/timeline_model_shim.js
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2012 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.
-
-function TimelineModelShim() {
- tracing.TimelineModel.apply(this, arguments);
-}
-
-TimelineModelShim.prototype = {
- __proto__: tracing.TimelineModel.prototype,
-
- invokeMethod: function(methodName, args) {
- var sendToPython = function(obj) {
- // We use sendJSON here because domAutomationController's send() chokes on
- // large amounts of data. Inside of send() it converts the arg to JSON and
- // invokes sendJSON. The JSON conversion is what fails. This way works
- // around the bad code, but note that the recieving python converts from
- // JSON before passing it back to the pyauto test.
- window.domAutomationController.sendJSON(
- JSON.stringify(obj)
- );
- };
- var result;
- try {
- result = this[methodName].apply(this, JSON.parse(args));
- } catch( e ) {
- var ret = {
- success: false,
- message: 'Unspecified error',
- };
- // We'll try sending the entire exception. If that doesn't work, it's ok.
- try {
- ret.exception = JSON.stringify(e);
- } catch(e2) {}
- if( typeof(e) == 'string' || e instanceof String ) {
- ret.message = e;
- } else {
- if( e.stack != undefined ) ret.stack = e.stack;
- if( e.message != undefined ) ret.message = e.message;
- }
- sendToPython(ret);
- throw e;
- }
- sendToPython({
- success: true,
- data: result
- });
- }
-},
-
-// This causes the PyAuto ExecuteJavascript call which executed this file to
-// return.
-window.domAutomationController.send('');
diff --git a/chrome/test/functional/tracing/tracer.js b/chrome/test/functional/tracing/tracer.js
deleted file mode 100644
index 75c43a7..0000000
--- a/chrome/test/functional/tracing/tracer.js
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2012 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.
-
-window.pyautoRecordTrace = function(systemTracing) {
- 'use strict';
- if( window.timelineModelShimId == undefined )
- window.timelineModelShimId = 0;
- if( window.timelineModelShims == undefined )
- window.timelineModelShims = {};
- var handler = function() {
- tracingController.removeEventListener('traceEnded', handler);
- var model = new TimelineModelShim(
- Array.prototype.slice.call(arguments, 1)
- );
- var events = [tracingController.traceEvents_];
- if (tracingController.supportsSystemTracing)
- events.push(tracingController.systemTraceEvents_);
- model.importTraces(events);
- var shimId = window.timelineModelShimId;
- window.timelineModelShims[shimId] = model;
- window.domAutomationController.send(shimId);
- window.timelineModelShimId++;
- };
- tracingController.addEventListener('traceEnded', handler);
- var willSystemTrace =
- tracingController.supportsSystemTracing ? systemTracing : false;
- tracingController.beginTracing(willSystemTrace);
- return willSystemTrace;
-};
-
-// This causes the PyAuto ExecuteJavascript call which executed this file to
-// return.
-window.domAutomationController.send('');
diff --git a/chrome/test/functional/tracing/tracer.py b/chrome/test/functional/tracing/tracer.py
deleted file mode 100644
index 0366e1d..0000000
--- a/chrome/test/functional/tracing/tracer.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# Copyright (c) 2012 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.
-
-import pyauto_tracing
-import pyauto
-import tab_tracker
-from timeline_model import TimelineModel
-
-import os
-
-
-class Tracer(object):
- """Controlls chrome and system tracing, returning a TimelineModel."""
-
- def __init__(self, browser, tab_tracker):
- """
- Args:
- browser: an instance of a PyUITest
- tab_tracker: an instance of a TabTracker
- """
- self._browser = browser
- self._tab_tracker = tab_tracker
- self._tab_uuid = tab_tracker.CreateTab('chrome://tracing')
-
- # TODO(eatnumber): Find a way to import timeline_model_shim.js from within
- # TimelineModelProxy
- # I'm not happy with importing timeline_model_shim.js
- # here. I'd rather pull it in from within TimelineModelProxy.
- # tracing_test.js depends on timeline_model_shim.js however.
- files = ['timeline_model_shim.js', 'tracer.js']
- for fileName in files:
- with open(os.path.join(os.path.dirname(__file__), fileName), 'r') as fd:
- self._ExecuteJavascript(fd.read())
-
- def __del__(self):
- self._tab_tracker.ReleaseTab(self._tab_uuid)
-
- def _ExecuteJavascript(self, js):
- return self._browser.ExecuteJavascript(
- js = js,
- windex = self._tab_tracker.GetWindowIndex(),
- tab_index = self._tab_tracker.GetTabIndex(self._tab_uuid)
- )
-
- def BeginTracing(self, system_tracing=True):
- """Start tracing.
-
- Args:
- system_tracing: whether or not to gather system traces along with chrome
- traces.
- """
- self._ExecuteJavascript("""
- window.domAutomationController.send(
- window.pyautoRecordTrace(%s)
- );
- """ % ('true' if system_tracing else 'false'))
-
- def EndTracing(self):
- """End tracing and return a TimelineModel.
-
- Returns:
- an instance of a TimelineModel which contains the results of the trace
- """
- return TimelineModel(
- js_executor = self._ExecuteJavascript.__get__(self, Tracer),
- shim_id = self._ExecuteJavascript('tracingController.endTracing();')
- )
-
-
-class TracerFactory(object):
- """A TracerFactory is used to produce a Tracer.
-
- It's recommended to use the same TracerFactory to produce all Tracers so that
- the same TabTracker can be used throughout
-
- Args:
- browser: an instance of a PyUITest
- """
- def __init__(self, browser):
- self._tab_tracker = tab_tracker.TabTracker(browser)
- self._browser = browser
-
- def Produce(self):
- """Produce an instance of a Tracer"""
- return Tracer(self._browser, self._tab_tracker)
diff --git a/chrome/test/functional/tracing/tracing_smoke_test.py b/chrome/test/functional/tracing/tracing_smoke_test.py
deleted file mode 100755
index 4621421..0000000
--- a/chrome/test/functional/tracing/tracing_smoke_test.py
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import pyauto_tracing
-import pyauto
-import tracer
-
-
-class TracingSmokeTest(pyauto.PyUITest):
- """Test basic functionality of the tracing API."""
- def setUp(self):
- super(TracingSmokeTest, self).setUp()
- self._tracer_factory = tracer.TracerFactory(self)
-
- def testGetData(self):
- """Check that we can find a CrBrowserMain thread."""
- tracer = self._tracer_factory.Produce()
- tracer.BeginTracing()
- model = tracer.EndTracing()
- self.assertEqual(1, len(model.FindAllThreadsNamed('CrBrowserMain')))
-
- def testMultipleTraces(self):
- """Check that we can run multiple traces on the same tracer."""
- tracer = self._tracer_factory.Produce()
- tracer.BeginTracing()
- model1 = tracer.EndTracing()
- tracer.BeginTracing()
- model2 = tracer.EndTracing()
- self.assertEqual(1, len(model1.FindAllThreadsNamed('CrBrowserMain')))
- self.assertEqual(1, len(model2.FindAllThreadsNamed('CrBrowserMain')))
-
- def testMultipleTracers(self):
- """Check that we can run multiple traces with multiple tracers."""
- tracer1 = self._tracer_factory.Produce()
- tracer2 = self._tracer_factory.Produce()
- # Nested calls to beginTracing is untested and probably won't work.
- tracer1.BeginTracing()
- model1 = tracer1.EndTracing()
- tracer2.BeginTracing()
- model2 = tracer2.EndTracing()
- self.assertEqual(1, len(model1.FindAllThreadsNamed('CrBrowserMain')))
- self.assertEqual(1, len(model2.FindAllThreadsNamed('CrBrowserMain')))
-
- def testModelValidAfterTracer(self):
- """Check that a TimelineModel is valid after its Tracer is gone."""
- tracer = self._tracer_factory.Produce()
- del self._tracer_factory
- tracer.BeginTracing()
- model = tracer.EndTracing()
- del tracer
- self.assertEqual(1, len(model.FindAllThreadsNamed('CrBrowserMain')))
-
-
-if __name__ == '__main__':
- pyauto_tracing.Main()
diff --git a/chrome/test/functional/webdriver_pages/__init__.py b/chrome/test/functional/webdriver_pages/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/chrome/test/functional/webdriver_pages/__init__.py
+++ /dev/null
diff --git a/chrome/test/functional/webdriver_pages/settings.py b/chrome/test/functional/webdriver_pages/settings.py
deleted file mode 100644
index 2a916c0..0000000
--- a/chrome/test/functional/webdriver_pages/settings.py
+++ /dev/null
@@ -1,699 +0,0 @@
-# Copyright (c) 2012 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.
-
-import types
-
-import selenium.common.exceptions
-from selenium.webdriver.common.action_chains import ActionChains
-from selenium.webdriver.support.ui import WebDriverWait
-
-
-def _FocusField(driver, list_elem, field_elem):
- """Focuses a field in a dynamic list.
-
- Note, the item containing the field should not be focused already.
-
- Typing into a field is tricky because the js automatically focuses and
- selects the text field after 50ms after it first receives focus. This
- method focuses the field and waits for the timeout to occur.
- For more info, see inline_editable_list.js and search for setTimeout.
- See crbug.com/97369.
-
- Args:
- list_elem: An element in the HTML list.
- field_elem: An element in the HTML text field.
-
- Raises:
- RuntimeError: If a timeout occurs when waiting for the focus event.
- """
- # To wait properly for the focus, we focus the last text field, and then
- # add a focus listener to it, so that we return when the element is focused
- # again after the timeout. We have to focus a different element in between
- # these steps, otherwise the focus event will not fire since the element
- # already has focus.
- # Ideally this should be fixed in the page.
-
- correct_focus_script = """
- (function(listElem, itemElem, callback) {
- if (document.activeElement == itemElem) {
- callback();
- return;
- }
- itemElem.focus();
- listElem.focus();
- itemElem.addEventListener("focus", callback);
- }).apply(null, arguments);
- """
- driver.set_script_timeout(5)
- try:
- driver.execute_async_script(correct_focus_script, list_elem, field_elem)
- except selenium.common.exceptions.TimeoutException:
- raise RuntimeError('Unable to focus list item ' + field_elem.tag_name)
-
-
-class Item(object):
- """A list item web element."""
- def __init__(self, elem):
- self._elem = elem
-
- def Remove(self, driver):
- button = self._elem.find_element_by_xpath('./button')
- ActionChains(driver).move_to_element(button).click().perform()
-
-
-class TextFieldsItem(Item):
- """An item consisting only of text fields."""
- def _GetFields(self):
- """Returns the text fields list."""
- return self._elem.find_elements_by_tag_name('input')
-
- def Set(self, values):
- """Sets the value(s) of the item's text field(s).
-
- Args:
- values: The new value or the list of the new values of the fields.
- """
- field_list = self._GetFields()
- if len(field_list) > 1:
- assert type(values) == types.ListType, \
- """The values must be a list for a HTML list that has multi-field
- items. '%s' should be in a list.""" % values
- value_list = values
- else:
- value_list = [values]
-
- assert len(field_list) == len(value_list), \
- """The item to be added must have the same number of fields as an item
- in the HTML list. Given item '%s' should have %s fields.""" % (
- value_list, len(field_list))
- for field, value in zip(field_list, value_list):
- field.clear()
- field.send_keys(value)
- field_list[-1].send_keys('\n') # press enter on the last field.
-
- def Get(self):
- """Returns the list of the text field values."""
- return map(lambda f: f.get_attribute('value'), self._GetFields())
-
-
-class TextField(object):
- """A text field web element."""
- def __init__(self, elem):
- self._elem = elem
-
- def Set(self, value):
- """Sets the value of the text field.
-
- Args:
- value: The new value of the field.
- """
- self._elem.clear()
- self._elem.send_keys(value)
-
- def Get(self):
- """Returns the value of the text field."""
- return self._elem.get_attribute('value')
-
-
-class List(object):
- """A web element that holds a list of items."""
-
- def __init__(self, driver, elem, item_class=Item):
- """item element is an element in the HTML list.
- item class is the class of item the list holds."""
- self._driver = driver
- self._elem = elem
- self._item_class = item_class
-
- def RemoveAll(self):
- """Removes all items from the list.
-
- In the loop the removal of an elem renders the remaining elems of the list
- invalid. After each item is removed, GetItems() is called.
- """
- for i in range(len(self.GetItems())):
- self.GetItems()[0].Remove(self._driver)
-
- def GetItems(self):
- """Returns all the items that are in the list."""
- items = self._GetItemElems()
- return map(lambda x: self._item_class(x), items)
-
- def GetSize(self):
- """Returns the number of items in the list."""
- return len(self._GetItemElems())
-
- def _GetItemElems(self):
- return self._elem.find_elements_by_xpath('.//*[@role="listitem"]')
-
-
-class DynamicList(List):
- """A web element that holds a dynamic list of items of text fields.
-
- Terminology:
- item element: an element in the HTML list item.
- item_class: the class of item the list holds
- placeholder: the last item element in the list, which is not committed yet
-
- The user can add new items to the list by typing in the placeholder item.
- When a user presses enter or focuses something else, the placeholder item
- is committed and a new placeholder is created. An item may contain 1 or
- more text fields.
- """
-
- def __init__(self, driver, elem, item_class=TextFieldsItem):
- return super(DynamicList, self).__init__(
- driver, elem, item_class=item_class)
-
- def GetPlaceholderItem(self):
- return self.GetItems()[-1]
-
- def GetCommittedItems(self):
- """Returns all the items that are in the list, except the placeholder."""
- return map(lambda x: self._item_class(x), self._GetCommittedItemElems())
-
- def GetSize(self):
- """Returns the number of items in the list, excluding the placeholder."""
- return len(self._GetCommittedItemElems())
-
- def _GetCommittedItemElems(self):
- return self._GetItemElems()[:-1]
-
- def _GetPlaceholderElem(self):
- return self._GetItemElems()[-1]
-
-
-class AutofillEditAddressDialog(object):
- """The overlay for editing an autofill address."""
-
- _URL = 'chrome://settings-frame/autofillEditAddress'
-
- @staticmethod
- def FromNavigation(driver):
- """Creates an instance of the dialog by navigating directly to it."""
- driver.get(AutofillEditAddressDialog._URL)
- return AutofillEditAddressDialog(driver)
-
- def __init__(self, driver):
- self.driver = driver
- assert self._URL == driver.current_url
- self.dialog_elem = driver.find_element_by_id(
- 'autofill-edit-address-overlay')
-
- def Fill(self, names=None, addr_line_1=None, city=None, state=None,
- postal_code=None, country_code=None, phones=None):
- """Fills in the given data into the appropriate fields.
-
- If filling into a text field, the given value will replace the current one.
- If filling into a list, the values will be added after all items are
- deleted.
-
- Note: 'names', in the new autofill UI, is an array of full names. A full
- name is an array of first, middle, last names. Example:
- names=[['Joe', '', 'King'], ['Fred', 'W', 'Michno']]
-
- Args:
- names: List of names; each name should be [first, middle, last].
- addr_line_1: First line in the address.
- city: City.
- state: State.
- postal_code: Postal code (zip code for US).
- country_code: Country code (e.g., US or FR).
- phones: List of phone numbers.
- """
- id_dict = {'addr-line-1': addr_line_1,
- 'city': city,
- 'state': state,
- 'postal-code': postal_code}
- for id, value in id_dict.items():
- if value is not None:
- TextField(self.dialog_elem.find_element_by_id(id)).Set(value)
-
- list_id_dict = {'full-name-list': names,
- 'phone-list': phones}
- for list_id, values in list_id_dict.items():
- if values is not None:
- list = DynamicList(self.driver,
- self.dialog_elem.find_element_by_id(list_id))
- list.RemoveAll()
- for value in values:
- list.GetPlaceholderItem().Set(value)
-
- if country_code is not None:
- self.dialog_elem.find_element_by_xpath(
- './/*[@id="country"]/*[@value="%s"]' % country_code).click()
-
- def GetStateLabel(self):
- """Returns the label used for the state text field."""
- return self.dialog_elem.find_element_by_id('state-label').text
-
- def GetPostalCodeLabel(self):
- """Returns the label used for the postal code text field."""
- return self.dialog_elem.find_element_by_id('postal-code-label').text
-
- def GetPhones(self):
- """Returns a list of the phone numbers in the phones list."""
- list = DynamicList(
- self.driver, self.dialog_elem.find_element_by_id('phone-list'))
- return [item.Get()[0] for item in list.GetCommittedItems()]
-
-
-class ContentTypes(object):
- COOKIES = 'cookies'
- IMAGES = 'images'
- JAVASCRIPT = 'javascript'
- HANDLERS = 'handlers'
- PLUGINS = 'plugins'
- POPUPS = 'popups'
- GEOLOCATION = 'location'
- NOTIFICATIONS = 'notifications'
- PASSWORDS = 'passwords'
-
-
-class Behaviors(object):
- ALLOW = 'allow'
- SESSION_ONLY = 'session_only'
- ASK = 'ask'
- BLOCK = 'block'
-
-
-class ContentSettingsPage(object):
- """The overlay for managing exceptions on the Content Settings page."""
-
- _URL = 'chrome://settings-frame/content'
-
- @staticmethod
- def FromNavigation(driver):
- """Creates an instance of the dialog by navigating directly to it."""
- driver.get(ContentSettingsPage._URL)
- return ContentSettingsPage(driver)
-
- def __init__(self, driver):
- assert self._URL == driver.current_url
- self.page_elem = driver.find_element_by_id(
- 'content-settings-page')
-
- def SetContentTypeOption(self, content_type, option):
- """Set the option for the specified content type.
-
- Args:
- content_type: The content type to manage.
- option: The option to allow, deny or ask.
- """
- self.page_elem.find_element_by_xpath(
- './/*[@name="%s"][@value="%s"]' % (content_type, option)).click()
-
-
-class ManageExceptionsPage(object):
- """The overlay for the content exceptions page."""
-
- @staticmethod
- def FromNavigation(driver, content_type):
- """Creates an instance of the dialog by navigating directly to it.
-
- Args:
- driver: The remote WebDriver instance to manage some content type.
- content_type: The content type to manage.
- """
- content_url = 'chrome://settings-frame/contentExceptions#%s' % content_type
- driver.get(content_url)
- return ManageExceptionsPage(driver, content_type)
-
- def __init__(self, driver, content_type):
- self._list_elem = driver.find_element_by_xpath(
- './/*[@id="content-settings-exceptions-area"]'
- '//*[@contenttype="%s"]//list[@role="list"]'
- '[@class="settings-list"]' % content_type)
- self._driver = driver
- self._content_type = content_type
- try:
- self._incognito_list_elem = driver.find_element_by_xpath(
- './/*[@id="content-settings-exceptions-area"]'
- '//*[@contenttype="%s"]//div[not(@hidden)]'
- '//list[@mode="otr"][@role="list"]'
- '[@class="settings-list"]' % content_type)
- except selenium.common.exceptions.NoSuchElementException:
- self._incognito_list_elem = None
-
- def _AssertIncognitoAvailable(self):
- if not self._incognito_list_elem:
- raise AssertionError(
- 'Incognito settings in "%s" content page not available'
- % self._content_type)
-
- def _GetExceptionList(self, incognito):
- if not incognito:
- list_elem = self._list_elem
- else:
- list_elem = self._incognito_list_elem
- return DynamicList(self._driver, list_elem)
-
- def _GetPatternList(self, incognito):
- if not incognito:
- list_elem = self._list_elem
- else:
- list_elem = self._incognito_list_elem
- pattern_list = [p.text for p in
- list_elem.find_elements_by_xpath(
- './/*[contains(@class, "exception-pattern")]'
- '//*[@class="static-text"]')]
- return pattern_list
-
- def AddNewException(self, pattern, behavior, incognito=False):
- """Add a new pattern and behavior to the Exceptions page.
-
- Args:
- pattern: Hostname pattern string.
- behavior: Setting for the hostname pattern (Allow, Block, Session Only).
- incognito: Incognito list box. Display to false.
-
- Raises:
- AssertionError when an exception cannot be added on the content page.
- """
- if incognito:
- self._AssertIncognitoAvailable()
- list_elem = self._incognito_list_elem
- else:
- list_elem = self._list_elem
- # Select behavior first.
- try:
- list_elem.find_element_by_xpath(
- './/*[@class="exception-setting"]'
- '[not(@displaymode)]//option[@value="%s"]'
- % behavior).click()
- except selenium.common.exceptions.NoSuchElementException:
- raise AssertionError(
- 'Adding new exception not allowed in "%s" content page'
- % self._content_type)
- # Set pattern now.
- self._GetExceptionList(incognito).GetPlaceholderItem().Set(pattern)
-
- def DeleteException(self, pattern, incognito=False):
- """Delete the exception for the selected hostname pattern.
-
- Args:
- pattern: Hostname pattern string.
- incognito: Incognito list box. Default to false.
- """
- if incognito:
- self._AssertIncognitoAvailable()
- list = self._GetExceptionList(incognito)
- items = filter(lambda item: item.Get()[0] == pattern,
- list.GetComittedItems())
- map(lambda item: item.Remove(self._driver), items)
-
- def GetExceptions(self, incognito=False):
- """Returns a dictionary of {pattern: behavior}.
-
- Example: {'file:///*': 'block'}
-
- Args:
- incognito: Incognito list box. Default to false.
- """
- if incognito:
- self._AssertIncognitoAvailable()
- list_elem = self._incognito_list_elem
- else:
- list_elem = self._list_elem
- pattern_list = self._GetPatternList(incognito)
- behavior_list = list_elem.find_elements_by_xpath(
- './/*[@role="listitem"][@class="deletable-item"]'
- '//*[@class="exception-setting"][@displaymode="static"]')
- assert len(pattern_list) == len(behavior_list), \
- 'Number of patterns does not match the behaviors.'
- return dict(zip(pattern_list, [b.text.lower() for b in behavior_list]))
-
- def GetBehaviorForPattern(self, pattern, incognito=False):
- """Returns the behavior for a given pattern on the Exceptions page.
-
- Args:
- pattern: Hostname pattern string.
- incognito: Incognito list box. Default to false.
- """
- if incognito:
- self._AssertIncognitoAvailable()
- assert self.GetExceptions(incognito).has_key(pattern), \
- 'No displayed host name matches pattern "%s"' % pattern
- return self.GetExceptions(incognito)[pattern]
-
- def SetBehaviorForPattern(self, pattern, behavior, incognito=False):
- """Set the behavior for the selected pattern on the Exceptions page.
-
- Args:
- pattern: Hostname pattern string.
- behavior: Setting for the hostname pattern (Allow, Block, Session Only).
- incognito: Incognito list box. Default to false.
-
- Raises:
- AssertionError when the behavior cannot be changed on the content page.
- """
- if incognito:
- self._AssertIncognitoAvailable()
- list_elem = self._incognito_list_elem
- else:
- list_elem = self._list_elem
- pattern_list = self._GetPatternList(incognito)
- listitem_list = list_elem.find_elements_by_xpath(
- './/*[@role="listitem"][@class="deletable-item"]')
- pattern_listitem_dict = dict(zip(pattern_list, listitem_list))
- # Set focus to appropriate listitem.
- listitem_elem = pattern_listitem_dict[pattern]
- listitem_elem.click()
- # Set behavior.
- try:
- listitem_elem.find_element_by_xpath(
- './/option[@value="%s"]' % behavior).click()
- except selenium.common.exceptions.ElementNotVisibleException:
- raise AssertionError(
- 'Changing the behavior is invalid for pattern '
- '"%s" in "%s" content page' % (behavior, self._content_type))
- # Send enter key.
- pattern_elem = listitem_elem.find_element_by_tag_name('input')
- pattern_elem.send_keys('\n')
-
-
-class RestoreOnStartupType(object):
- NEW_TAB_PAGE = 5
- RESTORE_SESSION = 1
- RESTORE_URLS = 4
-
-
-class BasicSettingsPage(object):
- """The basic settings page."""
- _URL = 'chrome://settings-frame/settings'
-
- @staticmethod
- def FromNavigation(driver):
- """Creates an instance of BasicSetting page by navigating to it."""
- driver.get(BasicSettingsPage._URL)
- return BasicSettingsPage(driver)
-
- def __init__(self, driver):
- self._driver = driver
- assert self._URL == driver.current_url
-
- def SetOnStartupOptions(self, on_startup_option):
- """Set on-startup options.
-
- Args:
- on_startup_option: option types for on start up settings.
-
- Raises:
- AssertionError when invalid startup option type is provided.
- """
- if on_startup_option == RestoreOnStartupType.NEW_TAB_PAGE:
- startup_option_elem = self._driver.find_element_by_id('startup-newtab')
- elif on_startup_option == RestoreOnStartupType.RESTORE_SESSION:
- startup_option_elem = self._driver.find_element_by_id(
- 'startup-restore-session')
- elif on_startup_option == RestoreOnStartupType.RESTORE_URLS:
- startup_option_elem = self._driver.find_element_by_id(
- 'startup-show-pages')
- else:
- raise AssertionError('Invalid value for restore start up option!')
- startup_option_elem.click()
-
- def _GoToStartupSetPages(self):
- self._driver.find_element_by_id('startup-set-pages').click()
-
- def _FillStartupURL(self, url):
- list = DynamicList(self._driver, self._driver.find_element_by_id(
- 'startupPagesList'))
- list.GetPlaceholderItem().Set(url + '\n')
-
- def AddStartupPage(self, url):
- """Add a startup URL.
-
- Args:
- url: A startup url.
- """
- self._GoToStartupSetPages()
- self._FillStartupURL(url)
- self._driver.find_element_by_id('startup-overlay-confirm').click()
- self._driver.get(self._URL)
-
- def UseCurrentPageForStartup(self, title_list):
- """Use current pages and verify page url show up in settings.
-
- Args:
- title_list: startup web page title list.
- """
- self._GoToStartupSetPages()
- self._driver.find_element_by_id('startupUseCurrentButton').click()
- self._driver.find_element_by_id('startup-overlay-confirm').click()
- def is_current_page_visible(driver):
- title_elem_list = driver.find_elements_by_xpath(
- '//*[contains(@class, "title")][text()="%s"]' % title_list[0])
- if len(title_elem_list) == 0:
- return False
- return True
- WebDriverWait(self._driver, 10).until(is_current_page_visible)
- self._driver.get(self._URL)
-
- def VerifyStartupURLs(self, title_list):
- """Verify saved startup URLs appear in set page UI.
-
- Args:
- title_list: A list of startup page title.
-
- Raises:
- AssertionError when start up URLs do not appear in set page UI.
- """
- self._GoToStartupSetPages()
- for i in range(len(title_list)):
- try:
- self._driver.find_element_by_xpath(
- '//*[contains(@class, "title")][text()="%s"]' % title_list[i])
- except selenium.common.exceptions.NoSuchElementException:
- raise AssertionError("Current page %s did not appear as startup page."
- % title_list[i])
- self._driver.find_element_by_id('startup-overlay-cancel').click()
-
- def CancelStartupURLSetting(self, url):
- """Cancel start up URL settings.
-
- Args:
- url: A startup url.
- """
- self._GoToStartupSetPages()
- self._FillStartupURL(url)
- self._driver.find_element_by_id('startup-overlay-cancel').click()
- self._driver.get(self._URL)
-
-
-class PasswordsSettings(object):
- """The overlay for managing passwords on the Content Settings page."""
-
- _URL = 'chrome://settings-frame/passwords'
-
- class PasswordsItem(Item):
- """A list of passwords item web element."""
- def _GetFields(self):
- """Returns the field list element."""
- return self._elem.find_elements_by_xpath('./div/*')
-
- def GetSite(self):
- """Returns the site field value."""
- return self._GetFields()[0].text
-
- def GetUsername(self):
- """Returns the username field value."""
- return self._GetFields()[1].text
-
-
- @staticmethod
- def FromNavigation(driver):
- """Creates an instance of the dialog by navigating directly to it.
-
- Args:
- driver: The remote WebDriver instance to manage some content type.
- """
- driver.get(PasswordsSettings._URL)
- return PasswordsSettings(driver)
-
- def __init__(self, driver):
- self._driver = driver
- assert self._URL == driver.current_url
- list_elem = driver.find_element_by_id('saved-passwords-list')
- self._items_list = List(self._driver, list_elem, self.PasswordsItem)
-
- def DeleteItem(self, url, username):
- """Deletes a line entry in Passwords Content Settings.
-
- Args:
- url: The URL string as it appears in the UI.
- username: The username string as it appears in the second column.
- """
- for password_item in self._items_list.GetItems():
- if (password_item.GetSite() == url and
- password_item.GetUsername() == username):
- password_item.Remove(self._driver)
-
-
-class CookiesAndSiteDataSettings(object):
- """The overlay for managing cookies on the Content Settings page."""
-
- _URL = 'chrome://settings-frame/cookies'
-
- @staticmethod
- def FromNavigation(driver):
- """Creates an instance of the dialog by navigating directly to it.
-
- Args:
- driver: The remote WebDriver instance for managing content type.
- """
- driver.get(CookiesAndSiteDataSettings._URL)
- return CookiesAndSiteDataSettings(driver)
-
- def __init__(self, driver):
- self._driver = driver
- assert self._URL == driver.current_url
- self._list_elem = driver.find_element_by_id('cookies-list')
-
- def GetSiteNameList(self):
- """Returns a list of the site names.
-
- This is a public function since the test needs to check if the site is
- deleted.
- """
- site_list = [p.text for p in
- self._list_elem.find_elements_by_xpath(
- './/*[contains(@class, "deletable-item")]'
- '//div[@class="cookie-site"]')]
- return site_list
-
- def _GetCookieNameList(self):
- """Returns a list where each item is the list of cookie names of each site.
-
- Example: site1 | cookie1 cookie2
- site2 | cookieA
- site3 | cookieA cookie1 cookieB
-
- Returns:
- A cookie names list such as:
- [ ['cookie1', 'cookie2'], ['cookieA'], ['cookieA', 'cookie1', 'cookieB'] ]
- """
- cookie_name_list = []
- for elem in self._list_elem.find_elements_by_xpath(
- './/*[@role="listitem"]'):
- elem.click()
- cookie_name_list.append([c.text for c in
- elem.find_elements_by_xpath('.//div[@class="cookie-item"]')])
- return cookie_name_list
-
- def DeleteSiteData(self, site):
- """Delete a site entry with its cookies in cookies content settings.
-
- Args:
- site: The site string as it appears in the UI.
- """
- delete_button_list = self._list_elem.find_elements_by_class_name(
- 'row-delete-button')
- site_list = self.GetSiteNameList()
- for i in range(len(site_list)):
- if site_list[i] == site:
- # Highlight the item so the close button shows up, then delete button
- # shows up, then click on the delete button.
- ActionChains(self._driver).move_to_element(
- delete_button_list[i]).click().perform()
diff --git a/chrome/test/functional/webpagereplay.py b/chrome/test/functional/webpagereplay.py
deleted file mode 100755
index 8d115ef..0000000
--- a/chrome/test/functional/webpagereplay.py
+++ /dev/null
@@ -1,255 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Start and stop Web Page Replay.
-
-Of the public module names, the following one is key:
- ReplayServer: a class to start/stop Web Page Replay.
-"""
-
-import logging
-import os
-import re
-import signal
-import subprocess
-import sys
-import time
-import urllib
-
-
-_CHROME_SRC_DIR = os.path.abspath(os.path.join(
- os.path.dirname(__file__), os.pardir, os.pardir, os.pardir))
-REPLAY_DIR = os.path.join(
- _CHROME_SRC_DIR, 'third_party', 'webpagereplay')
-LOG_PATH = os.path.join(
- _CHROME_SRC_DIR, 'webpagereplay_logs', 'logs.txt')
-
-
-# Chrome options to make it work with Web Page Replay.
-def GetChromeFlags(replay_host, http_port, https_port):
- assert replay_host and http_port and https_port, 'All arguments required'
- return [
- '--host-resolver-rules=MAP * %s,EXCLUDE localhost' % replay_host,
- '--testing-fixed-http-port=%s' % http_port,
- '--testing-fixed-https-port=%s' % https_port,
- '--ignore-certificate-errors',
- ]
-
-
-# Signal masks on Linux are inherited from parent processes. If anything
-# invoking us accidentally masks SIGINT (e.g. by putting a process in the
-# background from a shell script), sending a SIGINT to the child will fail
-# to terminate it. Running this signal handler before execing should fix that
-# problem.
-def ResetInterruptHandler():
- signal.signal(signal.SIGINT, signal.SIG_DFL)
-
-
-class ReplayError(Exception):
- """Catch-all exception for the module."""
- pass
-
-
-class ReplayNotFoundError(ReplayError):
- def __init__(self, label, path):
- self.args = (label, path)
-
- def __str__(self):
- label, path = self.args
- return 'Path does not exist for %s: %s' % (label, path)
-
-
-class ReplayNotStartedError(ReplayError):
- pass
-
-
-class ReplayServer(object):
- """Start and Stop Web Page Replay.
-
- Web Page Replay is a proxy that can record and "replay" web pages with
- simulated network characteristics -- without having to edit the pages
- by hand. With WPR, tests can use "real" web content, and catch
- performance issues that may result from introducing network delays and
- bandwidth throttling.
-
- Example:
- with ReplayServer(archive_path):
- self.NavigateToURL(start_url)
- self.WaitUntil(...)
-
- Environment Variables (for development):
- WPR_ARCHIVE_PATH: path to alternate archive file (e.g. '/tmp/foo.wpr').
- WPR_RECORD: if set, puts Web Page Replay in record mode instead of replay.
- WPR_REPLAY_DIR: path to alternate Web Page Replay source.
- """
-
- def __init__(self, archive_path, replay_host, dns_port, http_port, https_port,
- replay_options=None, replay_dir=None,
- log_path=None):
- """Initialize ReplayServer.
-
- Args:
- archive_path: a path to a specific WPR archive (required).
- replay_host: the hostname to serve traffic.
- dns_port: an integer port on which to serve DNS traffic. May be zero
- to let the OS choose an available port. If None DNS forwarding is
- disabled.
- http_port: an integer port on which to serve HTTP traffic. May be zero
- to let the OS choose an available port.
- https_port: an integer port on which to serve HTTPS traffic. May be zero
- to let the OS choose an available port.
- replay_options: an iterable of options strings to forward to replay.py.
- replay_dir: directory that has replay.py and related modules.
- log_path: a path to a log file.
- """
- self.archive_path = os.environ.get('WPR_ARCHIVE_PATH', archive_path)
- self.replay_options = list(replay_options or ())
- self.replay_dir = os.environ.get('WPR_REPLAY_DIR', replay_dir or REPLAY_DIR)
- self.log_path = log_path or LOG_PATH
- self.dns_port = dns_port
- self.http_port = http_port
- self.https_port = https_port
- self._replay_host = replay_host
-
- if 'WPR_RECORD' in os.environ and '--record' not in self.replay_options:
- self.replay_options.append('--record')
- self.is_record_mode = '--record' in self.replay_options
- self._AddDefaultReplayOptions()
-
- self.replay_py = os.path.join(self.replay_dir, 'replay.py')
-
- if self.is_record_mode:
- self._CheckPath('archive directory', os.path.dirname(self.archive_path))
- elif not os.path.exists(self.archive_path):
- self._CheckPath('archive file', self.archive_path)
- self._CheckPath('replay script', self.replay_py)
-
- self.log_fh = None
- self.replay_process = None
-
- def _AddDefaultReplayOptions(self):
- """Set WPR command-line options. Can be overridden if needed."""
- self.replay_options = [
- '--host', str(self._replay_host),
- '--port', str(self.http_port),
- '--ssl_port', str(self.https_port),
- '--use_closest_match',
- '--no-dns_forwarding',
- '--log_level', 'warning'
- ] + self.replay_options
- if self.dns_port is not None:
- self.replay_options.extend(['--dns_port', str(self.dns_port)])
-
- def _CheckPath(self, label, path):
- if not os.path.exists(path):
- raise ReplayNotFoundError(label, path)
-
- def _OpenLogFile(self):
- log_dir = os.path.dirname(self.log_path)
- if not os.path.exists(log_dir):
- os.makedirs(log_dir)
- return open(self.log_path, 'w')
-
- def WaitForStart(self, timeout):
- """Checks to see if the server is up and running."""
- port_re = re.compile(
- '.*?(?P<protocol>[A-Z]+) server started on (?P<host>.*):(?P<port>\d+)')
-
- start_time = time.time()
- elapsed_time = 0
- while elapsed_time < timeout:
- if self.replay_process.poll() is not None:
- break # The process has exited.
-
- # Read the ports from the WPR log.
- if not self.http_port or not self.https_port or not self.dns_port:
- for line in open(self.log_path).readlines():
- m = port_re.match(line.strip())
- if m:
- if not self.http_port and m.group('protocol') == 'HTTP':
- self.http_port = int(m.group('port'))
- elif not self.https_port and m.group('protocol') == 'HTTPS':
- self.https_port = int(m.group('port'))
- elif not self.dns_port and m.group('protocol') == 'DNS':
- self.dns_port = int(m.group('port'))
-
- # Try to connect to the WPR ports.
- if self.http_port and self.https_port:
- try:
- up_url = '%s://%s:%s/web-page-replay-generate-200'
- http_up_url = up_url % ('http', self._replay_host, self.http_port)
- https_up_url = up_url % ('https', self._replay_host, self.https_port)
- if (200 == urllib.urlopen(http_up_url, None, {}).getcode() and
- 200 == urllib.urlopen(https_up_url, None, {}).getcode()):
- return True
- except IOError:
- pass
-
- poll_interval = min(max(elapsed_time / 10., .1), 5)
- time.sleep(poll_interval)
- elapsed_time = time.time() - start_time
-
- return False
-
- def StartServer(self):
- """Start Web Page Replay and verify that it started.
-
- Raises:
- ReplayNotStartedError: if Replay start-up fails.
- """
- cmd_line = [sys.executable, self.replay_py]
- cmd_line.extend(self.replay_options)
- cmd_line.append(self.archive_path)
- self.log_fh = self._OpenLogFile()
- logging.debug('Starting Web-Page-Replay: %s', cmd_line)
- kwargs = {'stdout': self.log_fh, 'stderr': subprocess.STDOUT}
- if sys.platform.startswith('linux') or sys.platform == 'darwin':
- kwargs['preexec_fn'] = ResetInterruptHandler
- self.replay_process = subprocess.Popen(cmd_line, **kwargs)
- if not self.WaitForStart(30):
- log = open(self.log_path).read()
- raise ReplayNotStartedError(
- 'Web Page Replay failed to start. Log output:\n%s' % log)
-
- def StopServer(self):
- """Stop Web Page Replay."""
- if self.replay_process:
- logging.debug('Trying to stop Web-Page-Replay gracefully')
- try:
- url = 'http://localhost:%s/web-page-replay-command-exit'
- urllib.urlopen(url % self.http_port, None, {})
- except IOError:
- # IOError is possible because the server might exit without response.
- pass
-
- start_time = time.time()
- while time.time() - start_time < 10: # Timeout after 10 seconds.
- if self.replay_process.poll() is not None:
- break
- time.sleep(1)
- else:
- try:
- # Use a SIGINT so that it can do graceful cleanup.
- self.replay_process.send_signal(signal.SIGINT)
- except: # pylint: disable=W0702
- # On Windows, we are left with no other option than terminate().
- if 'no-dns_forwarding' not in self.replay_options:
- logging.warning('DNS configuration might not be restored!')
- try:
- self.replay_process.terminate()
- except: # pylint: disable=W0702
- pass
- self.replay_process.wait()
- if self.log_fh:
- self.log_fh.close()
-
- def __enter__(self):
- """Add support for with-statement."""
- self.StartServer()
- return self
-
- def __exit__(self, unused_exc_type, unused_exc_val, unused_exc_tb):
- """Add support for with-statement."""
- self.StopServer()
diff --git a/chrome/test/functional/webrtc_write_wsh.py b/chrome/test/functional/webrtc_write_wsh.py
deleted file mode 100644
index 0cd13d3..0000000
--- a/chrome/test/functional/webrtc_write_wsh.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# Copyright (c) 2012 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.
-#
-# This module is handler for incoming data to the pywebsocket standalone server
-# (source is in http://code.google.com/p/pywebsocket/source/browse/trunk/src/).
-# It follows the conventions of the pywebsocket server and in our case receives
-# and stores incoming frames to disk.
-
-import Queue
-import os
-import sys
-import threading
-
-_NUMBER_OF_WRITER_THREADS = 10
-
-_HOME_ENV_NAME = 'HOMEPATH' if 'win32' == sys.platform else 'HOME'
-_WORKING_DIR = os.path.join(os.environ[_HOME_ENV_NAME], 'webrtc_video_quality')
-
-# I couldn't think of other way to handle this but through a global variable
-g_frame_number_counter = 0
-g_frames_queue = Queue.Queue()
-
-
-def web_socket_do_extra_handshake(request):
- pass # Always accept.
-
-
-def web_socket_transfer_data(request):
- while True:
- data = request.ws_stream.receive_message()
- if data is None:
- return
-
- # We assume we will receive only frames, i.e. binary data
- global g_frame_number_counter
- frame_number = str(g_frame_number_counter)
- g_frame_number_counter += 1
- g_frames_queue.put((frame_number, data))
-
-
-class FrameWriterThread(threading.Thread):
- """Writes received frames to disk.
-
- The frames are named in the format frame_xxxx, where xxxx is the 0-padded
- frame number. The frames and their numbers are obtained from a synchronized
- queue. The frames are written in the directory specified by _WORKING_DIR.
- """
- def __init__(self, queue):
- threading.Thread.__init__(self)
- self._queue = queue
-
- def run(self):
- while True:
- frame_number, frame_data = self._queue.get()
- file_name = 'frame_' + frame_number.zfill(4)
- file_name = os.path.join(_WORKING_DIR, file_name)
- frame = open(file_name, "wb")
- frame.write(frame_data)
- frame.close()
- self._queue.task_done()
-
-
-def start_threads():
- for i in range(_NUMBER_OF_WRITER_THREADS):
- t = FrameWriterThread(g_frames_queue)
- t.setDaemon(True)
- t.start()
- g_frames_queue.join()
-
-
-# This handler's entire code is imported as 'it is' and then incorporated in the
-# code of the standalone pywebsocket server. If we put this start_threads() call
-# inside a if __name__ == '__main__' clause it wouldn't run this code at all
-# (tested).
-start_threads()
diff --git a/chrome/test/functional/youtube.py b/chrome/test/functional/youtube.py
deleted file mode 100755
index 46a3d27..0000000
--- a/chrome/test/functional/youtube.py
+++ /dev/null
@@ -1,273 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import re
-import time
-
-import pyauto_functional
-import pyauto
-import pyauto_errors
-import test_utils
-
-
-class YoutubeTestHelper():
- """Helper functions for Youtube tests.
-
- For sample usage, look at class YoutubeTest.
- """
-
- # YouTube player states
- is_unstarted = '-1'
- is_playing = '1'
- is_paused = '2'
- has_ended = '0'
- _pyauto = None
-
- def __init__(self, pyauto):
- self._pyauto = pyauto
-
- def IsFlashPluginEnabled(self):
- """Verify flash plugin availability and its state."""
- return [x for x in self._pyauto.GetPluginsInfo().Plugins() \
- if x['name'] == 'Shockwave Flash' and x['enabled']]
-
- def AssertPlayerState(self, state, msg):
- expected_regex = '^%s$' % state
- self.WaitForDomNode('id("playerState")', expected_value=expected_regex,
- msg=msg)
-
- def WaitUntilPlayerReady(self):
- """Verify that player is ready."""
- self.AssertPlayerState(state=self.is_unstarted,
- msg='Failed to load youtube player.')
-
- def GetPlayerState(self):
- """Returns a player state."""
- js = """
- var val = ytplayer.getPlayerState();
- window.domAutomationController.send(val + '');
- """
- return self._pyauto.ExecuteJavascript(js)
-
- def GetVideoInfo(self):
- """Returns Youtube video info."""
- youtube_apis = self._pyauto.GetPrivateInfo()['youtube_api']
- youtube_debug_text = youtube_apis['GetDebugText']
- return self._pyauto.ExecuteJavascript(
- 'window.domAutomationController.send(%s);' % youtube_debug_text)
-
- def GetVideoDroppedFrames(self):
- """Returns total Youtube video dropped frames.
-
- Returns:
- -1 if failed to get video frames from the video data
- """
- video_data = self._pyauto.GetVideoInfo()
- matched = re.search('droppedFrames=([\d\.]+)', video_data)
- if matched:
- return int(matched.group(1))
- else:
- return -1
-
- def GetVideoFrames(self):
- """Returns Youtube video frames/second.
-
- Returns:
- -1 if failed to get droppd frames from the video data.
- """
- video_data = self._pyauto.GetVideoInfo()
- matched = re.search('videoFps=([\d\.]+)', video_data)
- if matched:
- return int(matched.group(1))
- else:
- return -1
-
- def GetVideoTotalBytes(self):
- """Returns video total size in bytes.
-
- To call this function, video must be in the paying state,
- or this returns 0.
- """
- total_bytes = 0
- total_bytes = self._pyauto.ExecuteJavascript("""
- bytesTotal = document.getElementById("bytesTotal");
- window.domAutomationController.send(bytesTotal.innerHTML);
- """)
- return int(total_bytes)
-
- def GetVideoLoadedBytes(self):
- """Returns video size in bytes."""
- loaded_bytes = 0
- loaded_bytes = self.ExecuteJavascript("""
- bytesLoaded = document.getElementById("bytesLoaded");
- window.domAutomationController.send(bytesLoaded.innerHTML);
- """)
- return int(loaded_bytes)
-
- def GetCurrentVideoTime(self):
- """Returns the current time of the video in seconds."""
- current_time = 0
- current_time = self.ExecuteJavascript("""
- videoCurrentTime = document.getElementById("videoCurrentTime");
- window.domAutomationController.send(videoCurrentTime.innerHTML);
- """)
- return int(current_time)
-
- def PlayVideo(self):
- """Plays the loaded video."""
- self._pyauto.ExecuteJavascript("""
- ytplayer.playVideo();
- window.domAutomationController.send('');
- """)
-
- def StopVideo(self):
- """Stops the video and cancels loading."""
- self._pyauto.ExecuteJavascript("""
- ytplayer.stopVideo();
- window.domAutomationController.send('');
- """)
-
- def PauseVideo(self):
- """Pause the video."""
- self.ExecuteJavascript("""
- ytplayer.pauseVideo();
- window.domAutomationController.send('');
- """)
-
- def PlayVideoAndAssert(self, youtube_video='zuzaxlddWbk',
- ignore_assert=False):
- """Start video and assert the playing state.
-
- By default test uses http://www.youtube.com/watch?v=zuzaxlddWbki.
-
- Args:
- youtube_video: The string ID of the youtube video to play.
- ignore_assert: flag to ignore the assertion and continue the test.
- """
- self._pyauto.assertTrue(self._pyauto.IsFlashPluginEnabled(),
- msg='From here Flash plugin is disabled or not available.')
- url = self._pyauto.GetHttpURLForDataPath(
- 'media', 'youtube.html?video=' + youtube_video)
- self._pyauto.NavigateToURL(url)
- self.WaitUntilPlayerReady()
- i = 0
- # The YouTube player will get in a state where it does not return the
- # number of loaded bytes. When this happens we need to reload the page
- # before starting the test.
- while self.GetVideoLoadedBytes() == 1 and i < 30:
- self._pyauto.NavigateToURL(url)
- self.WaitUntilPlayerReady()
- i = i + 1
- self.PlayVideo()
- if ignore_assert:
- return self.is_playing
- self.AssertPlayerState(state=self.is_playing,
- msg='Player did not enter the playing state.')
-
- def VideoBytesLoadingAndAssert(self):
- """Assert the video loading."""
- total_bytes = self.GetVideoTotalBytes()
- prev_loaded_bytes = 0
- loaded_bytes = 0
- count = 0
- while loaded_bytes < total_bytes:
- # We want to test bytes loading only twice
- count = count + 1
- if count == 2:
- break
- loaded_bytes = self.GetVideoLoadedBytes()
- self.assertTrue(prev_loaded_bytes <= loaded_bytes)
- prev_loaded_bytes = loaded_bytes
- # Give some time to load a video
- time.sleep(1)
-
- def PlayFAVideo(self):
- """Play and assert FA video playing.
-
- We are using multiple test videos in case any FA video playback fails
- becuase other tests are palying the same video and the test gets the
- simultaneous playback error.
- """
- fa_videos = ('APRpcscmbY0', 'yQqvrED-np0', 'KJuFw6hQdNY',
- 'BeFQbgxr_9g', 'L6JwlOudqA4')
- credentials = self.GetPrivateInfo()['test_fa_account']
- test_utils.GoogleAccountsLogin(self,
- credentials['username'], credentials['password'])
- for video in fa_videos:
- result = self.PlayVideoAndAssert(video, ignore_assert=True)
- if result is self.is_playing:
- return
- self.assertTrue(False, msg='Player did not enter the playing state.')
-
-
-class YoutubeTest(pyauto.PyUITest, YoutubeTestHelper):
- """Test case for Youtube videos."""
-
- def __init__(self, methodName='runTest', **kwargs):
- pyauto.PyUITest.__init__(self, methodName, **kwargs)
- YoutubeTestHelper.__init__(self, self)
-
- def testPlayerStatus(self):
- """Test that YouTube loads a player and changes player states.
-
- Test verifies various player states like unstarted, playing, paused
- and ended.
- """
- # Navigating to Youtube video. This video is 122 seconds long.
- # During tests, we are not goinig to play this video full.
- self.PlayVideoAndAssert()
- self.PauseVideo()
- self.AssertPlayerState(state=self.is_paused,
- msg='Player did not enter the paused state.')
- # Seek to the end of video
- self.ExecuteJavascript("""
- val = ytplayer.getDuration();
- ytplayer.seekTo(val, true);
- window.domAutomationController.send('');
- """)
- self.PlayVideo()
- # We've seeked to almost the end of the video but not quite.
- # Wait until the end.
- self.AssertPlayerState(state=self.has_ended,
- msg='Player did not reach the stopped state.')
-
- def testPlayerResolution(self):
- """Test various video resolutions."""
- self.PlayVideoAndAssert()
- resolutions = self.ExecuteJavascript("""
- res = ytplayer.getAvailableQualityLevels();
- window.domAutomationController.send(res.toString());
- """)
- resolutions = resolutions.split(',')
- for res in resolutions:
- self.ExecuteJavascript("""
- ytplayer.setPlaybackQuality('%s');
- window.domAutomationController.send('');
- """ % res)
- curr_res = self.ExecuteJavascript("""
- res = ytplayer.getPlaybackQuality();
- window.domAutomationController.send(res + '');
- """)
- self.assertEqual(res, curr_res, msg='Resolution is not set to %s.' % res)
-
- def testPlayerBytes(self):
- """Test that player downloads video bytes."""
- self.PlayVideoAndAssert()
- self.VideoBytesLoadingAndAssert()
-
- def testFAVideo(self):
- """Test that FlashAccess/DRM video plays."""
- self.PlayFAVideo()
- self.StopVideo()
-
- def testFAVideoBytes(self):
- """Test FlashAccess/DRM video bytes loading."""
- self.PlayFAVideo()
- self.VideoBytesLoadingAndAssert()
- self.StopVideo()
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/pyautolib/OWNERS b/chrome/test/pyautolib/OWNERS
deleted file mode 100644
index afe7a77..0000000
--- a/chrome/test/pyautolib/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-craigdh@chromium.org
diff --git a/chrome/test/pyautolib/PYAUTO_TESTS b/chrome/test/pyautolib/PYAUTO_TESTS
deleted file mode 100644
index 0b9cb3f..0000000
--- a/chrome/test/pyautolib/PYAUTO_TESTS
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright (c) 2010 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.
-
-{
- 'FULL': {
- 'all': [
- ],
-
- 'win': [
- ],
-
- 'mac': [
- ],
-
- 'linux': [
- ],
-
- 'chromeos': [
- ],
- },
-}
diff --git a/chrome/test/pyautolib/argc_argv.i b/chrome/test/pyautolib/argc_argv.i
deleted file mode 100644
index b705006..0000000
--- a/chrome/test/pyautolib/argc_argv.i
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2010 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.
-//
-// Make functions using (int argc, char** argv) usable as (sys.argv) from python
-
-%typemap(in) (int argc, char **argv) {
- int i;
- if (!PyList_Check($input)) {
- PyErr_SetString(PyExc_ValueError, "Expecting a list");
- return NULL;
- }
- $1 = PyList_Size($input);
- $2 = (char **) malloc(($1+1)*sizeof(char *));
- for (i = 0; i < $1; i++) {
- PyObject *s = PyList_GetItem($input,i);
- if (!PyString_Check(s)) {
- free($2);
- PyErr_SetString(PyExc_ValueError, "List items must be strings");
- return NULL;
- }
- $2[i] = PyString_AsString(s);
- }
- $2[i] = 0;
-}
-
-%typemap(freearg) (int argc, char **argv) {
- if ($2) free($2);
-}
-
diff --git a/chrome/test/pyautolib/asan_stub.c b/chrome/test/pyautolib/asan_stub.c
deleted file mode 100644
index ae8c215..0000000
--- a/chrome/test/pyautolib/asan_stub.c
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright (c) 2012 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.
-//
-// Fake Address Sanitizer run-time support.
-// Enough for programs to link and run, but will not find any errors.
-// Also, linking this to shared libraries voids the warranty.
-//
-// We need this fake thunks if we build Chrome with ASAN support because
-// pyautolib DSO is instrumented with ASAN and is loaded to regular python
-// process that has no ASAN runtime.
-//
-// We have three options here:
-// 1) use our custom build of Python that have ASAN runtime linked in,
-// 2) do not instrument pyautolib with ASAN support,
-// 3) use this fake asan thunks linked to pyautolib so that instrumented code
-// does not complain.
-//
-// Note that we should not use real ASAN runtime linked with DSO because it will
-// not have information about memory allocations made prior to DSO load.
-//
-// Option (2) is not easy because pyautolib uses code from Chrome
-// (see chrome_tests.gypi, dependencies for target_name: pyautolib) that
-// has been instrumented with ASAN. So even if we disable -sanitize=address
-// for pyautolib own sources, ASAN instrumentation will creep in from there.
-// To avoid ASAN instrumentation, we might force Chrome build to compile all our
-// dependencies one more time without -fsanitize=address.
-//
-// Note also that using these empty stubs prevents ASAN from catching bugs in
-// Python-pyautolib process. But we do not need it, we are interested in Chrome
-// bugs.
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-
-void __asan_init() {
- static int inited = 0;
- if (inited) return;
- inited = 1;
-#if __WORDSIZE == 64
- unsigned long start = 0x100000000000;
- unsigned long size = 0x100000000000;
-#else
- unsigned long start = 0x20000000;
- unsigned long size = 0x20000000;
-#endif
- void *res = mmap((void*)start, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
- 0, 0);
- if (res == (void*)start) {
- fprintf(stderr, "Fake AddressSanitizer run-time initialized ok at %p\n",
- res);
- } else {
- fprintf(stderr, "Fake AddressSanitizer run-time failed to initialize.\n"
- "You have been warned. Aborting.");
- abort();
- }
-}
-
-// Update the name when asan api updates.
-void __asan_init_v1() {
- __asan_init();
-}
-
-void __asan_init_v3() {
- static int inited = 0;
- if (inited) return;
- inited = 1;
-#if __WORDSIZE == 64
- unsigned long start = 0x00007fff8000;
- unsigned long size = 0x100000000000;
-#else
- unsigned long start = 0x20000000;
- unsigned long size = 0x20000000;
-#endif
- void *res = mmap((void*)start, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
- 0, 0);
- if (res == (void*)start) {
- fprintf(stderr, "Fake AddressSanitizer run-time initialized ok at %p\n",
- res);
- } else {
- fprintf(stderr, "Fake AddressSanitizer run-time failed to initialize.\n"
- "You have been warned. Aborting.");
- abort();
- }
-}
-
-void __asan_handle_no_return() { }
-void __asan_register_globals() { }
-void __asan_report_load1() { }
-void __asan_report_load16() { }
-void __asan_report_load2() { }
-void __asan_report_load4() { }
-void __asan_report_load8() { }
-void __asan_report_load_n() { }
-void __asan_report_store1() { }
-void __asan_report_store16() { }
-void __asan_report_store2() { }
-void __asan_report_store4() { }
-void __asan_report_store8() { }
-void __asan_report_store_n() { }
-void __asan_set_error_report_callback() { }
-void __asan_unregister_globals() { }
-void __sanitizer_sandbox_on_notify() { }
-void __asan_before_dynamic_init(const char *module_name) { }
-void __asan_after_dynamic_init() { }
-int __asan_option_detect_stack_use_after_return;
-typedef unsigned long long uptr;
-void __asan_poison_memory_region(void const volatile *addr, uptr size) { }
-void __asan_unpoison_memory_region(void const volatile *addr, uptr size) { }
-uptr __asan_stack_malloc_0(uptr size, uptr real_stack) {}
-uptr __asan_stack_malloc_1(uptr size, uptr real_stack) {}
-uptr __asan_stack_malloc_2(uptr size, uptr real_stack) {}
-uptr __asan_stack_malloc_3(uptr size, uptr real_stack) {}
-uptr __asan_stack_malloc_4(uptr size, uptr real_stack) {}
-uptr __asan_stack_malloc_5(uptr size, uptr real_stack) {}
-uptr __asan_stack_malloc_6(uptr size, uptr real_stack) {}
-uptr __asan_stack_malloc_7(uptr size, uptr real_stack) {}
-uptr __asan_stack_malloc_8(uptr size, uptr real_stack) {}
-uptr __asan_stack_malloc_9(uptr size, uptr real_stack) {}
-uptr __asan_stack_malloc_10(uptr size, uptr real_stack) {}
-void __asan_stack_free_0(uptr ptr, uptr size, uptr real_stack) {}
-void __asan_stack_free_1(uptr ptr, uptr size, uptr real_stack) {}
-void __asan_stack_free_2(uptr ptr, uptr size, uptr real_stack) {}
-void __asan_stack_free_3(uptr ptr, uptr size, uptr real_stack) {}
-void __asan_stack_free_4(uptr ptr, uptr size, uptr real_stack) {}
-void __asan_stack_free_5(uptr ptr, uptr size, uptr real_stack) {}
-void __asan_stack_free_6(uptr ptr, uptr size, uptr real_stack) {}
-void __asan_stack_free_7(uptr ptr, uptr size, uptr real_stack) {}
-void __asan_stack_free_8(uptr ptr, uptr size, uptr real_stack) {}
-void __asan_stack_free_9(uptr ptr, uptr size, uptr real_stack) {}
-void __asan_stack_free_10(uptr ptr, uptr size, uptr real_stack) {}
diff --git a/chrome/test/pyautolib/bookmark_model.py b/chrome/test/pyautolib/bookmark_model.py
deleted file mode 100644
index b70fa4a..0000000
--- a/chrome/test/pyautolib/bookmark_model.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# Copyright (c) 2011 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.
-
-"""BookmarkModel: python representation of the bookmark model.
-
-Obtain one of these from PyUITestSuite::GetBookmarkModel() call.
-"""
-
-import os
-import simplejson as json
-import sys
-
-class BookmarkModel(object):
-
- def __init__(self, json_string):
- """Initialize a BookmarkModel from a string of json.
-
- The JSON representation is the same as used by the bookmark model
- to save to disk.
-
- Args:
- json_string: a string of JSON.
- """
- self.bookdict = json.loads(json_string)
-
- def BookmarkBar(self):
- """Return the bookmark bar node as a dict."""
- return self.bookdict['roots']['bookmark_bar']
-
- def Other(self):
- """Return the 'other' node (e.g. parent of "Other Bookmarks")"""
- return self.bookdict['roots']['other']
-
- def NodeCount(self, node=None):
- """Return a count of bookmark nodes, including folders.
-
- The root node itself is included in the count.
-
- Args:
- node: the root to start with. If not specified, count all."""
- if node == None:
- return reduce(lambda x, y: x + y,
- [self.NodeCount(x)
- for x in self.bookdict['roots'].values()])
- total = 1
- children = node.get('children', None)
- if children:
- total = total + reduce(lambda x,y: x + y,
- [self.NodeCount(x) for x in children])
- return total
-
- def FindByID(self, id, nodes=None):
- """Find the bookmark by id. Return the dict or None.
-
- Args:
- id: the id to look for.
- nodes: an iterable of nodes to start with. If not specified, search all.
- 'Not specified' means None, not [].
- """
- # Careful; we may get an empty list which is different than not
- # having specified a list.
- if nodes == None:
- nodes = self.bookdict['roots'].values()
- # Check each item. If it matches, return. If not, check each of
- # their kids.
- for node in nodes:
- if node['id'] == id:
- return node
- for child in node.get('children', []):
- found_node = self.FindByID(id, [child])
- if found_node:
- return found_node
- # Not found at all.
- return None
-
- def FindByTitle(self, title, nodes=None):
- """Return a tuple of all nodes which have |title| in their title.
-
- Args:
- title: the title to look for.
- node: an iterable of nodes to start with. If not specified, search all.
- 'Not specified' means None, not [].
- """
- # Careful; we may get an empty list which is different than not
- # having specified a list.
- if nodes == None:
- nodes = self.bookdict['roots'].values()
- # Check each item. If it matches, return. If not, check each of
- # their kids.
- results = []
- for node in nodes:
- node_title = node.get('title', None) or node.get('name', None)
- if title == node_title:
- results.append(node)
- # Note we check everything; unlike the FindByID, we do not stop early.
- for child in node.get('children', []):
- results += self.FindByTitle(title, [child])
- return results
diff --git a/chrome/test/pyautolib/chrome_driver_factory.py b/chrome/test/pyautolib/chrome_driver_factory.py
deleted file mode 100644
index a5ef54bb..0000000
--- a/chrome/test/pyautolib/chrome_driver_factory.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# Copyright (c) 2012 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.
-
-"""Factory that creates ChromeDriver instances for pyauto."""
-
-import os
-import random
-import tempfile
-
-import pyauto_paths
-from selenium import webdriver
-from selenium.webdriver.chrome import service
-
-
-class ChromeDriverFactory(object):
- """"Factory that creates ChromeDriver instances for pyauto.
-
- Starts a single ChromeDriver server when necessary. Users should call 'Stop'
- when no longer using the factory.
- """
-
- def __init__(self, port=0):
- """Initialize ChromeDriverFactory.
-
- Args:
- port: The port for WebDriver to use; by default the service will select a
- free port.
- """
- self._chromedriver_port = port
- self._chromedriver_server = None
-
- def NewChromeDriver(self, pyauto):
- """Creates a new remote WebDriver instance.
-
- This instance will connect to a new automation provider of an already
- running Chrome.
-
- Args:
- pyauto: pyauto.PyUITest instance
-
- Returns:
- selenium.webdriver.remote.webdriver.WebDriver instance.
- """
- if pyauto.IsChromeOS():
- os.putenv('DISPLAY', ':0.0')
- os.putenv('XAUTHORITY', '/home/chronos/.Xauthority')
- self._StartServerIfNecessary()
- channel_id = 'testing' + hex(random.getrandbits(20 * 4))[2:-1]
- if not pyauto.IsWin():
- channel_id = os.path.join(tempfile.gettempdir(), channel_id)
- pyauto.CreateNewAutomationProvider(channel_id)
- return webdriver.Remote(self._chromedriver_server.service_url,
- {'chrome.channel': channel_id,
- 'chrome.noWebsiteTestingDefaults': True})
-
- def _StartServerIfNecessary(self):
- """Starts the ChromeDriver server, if not already started."""
- if self._chromedriver_server is None:
- exe = pyauto_paths.GetChromeDriverExe()
- assert exe, 'Cannot find chromedriver exe. Did you build it?'
- self._chromedriver_server = service.Service(exe, self._chromedriver_port)
- self._chromedriver_server.start()
-
- def Stop(self):
- """Stops the ChromeDriver server, if running."""
- if self._chromedriver_server is not None:
- self._chromedriver_server.stop()
- self._chromedriver_server = None
-
- def GetPort(self):
- """Gets the port ChromeDriver is set to use.
-
- Returns:
- The port all ChromeDriver instances returned from NewChromeDriver() will
- be listening on. A return value of 0 indicates the ChromeDriver service
- will select a free port.
- """
- return self._chromedriver_port
-
- def __del__(self):
- self.Stop()
diff --git a/chrome/test/pyautolib/chromeos/__init__.py b/chrome/test/pyautolib/chromeos/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/chrome/test/pyautolib/chromeos/__init__.py
+++ /dev/null
diff --git a/chrome/test/pyautolib/chromeos/chromeos_utils.py b/chrome/test/pyautolib/chromeos/chromeos_utils.py
deleted file mode 100755
index eb26a6f..0000000
--- a/chrome/test/pyautolib/chromeos/chromeos_utils.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import logging
-import os
-import sys
-
-
-def _SetupPaths():
- sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
- sys.path.append('/usr/local') # to import autotest libs
-
-_SetupPaths()
-
-from autotest.cros import constants
-import pyauto
-
-
-class ChromeosUtils(pyauto.PyUITest):
- """Utils for ChromeOS."""
-
- def LoginToDefaultAccount(self):
- """Login to ChromeOS using default testing account.
-
- Usage:
- python chromeos_utils.py \
- chromeos_utils.ChromeosUtils.LoginToDefaultAccount
- """
- # Should auto-login. Nothing to do here.
- # TODO(nirnimesh): Remove this when auto-login feature
- # reaches chromeos such that this helper is not necessary.
- pass
-
-
-if __name__ == '__main__':
- pyauto.Main()
diff --git a/chrome/test/pyautolib/chromeos/enable_testing.py b/chrome/test/pyautolib/chromeos/enable_testing.py
deleted file mode 100755
index 373c764..0000000
--- a/chrome/test/pyautolib/chromeos/enable_testing.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-"""Enable chrome testing interface on ChromeOS.
-
-Enables chrome automation over a named automation channel on ChromeOS.
-Also, allows passing extra flags to chrome (--extra-chrome-flags).
-The path to named testing interface automation socket is printed out.
-
-Needs to be run with superuser privileges.
-
-Usage:
- sudo python enable_testing.py --extra-chrome-flags="--homepage=about:blank"
-"""
-
-import dbus
-import optparse
-import os
-import sys
-
-
-class EnableChromeTestingOnChromeOS(object):
- """Helper to enable chrome testing interface on ChromeOS.
-
- Also, can add additional flags to chrome to be used for testing.
- """
-
- SESSION_MANAGER_INTERFACE = 'org.chromium.SessionManagerInterface'
- SESSION_MANAGER_PATH = '/org/chromium/SessionManager'
- SESSION_MANAGER_SERVICE = 'org.chromium.SessionManager'
-
- def _ParseArgs(self):
- parser = optparse.OptionParser()
- parser.add_option(
- '', '--extra-chrome-flags', action='append', default=[],
- help='Pass extra flags to chrome.')
- self._options, self._args = parser.parse_args()
-
- def Run(self):
- self._ParseArgs()
- assert os.geteuid() == 0, 'Needs superuser privileges.'
- system_bus = dbus.SystemBus()
- manager = dbus.Interface(system_bus.get_object(self.SESSION_MANAGER_SERVICE,
- self.SESSION_MANAGER_PATH),
- self.SESSION_MANAGER_INTERFACE)
- print manager.EnableChromeTesting(True, self._options.extra_chrome_flags)
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(EnableChromeTestingOnChromeOS().Run())
diff --git a/chrome/test/pyautolib/chromeos/power_strip.py b/chrome/test/pyautolib/chromeos/power_strip.py
deleted file mode 100644
index b614b67..0000000
--- a/chrome/test/pyautolib/chromeos/power_strip.py
+++ /dev/null
@@ -1,119 +0,0 @@
-# Copyright (c) 2011 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.
-
-import logging
-import re
-import telnetlib
-
-
-class PowerStrip(object):
- """Controls Server Technology CW-16V1-C20M switched CDUs.
- (Cabinet Power Distribution Unit)
-
- This class is used to control the CW-16V1-C20M unit which
- is a 16 port remote power strip. The strip supports AC devices
- using 100-120V 50/60Hz input voltages. The commands in this
- class are supported by switches that use Sentry Switched CDU Version 6.0g.
-
- Opens a new connection for every command.
- """
-
- TIMEOUT = 10
-
- def __init__(self, host, user='admn', password='admn'):
- self._host = host
- self._user = user
- self._password = password
-
- def PowerOff(self, outlet):
- """Powers off the device that is plugged into the specified outlet.
-
- Args:
- outlet: The outlet ID defined on the switch (eg. .a14).
- """
- self._DoCommand('off', outlet)
-
- def PowerOn(self, outlet):
- """Powers on the device that is plugged into the specified outlet.
-
- Args:
- outlet: The outlet ID defined on the switch (eg. .a14).
- """
- self._DoCommand('on', outlet)
-
- def _DoCommand(self, command, outlet):
- """Performs power strip commands on the specified outlet.
-
- Sample telnet interaction:
- Escape character is '^]'.
-
- Sentry Switched CDU Version 6.0g
-
- Username: admn
- Password: < password hidden from view >
-
- Location:
-
- Switched CDU: on .a1
-
- Outlet Outlet Outlet Control
- ID Name Status State
-
- .A1 TowerA_Outlet1 On On
-
- Command successful
-
- Switched CDU: < cdu cmd >
-
- Args:
- command: A valid CW-16V1-C20M command that follows the format
- <command> <outlet>.
- outlet: The outlet ID defined on the switch (eg. .a14).
- """
- tn = telnetlib.Telnet()
- # To avoid 'Connection Reset by Peer: 104' exceptions when rapid calls
- # are made to the telnet server on the power strip, we retry executing
- # a command.
- retry = range(5)
- for attempt in retry:
- try:
- tn.open(self._host, timeout=PowerStrip.TIMEOUT)
- resp = tn.read_until('Username:', timeout=PowerStrip.TIMEOUT)
- assert 'Username' in resp, 'Username not found in response. (%s)' % resp
- tn.write(self._user + '\n')
-
- resp = tn.read_until('Password:', timeout=PowerStrip.TIMEOUT)
- assert 'Password' in resp, 'Password not found in response. (%s)' % resp
- tn.write(self._password + '\n')
-
- resp = tn.read_until('Switched CDU:', timeout=PowerStrip.TIMEOUT)
- assert 'Switched CDU' in resp, 'Standard prompt not found in ' \
- 'response. (%s)' % resp
- tn.write('%s %s\n' % (command, outlet))
-
- # Obtain the output of command and make sure it matches with the action
- # we performed.
- # Sample valid output:
- # .A1 TowerA_Outlet1 On On
- resp = tn.read_until('Switched CDU:', timeout=PowerStrip.TIMEOUT)
- if not re.search('%s\s+\S+\s+%s\s+%s' % (outlet, command, command),
- resp, re.I):
- raise Exception('Command \'%s\' execution failed. (%s)' %
- (command, resp))
-
- # Exiting the telnet session cleanly significantly reduces the chance of
- # connection error on initiating the following telnet session.
- tn.write('exit\n')
- tn.read_all()
-
- # If we've gotten this far, there is no need to retry.
- break
- except Exception as e:
- logging.debug('Power strip retry on cmd "%s". Reason: %s'
- % (command, str(e)))
- if attempt == retry[-1]:
- raise Exception('Sentry Command "%s" failed. '
- 'Reason: %s' % (command, str(e)))
- finally:
- tn.close()
diff --git a/chrome/test/pyautolib/chromeos/suid_actions.py b/chrome/test/pyautolib/chromeos/suid_actions.py
deleted file mode 100755
index b0ba529..0000000
--- a/chrome/test/pyautolib/chromeos/suid_actions.py
+++ /dev/null
@@ -1,153 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Helper script to perform actions as a super-user on ChromeOS.
-
-Needs to be run with superuser privileges, typically using the
-suid_python binary.
-
-Usage:
- sudo python suid_actions.py --action=CleanFlimflamDirs
-"""
-
-import optparse
-import os
-import shutil
-import subprocess
-import sys
-import time
-
-sys.path.append('/usr/local') # to import autotest libs.
-from autotest.cros import constants
-from autotest.cros import cryptohome
-
-TEMP_BACKCHANNEL_FILE = '/tmp/pyauto_network_backchannel_file'
-
-
-class SuidAction(object):
- """Helper to perform some super-user actions on ChromeOS."""
-
- def _ParseArgs(self):
- parser = optparse.OptionParser()
- parser.add_option(
- '-a', '--action', help='Action to perform.')
- self._options = parser.parse_args()[0]
- if not self._options.action:
- raise RuntimeError('No action specified.')
-
- def Run(self):
- self._ParseArgs()
- assert os.geteuid() == 0, 'Needs superuser privileges.'
- handler = getattr(self, self._options.action)
- assert handler and callable(handler), \
- 'No handler for %s' % self._options.action
- handler()
- return 0
-
- ## Actions ##
- def CleanFlimflamDirs(self):
- """Clean the contents of all connection manager (shill/flimflam) profiles.
- """
- flimflam_dirs = ['/home/chronos/user/flimflam',
- '/home/chronos/user/shill',
- '/var/cache/flimflam',
- '/var/cache/shill']
-
- # The stop/start flimflam command should stop/start shill respectivly if
- # enabled.
- os.system('stop flimflam')
- try:
- for flimflam_dir in flimflam_dirs:
- if not os.path.exists(flimflam_dir):
- continue
- for item in os.listdir(flimflam_dir):
- path = os.path.join(flimflam_dir, item)
- if os.path.isdir(path):
- shutil.rmtree(path)
- else:
- os.remove(path)
- finally:
- os.system('start flimflam')
- # TODO(stanleyw): crosbug.com/29421 This method should wait until
- # flimflam/shill is fully initialized and accessible via DBus again.
- # Otherwise, there is a race conditions and subsequent accesses to
- # flimflam/shill may fail. Until this is fixed, waiting for the
- # resolv.conf file to be created is better than nothing.
- begin = time.time()
- while not os.path.exists(constants.RESOLV_CONF_FILE):
- if time.time() - begin > 10:
- raise RuntimeError('Timeout while waiting for flimflam/shill start.')
- time.sleep(.25)
-
- def RemoveAllCryptohomeVaults(self):
- """Remove any existing cryptohome vaults."""
- cryptohome.remove_all_vaults()
-
- def _GetEthInterfaces(self):
- """Returns a list of the eth* interfaces detected by the device."""
- # Assumes ethernet interfaces all have "eth" in the name.
- import pyudev
- return sorted([iface.sys_name for iface in
- pyudev.Context().list_devices(subsystem='net')
- if 'eth' in iface.sys_name])
-
- def _Renameif(self, old_iface, new_iface, mac_address):
- """Renames the interface with mac_address from old_iface to new_iface.
-
- Args:
- old_iface: The name of the interface you want to change.
- new_iface: The name of the interface you want to change to.
- mac_address: The mac address of the interface being changed.
- """
- subprocess.call(['stop', 'flimflam'])
- subprocess.call(['ifconfig', old_iface, 'down'])
- subprocess.call(['nameif', new_iface, mac_address])
- subprocess.call(['ifconfig', new_iface, 'up'])
- subprocess.call(['start', 'flimflam'])
-
- # Check and make sure interfaces have been renamed
- eth_ifaces = self._GetEthInterfaces()
- if new_iface not in eth_ifaces:
- raise RuntimeError('Interface %s was not renamed to %s' %
- (old_iface, new_iface))
- elif old_iface in eth_ifaces:
- raise RuntimeError('Old iface %s is still present' % old_iface)
-
- def SetupBackchannel(self):
- """Renames the connected ethernet interface to eth_test for offline mode
- testing. Does nothing if no connected interface is found.
- """
- # Return the interface with ethernet connected or returns if none found.
- for iface in self._GetEthInterfaces():
- with open('/sys/class/net/%s/operstate' % iface, 'r') as fp:
- if 'up' in fp.read():
- eth_iface = iface
- break
- else:
- return
-
- # Write backup file to be used by TeardownBackchannel to restore the
- # interface names.
- with open(TEMP_BACKCHANNEL_FILE, 'w') as fpw:
- with open('/sys/class/net/%s/address' % eth_iface) as fp:
- mac_address = fp.read().strip()
- fpw.write('%s, %s' % (eth_iface, mac_address))
-
- self._Renameif(eth_iface, 'eth_test', mac_address)
-
- def TeardownBackchannel(self):
- """Restores the eth interface names if SetupBackchannel was called."""
- if not os.path.isfile(TEMP_BACKCHANNEL_FILE):
- return
-
- with open(TEMP_BACKCHANNEL_FILE, 'r') as fp:
- eth_iface, mac_address = fp.read().split(',')
-
- self._Renameif('eth_test', eth_iface, mac_address)
- os.remove(TEMP_BACKCHANNEL_FILE)
-
-
-if __name__ == '__main__':
- sys.exit(SuidAction().Run())
diff --git a/chrome/test/pyautolib/chromeos_network.py b/chrome/test/pyautolib/chromeos_network.py
deleted file mode 100644
index 0b42fa0..0000000
--- a/chrome/test/pyautolib/chromeos_network.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# Copyright (c) 2012 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.
-
-import copy
-import dbus
-import logging
-import os
-import time
-
-from chromeos.power_strip import PowerStrip
-import pyauto
-import pyauto_errors
-
-class PyNetworkUITest(pyauto.PyUITest):
- """A subclass of PyUITest for Chrome OS network tests.
-
- A subclass of PyUITest that automatically sets the flimflam
- priorities to put wifi connections first before starting tests.
- This is for convenience when writing wifi tests.
- """
- _ROUTER_CONFIG_FILE = os.path.join(pyauto.PyUITest.DataDir(),
- 'pyauto_private', 'chromeos', 'network',
- 'wifi_testbed_config')
- _FLIMFLAM_PATH = 'org.chromium.flimflam'
-
- def setUp(self):
- self.CleanupFlimflamDirsOnChromeOS()
- # Move ethernet to the end of the flimflam priority list,
- # effectively hiding any ssh connections that the
- # test harness might be using and putting wifi ahead.
- self._PushServiceOrder('wifi,ethernet')
- self._ParseDefaultRoutingTable()
- pyauto.PyUITest.setUp(self)
-
- def tearDown(self):
- pyauto.PyUITest.tearDown(self)
- self._PopServiceOrder()
- # Remove the route entry for the power strip.
- if hasattr(self, 'ps_route_entry'):
- os.system('route del -net %(ipaddress)s gateway %(gateway)s netmask '
- '%(netmask)s dev %(iface)s' % self.ps_route_entry)
-
- def _GetFlimflamManager(self):
- _proxy = dbus.SystemBus().get_object(self._FLIMFLAM_PATH, '/')
- return dbus.Interface(_proxy, self._FLIMFLAM_PATH + '.Manager')
-
- def _ParseDefaultRoutingTable(self):
- """Creates and stores a dictionary of the default routing paths."""
- route_table_headers = ['destination', 'gateway', 'genmask', 'flags',
- 'metric', 'ref', 'use', 'iface']
- routes = os.popen('route -n | egrep "^0.0.0.0"').read()
- routes = [interface.split() for interface in routes.split('\n')][:-1]
- self.default_routes = {}
- for iface in routes:
- self.default_routes[iface[-1]] = dict(zip(route_table_headers, iface))
-
- def _SetServiceOrder(self, service_order):
- self._GetFlimflamManager().SetServiceOrder(service_order)
- # Flimflam throws a dbus exception if device is already disabled. This
- # is not an error.
- try:
- self._GetFlimflamManager().DisableTechnology('wifi')
- except dbus.DBusException as e:
- if 'org.chromium.flimflam.Error.AlreadyDisabled' not in str(e):
- raise e
- self._GetFlimflamManager().EnableTechnology('wifi')
-
- def _PushServiceOrder(self, service_order):
- self._old_service_order = self._GetFlimflamManager().GetServiceOrder()
- self._SetServiceOrder(service_order)
- service_order = service_order.split(',')
-
- # Verify services that are present in both the service_order
- # we set and the one retrieved from device are in the correct order.
- set_service_order = self._GetFlimflamManager().GetServiceOrder().split(',')
- common_service = set(service_order) & set(set_service_order)
-
- service_order = [s for s in service_order if s in common_service]
- set_service_order = [s for s in set_service_order if s in common_service]
-
- assert service_order == set_service_order, \
- 'Flimflam service order not set properly. %s != %s' % \
- (service_order, set_service_order)
-
- def _PopServiceOrder(self):
- self._SetServiceOrder(self._old_service_order)
-
- # Verify services that are present in both the service_order
- # we set and the one retrieved from device are in the correct order.
- old_service_order = self._old_service_order.split(',')
- set_service_order = self._GetFlimflamManager().GetServiceOrder().split(',')
- common_service = set(old_service_order) & set(set_service_order)
-
- old_service_order = [s for s in old_service_order if s in common_service]
- set_service_order = [s for s in set_service_order if s in common_service]
-
- assert old_service_order == set_service_order, \
- 'Flimflam service order not set properly. %s != %s' % \
- (old_service_order, set_service_order)
diff --git a/chrome/test/pyautolib/chromoting_cert.p12 b/chrome/test/pyautolib/chromoting_cert.p12
deleted file mode 100644
index 4751cce..0000000
--- a/chrome/test/pyautolib/chromoting_cert.p12
+++ /dev/null
Binary files differ
diff --git a/chrome/test/pyautolib/chromoting_helper.py b/chrome/test/pyautolib/chromoting_helper.py
deleted file mode 100644
index 1c14bb5..0000000
--- a/chrome/test/pyautolib/chromoting_helper.py
+++ /dev/null
@@ -1,200 +0,0 @@
-# Copyright (c) 2012 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.
-
-"""Chromoting helper to install/uninstall host and replace pref pane."""
-
-import abc
-import os
-import shutil
-import sys
-import subprocess
-
-
-class ChromotingHelper(object):
- """Chromoting helper base class."""
- __metaclass__ = abc.ABCMeta
-
- @abc.abstractmethod
- def InstallHost(self, bin_dir):
- """Installs the chromoting host"""
- return
-
- @abc.abstractmethod
- def UninstallHost(self, bin_dir):
- """Uninstalls the chromoting host"""
- return
-
-
-class ChromotingHelperMac(ChromotingHelper):
- """Chromoting Helper class for Mac.
-
- Installs/uninstalls host and replace the pref pane for testing purpose.
- """
-
- def InstallHost(self, bin_dir):
- """Installs host on Mac."""
- assert os.geteuid() == 0, 'Need superuser privileges'
-
- # Run most of the steps here with login user
- login_uid = os.getuid()
- os.seteuid(login_uid)
-
- # Change the working dir to the dir that has the host zip file
- current_dir = os.getcwd()
- pyautolib_dir = os.path.dirname(os.path.abspath(__file__))
- os.chdir(bin_dir)
- host_dir = 'remoting-me2me-host-mac'
- output_dir = os.path.join(host_dir, 'output')
-
- # Remove remoting-me2me-host-mac dir just in case
- shutil.rmtree(host_dir, True)
-
- # Unzip the host archive and prepare the files/dirs
- subprocess.call('unzip remoting-me2me-host-mac.zip', shell=True)
- subprocess.call('mkdir ' + output_dir, shell=True)
-
- # Prepare security identity for code signing purpose
- os.seteuid(0)
- key_chain = '/Library/Keychains/ChromotingTest'
- password = '1111'
- key = os.path.join(pyautolib_dir, 'chromoting_key.p12')
- cert = os.path.join(pyautolib_dir, 'chromoting_cert.p12')
- subprocess.call(['security', 'delete-keychain', key_chain])
- subprocess.call(['security', 'create-keychain', '-p',
- password, key_chain])
- subprocess.call(['security', 'import', key,
- '-k', key_chain, '-P', password, '-A'])
- subprocess.call(['security', 'import', cert,
- '-k', key_chain, '-P', password])
- os.seteuid(login_uid)
-
- # Sign the host
- do_signing = os.path.join(host_dir, 'do_signing.sh')
- subprocess.call(do_signing + ' ' + output_dir + ' ' + host_dir + ' ' +
- key_chain + ' "Chromoting Test"', shell=True)
-
- # Remove security identify
- os.seteuid(0)
- subprocess.call(['security', 'delete-keychain', key_chain])
- os.seteuid(login_uid)
-
- # Figure out the dmg name
- version = ""
- for output_file in os.listdir(output_dir):
- if output_file.endswith('.dmg'):
- version = os.path.basename(output_file)[len('ChromotingHost-'):-4]
-
- # Mount before installation
- dmg = os.path.join(output_dir, 'ChromotingHost-' + version + '.dmg')
- subprocess.call('hdiutil' + ' mount ' + dmg, shell=True)
-
- # Install host
- os.seteuid(0)
- mpkg = os.path.join('/Volumes', 'Chromoting Host ' + version,
- 'Chromoting Host.pkg')
- subprocess.call(['/usr/sbin/installer', '-pkg',
- mpkg, '-target', '/'])
- os.seteuid(login_uid)
-
- # Unmount after installation
- mounted = os.path.join('/Volumes', 'Chromoting Host ' + version)
- subprocess.call('hdiutil detach "' + mounted + '"', shell=True)
-
- # Clean up remoting-me2me-host-mac dir
- shutil.rmtree(host_dir, True)
-
- # Resume the original working dir
- os.chdir(current_dir)
-
- def UninstallHost(self, bin_dir):
- """Uninstalls host on Mac."""
- assert os.geteuid() == 0, 'Need superuser privileges'
- uninstall_app = os.path.join('/', 'Applications',
- 'Chromoting Host Uninstaller.app',
- 'Contents', 'MacOS',
- 'remoting_host_uninstaller')
- subprocess.call([uninstall_app, '--no-ui'])
-
- def ReplacePrefPaneMac(self, operation):
- """Constructs mock pref pane to replace the actual pref pane on Mac."""
- assert os.geteuid() == 0, 'Need superuser privileges'
-
- pref_pane_dir = os.path.join('/Library', 'PreferencePanes')
-
- mock_pref_pane = os.path.join(pref_pane_dir, 'mock_pref_pane')
- pref_pane = os.path.join(pref_pane_dir,
- 'ChromeRemoteDesktop.prefPane')
- mock_pref_pane_python = os.path.join(
- os.path.dirname(os.path.abspath(__file__)),
- 'mock_pref_pane.py')
-
- # When the symlink from real pref pane to mock pref pane exists,
- # mock pref pane will be modified to be a dir when the host is installed.
- # After the host is installed and mock pref pane is modified to be a file,
- # it will be a file until next host installation.
- if os.path.isdir(mock_pref_pane):
- shutil.rmtree(mock_pref_pane, True)
- elif os.path.isfile(mock_pref_pane):
- os.remove(mock_pref_pane)
-
- mock_pref_pane_file = open(mock_pref_pane, 'w')
- mock_pref_pane_file.write('#!/bin/bash\n')
- mock_pref_pane_file.write('\n')
- mock_pref_pane_file.write('suid-python' +
- ' ' + mock_pref_pane_python + ' ' + operation)
- mock_pref_pane_file.close()
-
- subprocess.call(['chmod', 'a+x', mock_pref_pane])
-
- # The real pref pane is a dir if the host is installed on a clean machine.
- # Once the test is run on the machine, real pref pane will be replaced to
- # a symlink.
- if os.path.isdir(pref_pane):
- shutil.rmtree(pref_pane, True)
- elif os.path.isfile(pref_pane):
- os.remove(pref_pane)
-
- subprocess.call(['ln', '-s', mock_pref_pane, pref_pane])
-
-
-class ChromotingHelperWindows(ChromotingHelper):
- """Chromoting Helper class for Windows for installing/uninstalling host."""
-
- def InstallHost(self, bin_dir):
- """Installs host on Windows."""
- host_msi = os.path.join(bin_dir, 'chromoting.msi')
- subprocess.Popen(['msiexec', '/i', host_msi, '/passive']).wait()
-
- def UninstallHost(self, bin_dir):
- """Uninstalls host on Windows."""
- host_msi = os.path.join(bin_dir, 'chromoting.msi')
- subprocess.Popen(['msiexec', '/x', host_msi, '/passive']).wait()
-
-
-def Main():
- """Main function to dispatch operations."""
- assert sys.platform.startswith('win') or \
- sys.platform.startswith('darwin'), \
- 'Only support Windows and Mac'
-
- if sys.platform.startswith('win'):
- helper = ChromotingHelperWindows()
- elif sys.platform.startswith('darwin'):
- helper = ChromotingHelperMac()
-
- if sys.argv[1] == 'install':
- helper.InstallHost(sys.argv[2])
- elif sys.argv[1] == 'uninstall':
- helper.UninstallHost(sys.argv[2])
- elif sys.argv[1] in ['enable', 'disable', 'changepin']:
- assert sys.platform.startswith('darwin'), \
- 'Replacing pref pane is Mac specific'
- helper.ReplacePrefPaneMac(sys.argv[1])
- else:
- print >>sys.stderr, 'Invalid syntax'
- return 1
-
-
-if __name__ == '__main__':
- Main()
diff --git a/chrome/test/pyautolib/chromoting_key.p12 b/chrome/test/pyautolib/chromoting_key.p12
deleted file mode 100644
index 55c75f1..0000000
--- a/chrome/test/pyautolib/chromoting_key.p12
+++ /dev/null
Binary files differ
diff --git a/chrome/test/pyautolib/chromotinglib.py b/chrome/test/pyautolib/chromotinglib.py
deleted file mode 100644
index 86b9176..0000000
--- a/chrome/test/pyautolib/chromotinglib.py
+++ /dev/null
@@ -1,619 +0,0 @@
-# Copyright (c) 2012 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.
-
-"""Includes different methods to drive chromoting UI."""
-
-import os
-import subprocess
-import sys
-import time
-
-from pyauto_errors import JSONInterfaceError
-
-
-class ChromotingMixIn(object):
- """MixIn for PyUITest that adds Chromoting-specific methods.
-
- Prepend it as a base class of a test to enable Chromoting functionality.
- This is a separate class from PyUITest to avoid namespace collisions.
-
- Example usage:
- class ChromotingExample(chromoting.ChromotingMixIn, pyauto.PyUITest):
- def testShare(self):
- app = self.InstallApp(self.GetWebappPath())
- self.LaunchApp(app)
- self.Authenticate()
- self.assertTrue(self.Share())
- """
-
- def _ExecuteJavascript(self, command, tab_index, windex):
- """Helper that returns immediately after running a Javascript command.
- """
- try:
- self.ExecuteJavascript(
- '%s; window.domAutomationController.send("done");' % command,
- tab_index, windex)
- return True
- except JSONInterfaceError:
- print '_ExecuteJavascript threw JSONInterfaceError'
- return False
-
- def _WaitForJavascriptCondition(self, condition, tab_index, windex,
- timeout=-1):
- """Waits until the Javascript condition is true.
-
- This is different from a naive self.WaitUntil(lambda: self.GetDOMValue())
- because it uses Javascript to check the condition instead of Python.
-
- Returns: True if condition is satisfied or otherwise False.
- """
- try:
- return self.WaitUntil(lambda: self.GetDOMValue(
- '(%s) ? "1" : ""' % condition, tab_index, windex), timeout)
- except JSONInterfaceError:
- print '_WaitForJavascriptCondition threw JSONInterfaceError'
- return False
-
- def _ExecuteAndWaitForMode(self, command, mode, tab_index, windex):
- """ Executes JavaScript and wait for remoting app mode equal to
- the given mode.
-
- Returns: True if condition is satisfied or otherwise False.
- """
- if not self._ExecuteJavascript(command, tab_index, windex):
- return False
- return self._WaitForJavascriptCondition(
- 'remoting.currentMode == remoting.AppMode.%s' % mode,
- tab_index, windex)
-
- def _ExecuteAndWaitForMajorMode(self, command, mode, tab_index, windex):
- """ Executes JavaScript and wait for remoting app major mode equal to
- the given mode.
-
- Returns: True if condition is satisfied or otherwise False.
- """
- if not self._ExecuteJavascript(command, tab_index, windex):
- return False
- return self._WaitForJavascriptCondition(
- 'remoting.getMajorMode() == remoting.AppMode.%s' % mode,
- tab_index, windex)
-
- def GetWebappPath(self):
- """Returns the path to the webapp.
-
- Expects the webapp to be in the same place as the pyautolib binaries.
- """
- return os.path.join(self.BrowserPath(), 'remoting', 'remoting.webapp')
-
- def _GetHelperRunner(self):
- """Returns the python binary name that runs chromoting_helper.py."""
- if sys.platform.startswith('win'):
- return 'python'
- else:
- return 'suid-python'
-
- def _GetHelper(self):
- """Get chromoting_helper.py."""
- return os.path.join(os.path.dirname(__file__), 'chromoting_helper.py')
-
- def InstallHostDaemon(self):
- """Installs the host daemon."""
- subprocess.call([self._GetHelperRunner(), self._GetHelper(),
- 'install', self.BrowserPath()])
-
- def UninstallHostDaemon(self):
- """Uninstalls the host daemon."""
- subprocess.call([self._GetHelperRunner(), self._GetHelper(),
- 'uninstall', self.BrowserPath()])
-
- def ContinueAuth(self, tab_index=1, windex=0):
- """Starts authentication."""
- self.assertTrue(
- self._WaitForJavascriptCondition('window.remoting && remoting.oauth2',
- tab_index, windex),
- msg='Timed out while waiting for remoting app to finish loading.')
- self._ExecuteJavascript('remoting.oauth2.doAuthRedirect();',
- tab_index, windex)
-
- def SignIn(self, email=None, password=None, otp=None,
- tab_index=1, windex=0):
- """Logs a user in.
-
- PyAuto tests start with a clean profile, so Chromoting tests should call
- this for every run after launching the app. If email or password is
- omitted, the user can type it into the browser window manually.
- """
- self.assertTrue(
- self._WaitForJavascriptCondition('document.getElementById("signIn")',
- tab_index, windex),
- msg='Unable to redirect for authentication.')
-
- if email:
- self._ExecuteJavascript('document.getElementById("Email").value = "%s";'
- 'document.getElementById("Passwd").focus();'
- % email, tab_index, windex)
-
- if password:
- self._ExecuteJavascript('document.getElementById("Passwd").value = "%s";'
- 'document.getElementById("signIn").click();'
- % password, tab_index, windex)
-
- if otp:
- self.assertTrue(
- self._WaitForJavascriptCondition(
- 'document.getElementById("smsVerifyPin")',
- tab_index, windex),
- msg='Invalid username or password.')
- self._ExecuteJavascript(
- 'document.getElementById("smsUserPin").value = "%s";'
- 'document.getElementById("smsVerifyPin").click();' % otp,
- tab_index, windex)
-
- # If the account adder screen appears, then skip it.
- self.assertTrue(
- self._WaitForJavascriptCondition(
- 'document.getElementById("skip") || '
- 'document.getElementById("submit_approve_access")',
- tab_index, windex),
- msg='No "skip adding account" or "approve access" link.')
- self._ExecuteJavascript(
- 'if (document.getElementById("skip")) '
- '{ document.getElementById("skip").click(); }',
- tab_index, windex)
-
- def AllowAccess(self, tab_index=1, windex=0):
- """Allows access to chromoting webapp."""
- # Approve access.
- self.assertTrue(
- self._WaitForJavascriptCondition(
- 'document.getElementById("submit_approve_access")',
- tab_index, windex),
- msg='Did not go to permission page.')
- self._WaitForJavascriptCondition(
- '!document.getElementById("submit_approve_access").disabled',
- tab_index, windex)
- self._ExecuteJavascript(
- 'document.getElementById("submit_approve_access").click();',
- tab_index, windex)
-
- # Wait for some things to be ready.
- self.assertTrue(
- self._WaitForJavascriptCondition(
- 'window.remoting && remoting.oauth2 && ' \
- 'remoting.oauth2.isAuthenticated()',
- tab_index, windex),
- msg='OAuth2 authentication failed.')
- self.assertTrue(
- self._WaitForJavascriptCondition(
- 'window.localStorage.getItem("remoting-email")',
- tab_index, windex),
- msg='Chromoting app did not reload after authentication.')
-
- def DenyAccess(self, tab_index=1, windex=0):
- """Deny and then allow access to chromoting webapp."""
- self.assertTrue(
- self._WaitForJavascriptCondition(
- 'document.getElementById("submit_deny_access")',
- tab_index, windex),
- msg='Did not go to permission page.')
- self._WaitForJavascriptCondition(
- '!document.getElementById("submit_deny_access").disabled',
- tab_index, windex)
- self._ExecuteJavascript(
- 'document.getElementById("submit_deny_access").click();',
- tab_index, windex)
-
- def SignOut(self, tab_index=1, windex=0):
- """Signs out from chromoting and signs back in."""
- self._ExecuteAndWaitForMode(
- 'document.getElementById("sign-out").click();',
- 'UNAUTHENTICATED', tab_index, windex)
-
- def Authenticate(self, tab_index=1, windex=0):
- """Finishes authentication flow for user."""
- self.ContinueAuth(tab_index, windex)
- account = self.GetPrivateInfo()['test_chromoting_account']
- self.host.SignIn(account['username'], account['password'], None,
- tab_index, windex)
- self.host.AllowAccess(tab_index, windex)
-
- def StartMe2Me(self, tab_index=1, windex=0):
- """Starts Me2Me. """
- self._ExecuteJavascript(
- 'document.getElementById("get-started-me2me").click();',
- tab_index, windex)
- self.assertTrue(
- self._WaitForJavascriptCondition(
- 'document.getElementById("me2me-content").hidden == false',
- tab_index, windex),
- msg='No me2me content')
-
- def Share(self, tab_index=1, windex=0):
- """Generates an access code and waits for incoming connections.
-
- Returns:
- The access code on success; None otherwise.
- """
- self._ExecuteAndWaitForMode(
- 'remoting.tryShare();',
- 'HOST_WAITING_FOR_CONNECTION', tab_index, windex)
- return self.GetDOMValue(
- 'document.getElementById("access-code-display").innerText',
- tab_index, windex)
-
- def CancelShare(self, tab_index=1, windex=0):
- """Stops sharing the desktop on the host side."""
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'remoting.cancelShare();',
- 'HOST_SHARE_FINISHED', tab_index, windex),
- msg='Stopping sharing from the host side failed')
-
- def CleanupHostList(self, tab_index=1, windex=0):
- """Removes hosts due to failure on previous stop-daemon"""
- self.EnableConnectionsInstalled()
- this_host_name = self.GetDOMValue(
- 'document.getElementById("this-host-name").textContent',
- tab_index, windex)
- if this_host_name.endswith(' (offline)'):
- this_host_name = this_host_name[:-10]
- self.DisableConnections()
-
- total_hosts = self.GetDOMValue(
- 'document.getElementById("host-list").childNodes.length',
- tab_index, windex)
-
- # Start from the end while deleting bogus hosts
- index = total_hosts
- while index > 0:
- index -= 1
- try:
- hostname = self.GetDOMValue(
- 'document.getElementById("host-list")'
- '.childNodes[%s].textContent' % index,
- tab_index, windex)
- if hostname == this_host_name or \
- hostname == this_host_name + ' (offline)':
- self._ExecuteJavascript(
- 'document.getElementById("host-list")'
- '.childNodes[%s].childNodes[3].click()' % index,
- tab_index, windex)
- self._ExecuteJavascript(
- 'document.getElementById("confirm-host-delete").click()',
- tab_index, windex)
- except JSONInterfaceError:
- print 'Ignore the error on deleting host'
-
- if self._WaitForJavascriptCondition(
- 'document.getElementById("this-host-connect")'
- '.getAttribute("data-daemon-state") == "enabled"',
- tab_index, windex, 1):
- self.DisableConnections()
-
- def EnableConnectionsInstalled(self, pin_exercise=False,
- tab_index=1, windex=0):
- """Enables the remote connections on the host side."""
- if sys.platform.startswith('darwin'):
- subprocess.call([self._GetHelperRunner(), self._GetHelper(), 'enable'])
-
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'document.getElementById("start-daemon").click();',
- 'HOST_SETUP_ASK_PIN', tab_index, windex),
- msg='Cannot start host setup')
- self.assertTrue(
- self._WaitForJavascriptCondition(
- 'document.getElementById("ask-pin-form").hidden == false',
- tab_index, windex),
- msg='No ask pin dialog')
-
- if pin_exercise:
- # Cancels the pin prompt
- self._ExecuteJavascript(
- 'document.getElementById("daemon-pin-cancel").click();',
- tab_index, windex)
-
- # Enables again
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'document.getElementById("start-daemon").click();',
- 'HOST_SETUP_ASK_PIN', tab_index, windex),
- msg='Cannot start host setup')
-
- # Click ok without typing in pins
- self._ExecuteJavascript(
- 'document.getElementById("daemon-pin-ok").click();',
- tab_index, windex)
- self.assertTrue(
- self._WaitForJavascriptCondition(
- 'document.getElementById("daemon-pin-error-message")',
- tab_index, windex),
- msg='No pin error message')
-
- # Mis-matching pins
- self._ExecuteJavascript(
- 'document.getElementById("daemon-pin-entry").value = "111111";',
- tab_index, windex)
- self._ExecuteJavascript(
- 'document.getElementById("daemon-pin-confirm").value = "123456";',
- tab_index, windex)
- self.assertTrue(
- self._WaitForJavascriptCondition(
- 'document.getElementById("daemon-pin-error-message")',
- tab_index, windex),
- msg='No pin error message')
-
- # Types in correct pins
- self._ExecuteJavascript(
- 'document.getElementById("daemon-pin-entry").value = "111111";',
- tab_index, windex)
- self._ExecuteJavascript(
- 'document.getElementById("daemon-pin-confirm").value = "111111";',
- tab_index, windex)
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'document.getElementById("daemon-pin-ok").click();',
- 'HOST_SETUP_PROCESSING', tab_index, windex),
- msg='Host setup was not started')
-
- # Handles preference panes
- self.assertTrue(
- self._WaitForJavascriptCondition(
- 'remoting.currentMode == remoting.AppMode.HOST_SETUP_DONE',
- tab_index, windex),
- msg='Host setup was not done')
-
- # Dismisses the host config done dialog
- self.assertTrue(
- self._WaitForJavascriptCondition(
- 'document.getElementById("host-setup-dialog")'
- '.childNodes[5].hidden == false',
- tab_index, windex),
- msg='No host setup done dialog')
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'document.getElementById("host-config-done-dismiss").click();',
- 'HOME', tab_index, windex),
- msg='Failed to dismiss host setup confirmation dialog')
-
- def EnableConnectionsUninstalledAndCancel(self, tab_index=1, windex=0):
- """Enables remote connections while host is not installed yet."""
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'document.getElementById("start-daemon").click();',
- 'HOST_SETUP_INSTALL', tab_index, windex),
- msg='Cannot start host install')
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'document.getElementById("host-config-install-dismiss").click();',
- 'HOME', tab_index, windex),
- msg='Failed to dismiss host install dialog')
-
- def DisableConnections(self, tab_index=1, windex=0):
- """Disables the remote connections on the host side."""
- if sys.platform.startswith('darwin'):
- subprocess.call([self._GetHelperRunner(), self._GetHelper(), 'disable'])
-
- # Re-try to make disabling connection more stable
- for _ in range (1, 4):
- self._ExecuteJavascript(
- 'document.getElementById("stop-daemon").click();',
- tab_index, windex)
-
- # Immediately waiting for host-setup-dialog hidden sometimes times out
- # even though visually it is hidden. Add some sleep here
- time.sleep(2)
-
- if self._WaitForJavascriptCondition(
- 'document.getElementById("host-setup-dialog")'
- '.childNodes[3].hidden == true',
- tab_index, windex, 1):
- break;
-
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'document.getElementById("host-config-done-dismiss").click();',
- 'HOME', tab_index, windex),
- msg='Failed to dismiss host setup confirmation dialog')
-
- def Connect(self, access_code, tab_index=1, windex=0):
- """Connects to a Chromoting host and starts the session."""
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'document.getElementById("access-code-entry").value = "%s";'
- 'remoting.connectIt2Me();' % access_code,
- 'IN_SESSION', tab_index, windex),
- msg='Cannot connect it2me session')
-
- def ChangePin(self, pin='222222', tab_index=1, windex=0):
- """Changes pin for enabled host."""
- if sys.platform.startswith('darwin'):
- subprocess.call([self._GetHelperRunner(), self._GetHelper(), 'changepin'])
-
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'document.getElementById("change-daemon-pin").click();',
- 'HOST_SETUP_ASK_PIN', tab_index, windex),
- msg='Cannot change daemon pin')
- self.assertTrue(
- self._WaitForJavascriptCondition(
- 'document.getElementById("ask-pin-form").hidden == false',
- tab_index, windex),
- msg='No ask pin dialog')
-
- self._ExecuteJavascript(
- 'document.getElementById("daemon-pin-entry").value = "' + pin + '";',
- tab_index, windex)
- self._ExecuteJavascript(
- 'document.getElementById("daemon-pin-confirm").value = "' +
- pin + '";', tab_index, windex)
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'document.getElementById("daemon-pin-ok").click();',
- 'HOST_SETUP_PROCESSING', tab_index, windex),
- msg='Host setup was not started')
-
- # Handles preference panes
- self.assertTrue(
- self._WaitForJavascriptCondition(
- 'remoting.currentMode == remoting.AppMode.HOST_SETUP_DONE',
- tab_index, windex),
- msg='Host setup was not done')
-
- # Dismisses the host config done dialog
- self.assertTrue(
- self._WaitForJavascriptCondition(
- 'document.getElementById("host-setup-dialog")'
- '.childNodes[5].hidden == false',
- tab_index, windex),
- msg='No host setup done dialog')
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'document.getElementById("host-config-done-dismiss").click();',
- 'HOME', tab_index, windex),
- msg='Failed to dismiss host setup confirmation dialog')
-
- def ChangeName(self, new_name='Changed', tab_index=1, windex=0):
- """Changes the host name."""
- self._ExecuteJavascript(
- 'document.getElementById("this-host-rename").click();',
- tab_index, windex)
- self._ExecuteJavascript(
- 'document.getElementById("this-host-name").childNodes[0].value = "' +
- new_name + '";', tab_index, windex)
- self._ExecuteJavascript(
- 'document.getElementById("this-host-rename").click();',
- tab_index, windex)
-
- def ConnectMe2Me(self, pin='111111', mode='IN_SESSION',
- tab_index=1, windex=0):
- """Connects to a Chromoting host and starts the session."""
-
- # There is delay from the enabling remote connections to the host
- # showing up in the host list. We need to reload the web app to get
- # the host to show up. We will repeat this a few times to make sure
- # eventually host appears.
- for _ in range(1, 13):
- self._ExecuteJavascript(
- 'window.location.reload();',
- tab_index, windex)
-
- # pyauto _GetResultFromJSONRequest throws JSONInterfaceError after
- # 45 seconds if ExecuteJavascript is called right after reload.
- # Waiting 2s here can avoid this. So instead of getting the error and
- # wait 45s, we wait 2s here. If the error still happens, the following
- # retry will handle that.
- time.sleep(2)
-
- # If this-host-connect is still not enabled, let's retry one more time.
- this_host_connect_enabled = False
- for _ in range(1, 3):
- daemon_state_enabled = self._WaitForJavascriptCondition(
- 'document.getElementById("this-host-connect")'
- '.getAttribute("data-daemon-state") == "enabled"',
- tab_index, windex, 1)
- host_online = self._WaitForJavascriptCondition(
- 'document.getElementById("this-host-name")'
- '.textContent.toString().indexOf("offline") == -1',
- tab_index, windex, 1)
- this_host_connect_enabled = daemon_state_enabled and host_online
- if this_host_connect_enabled:
- break
- if this_host_connect_enabled:
- break;
-
- # Clicking this-host-connect does work right after this-host-connect
- # is enabled. Need to retry.
- for _ in range(1, 4):
- self._ExecuteJavascript(
- 'document.getElementById("this-host-connect").click();',
- tab_index, windex)
-
- # pyauto _GetResultFromJSONRequest throws JSONInterfaceError after
- # a long time out if WaitUntil is called right after click.
- # Waiting 2s here can avoid this.
- time.sleep(2)
-
- # If cannot detect that pin-form appears, retry one more time.
- pin_form_exposed = False
- for _ in range(1, 3):
- pin_form_exposed = self._WaitForJavascriptCondition(
- 'document.getElementById("client-dialog")'
- '.childNodes[9].hidden == false',
- tab_index, windex, 1)
- if pin_form_exposed:
- break
-
- if pin_form_exposed:
- break
-
- # Dismiss connect failure dialog before retry
- if self._WaitForJavascriptCondition(
- 'document.getElementById("client-dialog")'
- '.childNodes[25].hidden == false',
- tab_index, windex, 1):
- self._ExecuteJavascript(
- 'document.getElementById("client-finished-me2me-button")'
- '.click();',
- tab_index, windex)
-
- self._ExecuteJavascript(
- 'document.getElementById("pin-entry").value = "' + pin + '";',
- tab_index, windex)
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'document.getElementById("pin-form").childNodes[5].click();',
- mode, tab_index, windex),
- msg='Session was not started')
-
- def Disconnect(self, tab_index=1, windex=0):
- """Disconnects from the Chromoting it2me session on the client side."""
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'remoting.disconnect();',
- 'CLIENT_SESSION_FINISHED_IT2ME', tab_index, windex),
- msg='Disconnecting it2me session from the client side failed')
-
- def DisconnectMe2Me(self, confirmation=True, tab_index=1, windex=0):
- """Disconnects from the Chromoting me2me session on the client side."""
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'remoting.disconnect();',
- 'CLIENT_SESSION_FINISHED_ME2ME', tab_index, windex),
- msg='Disconnecting me2me session from the client side failed')
-
- if confirmation:
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'document.getElementById("client-finished-me2me-button")'
- '.click();', 'HOME', tab_index, windex),
- msg='Failed to dismiss session finished dialog')
-
- def ReconnectMe2Me(self, pin='111111', tab_index=1, windex=0):
- """Reconnects the me2me session."""
- self._ExecuteJavascript(
- 'document.getElementById("client-reconnect-button").click();',
- tab_index, windex)
-
- # pyauto _GetResultFromJSONRequest throws JSONInterfaceError after
- # a long time out if WaitUntil is called right after click.
- time.sleep(2)
-
- # If cannot detect that pin-form appears, retry one more time.
- for _ in range(1, 3):
- pin_form_exposed = self._WaitForJavascriptCondition(
- 'document.getElementById("client-dialog")'
- '.childNodes[9].hidden == false',
- tab_index, windex, 1)
- if pin_form_exposed:
- break
-
- self._ExecuteJavascript(
- 'document.getElementById("pin-entry").value = "' + pin + '";',
- tab_index, windex)
- self.assertTrue(
- self._ExecuteAndWaitForMode(
- 'document.getElementById("pin-form").childNodes[5].click();',
- 'IN_SESSION', tab_index, windex),
- msg='Session was not started when reconnecting')
diff --git a/chrome/test/pyautolib/dom_mutation_observer.js b/chrome/test/pyautolib/dom_mutation_observer.js
deleted file mode 100644
index ced5ec3..0000000
--- a/chrome/test/pyautolib/dom_mutation_observer.js
+++ /dev/null
@@ -1,276 +0,0 @@
-/* Copyright (c) 2012 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.
- *
- * Helper javascript injected whenever a DomMutationEventObserver is created.
- *
- * This script uses MutationObservers to watch for changes to the DOM, then
- * reports the event to the observer using the DomAutomationController. An
- * anonymous namespace is used to prevent conflict with other Javascript.
- *
- * Args:
- * automation_id: Automation id used to route DomAutomationController messages.
- * observer_id: Id of the observer who will be receiving the messages.
- * observer_type: One of 'add', 'remove', 'change', or 'exists'.
- * xpath: XPath used to specify the DOM node of interest.
- * attribute: If |expected_value| is provided, check if this attribute of the
- * DOM node matches |expected value|.
- * expected_value: If not null, regular expression to match with the value of
- * |attribute| after the mutation.
- */
-function(automation_id, observer_id, observer_type, xpath, attribute,
- expected_value) {
-
- /* Raise an event for the DomMutationEventObserver. */
- function raiseEvent() {
- if (window.domAutomationController) {
- console.log("Event sent to DomEventObserver with id=" +
- observer_id + ".");
- window.domAutomationController.sendWithId(
- automation_id, "__dom_mutation_observer__:" + observer_id);
- }
- }
-
- /* Calls raiseEvent if the expected node has been added to the DOM.
- *
- * Args:
- * mutations: A list of mutation objects.
- * observer: The mutation observer object associated with this callback.
- */
- function addNodeCallback(mutations, observer) {
- for (var j=0; j<mutations.length; j++) {
- for (var i=0; i<mutations[j].addedNodes.length; i++) {
- var node = mutations[j].addedNodes[i];
- if (xpathMatchesNode(node, xpath) &&
- nodeAttributeValueEquals(node, attribute, expected_value)) {
- raiseEvent();
- observer.disconnect();
- delete observer;
- return;
- }
- }
- }
- }
-
- /* Calls raiseEvent if the expected node has been removed from the DOM.
- *
- * Args:
- * mutations: A list of mutation objects.
- * observer: The mutation observer object associated with this callback.
- */
- function removeNodeCallback(mutations, observer) {
- var node = firstXPathNode(xpath);
- if (!node) {
- raiseEvent();
- observer.disconnect();
- delete observer;
- }
- }
-
- /* Calls raiseEvent if the given node has been changed to expected_value.
- *
- * Args:
- * mutations: A list of mutation objects.
- * observer: The mutation observer object associated with this callback.
- */
- function changeNodeCallback(mutations, observer) {
- for (var j=0; j<mutations.length; j++) {
- if (nodeAttributeValueEquals(mutations[j].target, attribute,
- expected_value)) {
- raiseEvent();
- observer.disconnect();
- delete observer;
- return;
- }
- }
- }
-
- /* Calls raiseEvent if the expected node exists in the DOM.
- *
- * Args:
- * mutations: A list of mutation objects.
- * observer: The mutation observer object associated with this callback.
- */
- function existsNodeCallback(mutations, observer) {
- if (findNodeMatchingXPathAndValue(xpath, attribute, expected_value)) {
- raiseEvent();
- observer.disconnect();
- delete observer;
- return;
- }
- }
-
- /* Return true if the xpath matches the given node.
- *
- * Args:
- * node: A node object from the DOM.
- * xpath: An XPath used to compare with the DOM node.
- */
- function xpathMatchesNode(node, xpath) {
- var con = document.evaluate(xpath, document, null,
- XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
- var thisNode = con.iterateNext();
- while (thisNode) {
- if (node == thisNode) {
- return true;
- }
- thisNode = con.iterateNext();
- }
- return false;
- }
-
- /* Returns the first node in the DOM that matches the xpath.
- *
- * Args:
- * xpath: XPath used to specify the DOM node of interest.
- */
- function firstXPathNode(xpath) {
- return document.evaluate(xpath, document, null,
- XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
- }
-
- /* Returns the first node in the DOM that matches the xpath.
- *
- * Args:
- * xpath: XPath used to specify the DOM node of interest.
- * attribute: The attribute to match |expected_value| against.
- * expected_value: A regular expression to match with the node's
- * |attribute|. If null the match always succeeds.
- */
- function findNodeMatchingXPathAndValue(xpath, attribute, expected_value) {
- var nodes = document.evaluate(xpath, document, null,
- XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
- var node;
- while ( (node = nodes.iterateNext()) ) {
- if (nodeAttributeValueEquals(node, attribute, expected_value))
- return node;
- }
- return null;
- }
-
- /* Returns true if the node's |attribute| value is matched by the regular
- * expression |expected_value|, false otherwise.
- *
- * Args:
- * node: A node object from the DOM.
- * attribute: The attribute to match |expected_value| against.
- * expected_value: A regular expression to match with the node's
- * |attribute|. If null the test always passes.
- */
- function nodeAttributeValueEquals(node, attribute, expected_value) {
- return expected_value == null ||
- (node[attribute] && RegExp(expected_value, "").test(node[attribute]));
- }
-
- /* Watch for a node matching xpath to be added to the DOM.
- *
- * Args:
- * xpath: XPath used to specify the DOM node of interest.
- */
- function observeAdd(xpath) {
- window.domAutomationController.send("success");
- if (findNodeMatchingXPathAndValue(xpath, attribute, expected_value)) {
- raiseEvent();
- console.log("Matching node in DOM, assuming it was previously added.");
- return;
- }
-
- var obs = new MutationObserver(addNodeCallback);
- obs.observe(document,
- { childList: true,
- attributes: true,
- characterData: true,
- subtree: true});
- }
-
- /* Watch for a node matching xpath to be removed from the DOM.
- *
- * Args:
- * xpath: XPath used to specify the DOM node of interest.
- */
- function observeRemove(xpath) {
- window.domAutomationController.send("success");
- if (!firstXPathNode(xpath)) {
- raiseEvent();
- console.log("No matching node in DOM, assuming it was already removed.");
- return;
- }
-
- var obs = new MutationObserver(removeNodeCallback);
- obs.observe(document,
- { childList: true,
- attributes: true,
- subtree: true});
- }
-
- /* Watch for the textContent of a node matching xpath to change to
- * expected_value.
- *
- * Args:
- * xpath: XPath used to specify the DOM node of interest.
- */
- function observeChange(xpath) {
- var node = firstXPathNode(xpath);
- if (!node) {
- console.log("No matching node in DOM.");
- window.domAutomationController.send(
- "No DOM node matching xpath exists.");
- return;
- }
- window.domAutomationController.send("success");
-
- var obs = new MutationObserver(changeNodeCallback);
- obs.observe(node,
- { childList: true,
- attributes: true,
- characterData: true,
- subtree: true});
- }
-
- /* Watch for a node matching xpath to exist in the DOM.
- *
- * Args:
- * xpath: XPath used to specify the DOM node of interest.
- */
- function observeExists(xpath) {
- window.domAutomationController.send("success");
- if (findNodeMatchingXPathAndValue(xpath, attribute, expected_value)) {
- raiseEvent();
- console.log("Node already exists in DOM.");
- return;
- }
-
- var obs = new MutationObserver(existsNodeCallback);
- obs.observe(document,
- { childList: true,
- attributes: true,
- characterData: true,
- subtree: true});
- }
-
- /* Interpret arguments and launch the requested observer function. */
- function installMutationObserver() {
- switch (observer_type) {
- case "add":
- observeAdd(xpath);
- break;
- case "remove":
- observeRemove(xpath);
- break;
- case "change":
- observeChange(xpath);
- break;
- case "exists":
- observeExists(xpath);
- break;
- }
- console.log("MutationObserver javscript injection completed.");
- }
-
- /* Ensure the DOM is loaded before attempting to create MutationObservers. */
- if (document.body) {
- installMutationObserver();
- } else {
- window.addEventListener("DOMContentLoaded", installMutationObserver, true);
- }
-}
diff --git a/chrome/test/pyautolib/download_info.py b/chrome/test/pyautolib/download_info.py
deleted file mode 100644
index 44d5705..0000000
--- a/chrome/test/pyautolib/download_info.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# Copyright (c) 2011 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.
-
-"""DownloadInfo: python representation for downloads visible to Chrome.
-
-Obtain one of these from PyUITestSuite::GetDownloadsInfo() call.
-
-class MyDownloadsTest(pyauto.PyUITest):
- def testDownload(self):
- self.DownloadAndWaitForStart('http://my.url/package.zip')
- self.WaitForAllDownloadsToComplete()
- info = self.GetDownloadsInfo()
- print info.Downloads()
- self.assertEqual(info.Downloads()[0]['file_name'], 'packge.zip')
-
-See more tests in chrome/test/functional/downloads.py.
-"""
-
-import os
-import simplejson as json
-import sys
-
-from pyauto_errors import JSONInterfaceError
-
-
-class DownloadInfo(object):
- """Represent info about Downloads.
-
- The info is represented as a list of DownloadItems. Each DownloadItem is a
- dictionary with various attributes about a download, like id, file_name,
- path, state, and so on.
- """
- def __init__(self, downloads_dict):
- """Initialize a DownloadInfo from a string of json.
-
- Args:
- downloads_dict: a dict returned by the IPC command 'GetDownloadsInfo'.
- A typical dict representing one download looks like:
- {'downloads': [{'url': 'http://blah/a_file.zip',
- 'file_name': 'a_file.zip',
- 'state': 'COMPLETED',
- ...,
- ..., } ] }
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- # JSON string prepared in GetDownloadsInfo() in automation_provider.cc
- self.downloadsdict = downloads_dict
- if self.downloadsdict.has_key('error'):
- raise JSONInterfaceError(self.downloadsdict['error'])
-
- def Downloads(self):
- """Info about all downloads.
-
- This includes downloads in all states (COMPLETE, IN_PROGRESS, ...).
-
- Returns:
- [downloaditem1, downloaditem2, ...]
- """
- return self.downloadsdict.get('downloads', [])
-
- def DownloadsInProgress(self):
- """Info about all downloads in progress.
-
- Returns:
- [downloaditem1, downloaditem2, ...]
- """
- return [x for x in self.Downloads() if x['state'] == 'IN_PROGRESS']
-
- def DownloadsComplete(self):
- """Info about all downloads that have completed.
-
- Returns:
- [downloaditem1, downloaditem2, ...]
- """
- return [x for x in self.Downloads() if x['state'] == 'COMPLETE']
diff --git a/chrome/test/pyautolib/fetch_prebuilt_pyauto.py b/chrome/test/pyautolib/fetch_prebuilt_pyauto.py
deleted file mode 100755
index 963b98f..0000000
--- a/chrome/test/pyautolib/fetch_prebuilt_pyauto.py
+++ /dev/null
@@ -1,214 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Fetch prebuilt binaries to run PyAuto.
-
-Sets up Chrome and PyAuto binaries using prebuilt binaries from the
-continuous build archives. Works on mac, win, linux (32 & 64 bit).
-
-Examples:
- On Mac:
- $ python fetch_prebuilt_pyauto.py -d xcodebuild/Release
- http://build.chromium.org/f/chromium/continuous/mac/LATEST
-
- On Win:
- $ python fetch_prebuilt_pyauto.py -d chrome\Release
- http://build.chromium.org/f/chromium/continuous/win/LATEST
-"""
-
-import glob
-import httplib
-import optparse
-import os
-import platform
-import shutil
-import sys
-import urllib
-import urllib2
-import urlparse
-
-import pyauto_utils
-
-
-class FetchPrebuilt(object):
- """Util class to fetch prebuilt binaries to run PyAuto."""
-
- def _ParseArgs(self):
- parser = optparse.OptionParser()
- parser.add_option(
- '-d', '--outdir', type='string', default=None,
- help='Directory in which to setup. This is typically the directory '
- 'where the binaries would go when compiled from source.')
- parser.add_option(
- '-p', '--platform', type='string',
- default=pyauto_utils.GetCurrentPlatform(),
- help='Platform. Valid options: win, mac, linux32, linux64. '
- 'Default: current platform (%s)' % pyauto_utils.GetCurrentPlatform())
- parser.add_option(
- '-l', '--latest', action='store_true', default=False,
- help='Download the latest chromium build from commondatastorage. '
- '[default=False]')
- self._options, self._args = parser.parse_args()
- if self._options.latest:
- self._url = self._GetLastestDownloadURL(self._options.platform)
- elif not self._args:
- print >>sys.stderr, 'Need download url'
- sys.exit(2)
- else:
- self._url = self._args[0]
- if not self._options.outdir:
- print >>sys.stderr, 'Need output directory: -d/--outdir'
- sys.exit(1)
- self._outdir = self._options.outdir
- # Chromium continuous build archive has a non-standard format.
- if 'index.html?path=' in self._url:
- self._url = self._url.replace('index.html?path=', '')
- self._url = self._url.rstrip('/')
- # Determine name of zip.
- if not self._options.platform.startswith('linux'):
- self._chrome_zip_name = 'chrome-%s' % {'mac': 'mac',
- 'win': 'win32'
- }[self._options.platform]
- else:
- linux_32_names = ['linux', 'lucid32bit']
- linux_64_names = ['linux64', 'lucid64bit']
- linux_names = {'linux': linux_32_names + linux_64_names,
- 'linux32': linux_32_names,
- 'linux64': linux_64_names
- }[self._options.platform]
- for name in linux_names:
- zip_name = 'chrome-' + name
- if pyauto_utils.DoesUrlExist('%s/%s.zip' % (self._url, zip_name)):
- self._chrome_zip_name = zip_name
- break
- else:
- raise RuntimeError('Could not find chrome zip at ' + self._url)
-
- # Setup urls to download.
- self._chrome_zip_url = '%s/%s.zip' % (self._url, self._chrome_zip_name)
- self._remoting_zip_url = self._url + '/' + 'remoting-webapp.zip'
- chrome_test_url = '%s/%s.test' % (self._url, self._chrome_zip_name)
- self._pyautolib_py_url = '%s/pyautolib.py' % chrome_test_url
- if self._options.platform == 'win':
- self._pyautolib_so_name = '_pyautolib.pyd'
- self._chromedriver_name = 'chromedriver.exe'
- else:
- self._pyautolib_so_name = '_pyautolib.so'
- self._chromedriver_name = 'chromedriver'
- if self._options.platform == 'mac':
- self._ffmpegsumo_so_name = 'ffmpegsumo.so'
- self._ffmpegsumo_so_url = chrome_test_url + '/' + self._ffmpegsumo_so_name
- self._pyautolib_so_url = chrome_test_url + '/' + self._pyautolib_so_name
- self._chromedriver_url = chrome_test_url + '/' + self._chromedriver_name
-
- def _GetLastestDownloadURL(self, os_platform):
- os_type = {'win': 'Win',
- 'mac': 'Mac',
- 'linux': 'Linux',
- 'linux32': 'Linux',
- 'linux64': 'Linux_x64'}[os_platform]
- if os_type == 'Linux' and platform.architecture()[0] == '64bit':
- os_type = 'Linux_x64'
- last_change_url = ('http://commondatastorage.googleapis.com/'
- 'chromium-browser-continuous/%s/LAST_CHANGE' % os_type)
- response = urllib2.urlopen(last_change_url)
- last_change = response.read()
- if not last_change:
- print >>sys.stderr, ('Unable to get latest from %s' % last_change_url)
- sys.exit(2)
- last_change_url = ('http://commondatastorage.googleapis.com/'
- 'chromium-browser-continuous/%s/%s' % (os_type,
- last_change))
- return last_change_url
-
- def Cleanup(self):
- """Remove old binaries, if any."""
- pass
-
- def Run(self):
- self._ParseArgs()
- if not os.path.isdir(self._outdir):
- os.makedirs(self._outdir)
- get_remoting = pyauto_utils.DoesUrlExist(self._remoting_zip_url)
-
- # Fetch chrome & pyauto binaries
- print 'Fetching', self._chrome_zip_url
- chrome_zip = urllib.urlretrieve(self._chrome_zip_url)[0]
-
- if get_remoting:
- print 'Fetching', self._remoting_zip_url
- remoting_zip = urllib.urlretrieve(self._remoting_zip_url)[0]
- else:
- print 'Warning: %s does not exist.' % self._remoting_zip_url
-
- print 'Fetching', self._pyautolib_py_url
- pyautolib_py = urllib.urlretrieve(self._pyautolib_py_url)[0]
-
- print 'Fetching', self._pyautolib_so_url
- pyautolib_so = urllib.urlretrieve(self._pyautolib_so_url)[0]
-
- if self._options.platform == 'mac':
- print 'Fetching', self._ffmpegsumo_so_url
- ffmpegsumo_so = urllib.urlretrieve(self._ffmpegsumo_so_url)[0]
-
- print 'Fetching', self._chromedriver_url
- chromedriver = urllib.urlretrieve(self._chromedriver_url)[0]
-
- chrome_unzip_dir = os.path.join(self._outdir, self._chrome_zip_name)
- if os.path.exists(chrome_unzip_dir):
- print 'Cleaning', chrome_unzip_dir
- pyauto_utils.RemovePath(chrome_unzip_dir)
- print 'Unzipping'
- pyauto_utils.UnzipFilenameToDir(chrome_zip, self._outdir)
- if get_remoting:
- pyauto_utils.UnzipFilenameToDir(remoting_zip, self._outdir)
- shutil.move(self._outdir + '/remoting-webapp',
- self._outdir + '/remoting/remoting.webapp')
-
- # Copy over the binaries to outdir
- items_to_copy = {
- pyautolib_py: os.path.join(self._outdir, 'pyautolib.py'),
- pyautolib_so: os.path.join(self._outdir, self._pyautolib_so_name),
- chromedriver: os.path.join(self._outdir, self._chromedriver_name)
- }
- if self._options.platform == 'mac':
- items_to_copy[ffmpegsumo_so] = \
- os.path.join(self._outdir, self._ffmpegsumo_so_name)
-
- unzip_dir_contents = glob.glob(os.path.join(chrome_unzip_dir, '*'))
- for item in unzip_dir_contents:
- name = os.path.basename(item)
- items_to_copy[item] = os.path.join(self._outdir, name)
-
- for src, dest in items_to_copy.iteritems():
- pyauto_utils.RemovePath(dest)
- print '%s ==> %s' % (os.path.basename(src), dest)
- shutil.move(src, dest)
- pyauto_utils.RemovePath(chrome_unzip_dir)
-
- # Final setup (if any)
- # Set executable bit on chromedriver binary.
- if not self._options.platform == 'win':
- os.chmod(items_to_copy[chromedriver], 0700)
-
- # Create symlink to .framework on Mac
- if self._options.platform == 'mac':
- mac_app_name = os.path.basename([x for x in unzip_dir_contents
- if x.endswith('.app')][0])
- os.chdir(self._outdir)
- framework = glob.glob(os.path.join(
- mac_app_name, 'Contents', 'Versions', '*', '*.framework'))[0]
- print framework
- dest = os.path.basename(framework)
- os.path.lexists(dest) and os.remove(dest)
- print 'Creating symlink "%s"' % dest
- os.symlink(framework, dest)
-
- print 'Prepared binaries in "%s"' % self._outdir
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(FetchPrebuilt().Run())
diff --git a/chrome/test/pyautolib/generate_docs.py b/chrome/test/pyautolib/generate_docs.py
deleted file mode 100755
index a603ad8..0000000
--- a/chrome/test/pyautolib/generate_docs.py
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import optparse
-import os
-import pydoc
-import shutil
-import sys
-
-
-def main():
- parser = optparse.OptionParser()
- parser.add_option('-w', '--write', dest='dir', metavar='FILE',
- default=os.path.join(os.getcwd(), 'pyauto_docs'),
- help=('Directory path to write all of the documentation. '
- 'Defaults to "pyauto_docs" in current directory.'))
- parser.add_option('-p', '--pyautolib', dest='pyautolib', metavar='FILE',
- default=os.getcwd(),
- help='Location of pyautolib directory')
- (options, args) = parser.parse_args()
-
- if not os.path.isdir(options.dir):
- os.makedirs(options.dir)
-
- # Add these paths so pydoc can find everything
- sys.path.append(os.path.join(options.pyautolib,
- '../../../third_party/'))
- sys.path.append(options.pyautolib)
-
- # Get a snapshot of the current directory where pydoc will export the files
- previous_contents = set(os.listdir(os.getcwd()))
- pydoc.writedocs(options.pyautolib)
- current_contents = set(os.listdir(os.getcwd()))
-
- if options.dir == os.getcwd():
- print 'Export complete, files are located in %s' % options.dir
- return 1
-
- new_files = current_contents.difference(previous_contents)
- for file_name in new_files:
- basename, extension = os.path.splitext(file_name)
- if extension == '.html':
- # Build the complete path
- full_path = os.path.join(os.getcwd(), file_name)
- existing_file_path = os.path.join(options.dir, file_name)
- if os.path.isfile(existing_file_path):
- os.remove(existing_file_path)
- shutil.move(full_path, options.dir)
-
- print 'Export complete, files are located in %s' % options.dir
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/chrome/test/pyautolib/history_info.py b/chrome/test/pyautolib/history_info.py
deleted file mode 100644
index f8e05b3..0000000
--- a/chrome/test/pyautolib/history_info.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# Copyright (c) 2011 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.
-
-"""History: python representation for history.
-
-Obtain one of these from PyUITestSuite::GetHistoryInfo() call.
-
-Example:
-class MyTest(pyauto.PyUITest):
- def testBasic(self):
- url = 'http://www.google.com/'
- self.NavigateToURL(url)
- history = self.GetHistoryInfo()
- self.assertEqual(1, len(history))
- self.assertEqual(url, history[0]['url'])
-
-See more tests in chrome/test/functional/history.py.
-"""
-
-import simplejson as json
-
-from pyauto_errors import JSONInterfaceError
-
-
-class HistoryInfo(object):
- """Represent info about browsing history.
-
- The info is represented as a list of history items containing url, title,
- time, etc.
- """
- def __init__(self, history_dict):
- """Initialize a HistoryInfo from a string of json.
-
- Args:
- json_string: a dictionary as returned by the IPC command 'GetHistoryInfo'.
- A typical dict representing history info looks like:
- {'history': [
- {'url': 'http://www.google.com/',
- 'title': 'Google',
- ...,
- ...,
- }, ] }
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- # JSON string prepared in GetHistoryInfo() in automation_provider.cc
- self.historydict = history_dict
-
- def History(self):
- """Get history list.
-
- History is ordered latest first, that is in the same order as
- chrome://history/ would list.
-
- Example:
- [ { u'snippet': u'',
- u'starred': False,
- u'time': 1271781612,
- u'title': u'Google News',
- u'url': u'http://news.google.com/'},
- { u'snippet': u'',
- u'starred': True,
- u'time': 1271781602,
- u'title': u'Google',
- u'url': u'http://www.google.com/'}]
-
- The snippet attribute will be empty in most cases. If GetHistoryInfo() is
- provided a non-empty search_text arg, the snippet attribute will contain the
- snippet as it would be visible when searching for that text in the
- chrome://history/ UI.
-
- Returns:
- [item1, item2, ...]
- """
- return self.historydict.get('history', [])
diff --git a/chrome/test/pyautolib/mock_pref_pane.py b/chrome/test/pyautolib/mock_pref_pane.py
deleted file mode 100644
index cbb3a48..0000000
--- a/chrome/test/pyautolib/mock_pref_pane.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# Copyright (c) 2012 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.
-
-"""Mock pref pane for testing purpose on Mac."""
-
-import Foundation
-import os
-import signal
-import subprocess
-import sys
-import tempfile
-import time
-
-
-class MockPrefPane(object):
- """Mock Pref Pane to enable/disable/changepin without system prompt.
-
- This only applies to Mac.
- """
-
- def __init__(self):
- self._service_name = 'org.chromium.chromoting'
- self._real_user_id = os.getuid()
- self._config_file = os.path.join(tempfile.gettempdir(),
- '%s.json' % self._service_name)
- self._tool_script = '/Library/PrivilegedHelperTools/%s.me2me.sh' % \
- self._service_name
-
- def _GetJobPid(self):
- """Gets the org.chromium.chromoting job id."""
- process = subprocess.Popen(['launchctl', 'list'], stdout=subprocess.PIPE)
- pid = None
- for line in process.stdout:
- # Format is:
- # 12345 - my.job (if my.job is running, number is job's PID)
- # - 0 my.other.job (if my.other.job is not running)
- fields = line.strip().split('\t')
- if fields[2] == self._service_name and fields[0] != "-":
- pid = fields[0]
- break
- process.wait()
- return pid
-
- def Enable(self):
- """Handles what pref pane does for enabling connection."""
- # Elevate privileges, otherwise tool_script executes with EUID != 0.
- os.setuid(0)
- subprocess.call([self._tool_script, '--enable'],
- stdin=open(self._config_file))
-
- # Drop privileges, start the launchd job as the logged-in user.
- os.setuid(self._real_user_id)
- subprocess.call(['launchctl', 'start', self._service_name])
-
- # Starting a launchd job is an asynchronous operation that typically takes
- # a couple of seconds, so poll until the job has started.
- for _ in range(1, 10):
- if self._GetJobPid():
- print '*** org.chromium.chromoting is running ***'
- break
- time.sleep(2)
-
- def Disable(self):
- """Handles what pref pane does for disabling connection."""
- # Elevate privileges, otherwise tool_script executes with EUID != 0.
- os.setuid(0)
- subprocess.call([self._tool_script, '--disable'],
- stdin=open(self._config_file))
-
- # Drop privileges, stop the launchd job as the logged-in user.
- os.setuid(self._real_user_id)
- subprocess.call(['launchctl', 'stop', self._service_name])
-
- # Stopping a launchd job is an asynchronous operation that typically takes
- # a couple of seconds, so poll until the job has stopped.
- for _ in range(1, 10):
- if not self._GetJobPid():
- print '*** org.chromium.chromoting is not running ***'
- break
- time.sleep(2)
-
- def ChangePin(self):
- """Handles what pref pane does for changing pin."""
- # Elevate privileges, otherwise tool_script executes with EUID != 0.
- os.setuid(0)
- subprocess.call([self._tool_script, '--save-config'],
- stdin=open(self._config_file))
-
- # Drop privileges and send SIGHUP to org.chromium.chromoting
- os.setuid(self._real_user_id)
- os.kill(int(self._GetJobPid()), signal.SIGHUP)
-
- def NotifyWebapp(self):
- """Notifies the web app that pref pane operation is done."""
- notif_center = Foundation.NSDistributedNotificationCenter.defaultCenter()
- notif_center.postNotificationName_object_userInfo_(
- self._service_name + '.update_succeeded', None, None)
-
-
-def Main():
- """Handles the mock pref pane actions."""
- assert sys.platform.startswith('darwin')
-
- print '*** Started mock pref pane ***'
- print '*** EUID=%d, UID=%d ***' % (os.geteuid(), os.getuid())
-
- pref_pane = MockPrefPane()
-
- if sys.argv[1] == 'enable':
- pref_pane.Enable()
- elif sys.argv[1] == 'disable':
- pref_pane.Disable()
- elif sys.argv[1] == 'changepin':
- pref_pane.ChangePin()
- else:
- print >>sys.stderr, 'Invalid syntax'
- return
-
- pref_pane.NotifyWebapp()
-
-
-if __name__ == '__main__':
- Main() \ No newline at end of file
diff --git a/chrome/test/pyautolib/omnibox_info.py b/chrome/test/pyautolib/omnibox_info.py
deleted file mode 100644
index 5f11255..0000000
--- a/chrome/test/pyautolib/omnibox_info.py
+++ /dev/null
@@ -1,140 +0,0 @@
-# Copyright (c) 2011 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.
-
-"""Python representation for Chromium Omnibox.
-
-Obtain one of these from PyUITestSuite::GetOmniboxInfo() call.
-
-Example:
-class MyTest(pyauto.PyUITest):
- def testBasic(self):
- info = self.OmniboxInfo() # fetch omnibox snapshot
- print info.Matches()
-
-See more tests in chrome/test/functional/omnibox.py.
-"""
-
-import simplejson as json
-
-from pyauto_errors import JSONInterfaceError
-
-
-class OmniboxInfo(object):
- """Represent info for Chromium Omnibox.
-
- Info contains:
- - a list of matches in the same order as you'd see in the omnibox,
- - a dictionary of properties related to the omnibox.
-
- Sample info text:
-
- { u'matches': [
- {
- u'contents': u'google',
- u'description': u'Google Search',
- u'destination_url': u'http://www.google.com/search?aq=f&'
- 'sourceid=chrome&ie=UTF-8&q=google',
- u'starred': False,
- u'type': u'search-what-you-typed'},
- {
- u'contents': u'maps.google.com/',
- u'description': u'Google Maps',
- u'destination_url': u'http://maps.google.com/',
- u'starred': False,
- u'type': u'navsuggest'},
- { u'contents': u'google maps',
- u'description': u'',
- u'destination_url': u'http://www.google.com/search?aq=0&oq=google&'
- 'sourceid=chrome&ie=UTF-8&q=google+maps',
- u'starred': False,
- u'type': u'search-suggest'},
- { u'contents': u'google earth',
- u'description': u'',
- u'destination_url': u'http://www.google.com/search?aq=1&oq=google&'
- 'sourceid=chrome&ie=UTF-8&q=google+earth',
- u'starred': False,
- u'type': u'search-suggest'},
- { u'contents': u'Search Google for <enter query>',
- u'description': u'(Keyword: google.com)',
- u'destination_url': u'',
- u'starred': False,
- u'type': u'search-other-engine'}],
-
- u'properties': { u'has_focus': True,
- u'keyword': u'',
- u'query_in_progress': False,
- u'text': u'google'}}
- """
- def __init__(self, omnibox_dict):
- """Initialize a OmniboxInfo from a json string.
-
- Args:
- omnibox_dict: returned by an IPC call for the command 'GetOmniboxInfo'.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- # JSON string prepared in GetOmniboxInfo() in automation_provider.cc
- self.omniboxdict = omnibox_dict
- if self.omniboxdict.has_key('error'):
- raise JSONInterfaceError(self.omniboxdict['error'])
-
- def Matches(self):
- """Get omnibox matches.
-
- Returns:
- a list of omnibox match items.
- """
- return self.omniboxdict.get('matches', [])
-
- def MatchesWithAttributes(self, attr_dict):
- """Find all omnibox matches which match the attributes in |attr_dict|.
-
- Args:
- attr_dict: a dictionary of attributes to be satisfied.
- All attributes in the given dictionary should be satisfied.
- example:
- { 'destiantion_url': 'http://www.google.com/',
- 'description': 'Google' }
-
- Returns:
- a list of omnibox match items.
- """
- out = []
- for item in self.Matches():
- matched = True
- for key, val in attr_dict.iteritems():
- if not item.has_key(key) or item[key] != val:
- matched = False
- if matched:
- out.append(item)
- return out
-
- def Properties(self, key=None):
- """Get the properties
-
- Args:
- key: if specified, value for the given property is returned.
-
- Returns:
- a dictionary of properties if no key is given, OR
- value corresponding to a particular property if key is given
- """
- all = self.omniboxdict.get('properties')
- if not key:
- return all
- return all.get(key)
-
- def Text(self):
- """Get the text in the omnibox.
-
- This need not be the same as the user-inputted text, since omnibox may
- autocomplete some URLs, or the user may move omnibox popup selection
- up/down.
- """
- return self.Properties('text')
-
- def IsQueryInProgress(self):
- """Determine if a query is in progress."""
- return self.Properties('query_in_progress')
diff --git a/chrome/test/pyautolib/plugins_info.py b/chrome/test/pyautolib/plugins_info.py
deleted file mode 100644
index 6f55472..0000000
--- a/chrome/test/pyautolib/plugins_info.py
+++ /dev/null
@@ -1,112 +0,0 @@
-# Copyright (c) 2011 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.
-
-"""Python representation for Chromium Plugins info.
-
-This is the info available at about:plugins.
-Obtain one of these from PyUITestSuite::GetPluginsInfo() call.
-
-Example:
-class MyTest(pyauto.PyUITest):
- def testBasic(self):
- info = self.GetPluginsInfo() # fetch plugins snapshot
- print info.Plugins()
-
-See more examples in chrome/test/functional/plugins.py.
-"""
-
-import simplejson as json
-
-from pyauto_errors import JSONInterfaceError
-
-
-class PluginsInfo(object):
- """Represent info for Chromium plugins.
-
- The info is represented as a list of dictionaries, one for each plugin.
- """
- def __init__(self, plugins_dict):
- """Initialize a PluginsInfo from a json string.
-
- Args:
- plugins_dict: a dictionary returned by the automation command
- 'GetPluginsInfo'.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- # JSON string prepared in GetPluginsInfo() in automation_provider.cc
- self.pluginsdict = plugins_dict
- if self.pluginsdict.has_key('error'):
- raise JSONInterfaceError(self.pluginsdict['error'])
-
- def Plugins(self):
- """Get plugins.
-
- Returns:
- a list of plugins info
- Sample:
- [ { u'desc': u'Shockwave Flash 10.0 r45',
- u'enabled': True,
- u'mimeTypes': [ { u'description': u'Shockwave Flash',
- u'fileExtensions': [u'swf'],
- u'mimeType': u'application/x-shockwave-flash'},
- { u'description': u'FutureSplash Player',
- u'fileExtensions': [u'spl'],
- u'mimeType': u'application/futuresplash'}],
- u'name': u'Shockwave Flash',
- u'path': u'/Library/Internet Plug-Ins/Flash Player.plugin',
- u'version': u'10.0.45.2'},
- { u'desc': u'Version 1.1.2.9282',
- u'enabled': True,
- u'mimeTypes': [ { u'description': u'Google voice and video chat',
- u'fileExtensions': [u'googletalk'],
- u'mimeType': u'application/googletalk'}],
- u'name': u'Google Talk NPAPI Plugin',
- u'path': u'/Library/Internet Plug-Ins/googletalkbrowserplugin.plugin',
- u'version': u'1.1.2.9282'},
- ...,
- ...,
- ]
- """
- return self.pluginsdict.get('plugins', [])
-
- def PluginForPath(self, path):
- """Get plugin info for the given plugin path.
-
- Returns:
- a dictionary of info for the plugin.
- """
- got = filter(lambda x: x['path'] == path, self.Plugins())
- if not got: return None
- return got[0]
-
- def PluginForName(self, name):
- """Get plugin info for the given name.
-
- There might be several plugins with the same name.
-
- Args:
- name: the name for which to look for.
-
- Returns:
- a list of info dictionaries for each plugin found with the given name.
- """
- return filter(lambda x: x['name'] == name, self.Plugins())
-
- def FirstPluginForName(self, name):
- """Get plugin info for the first plugin with the given name.
-
- This is useful in case there are multiple plugins for a name.
-
- Args:
- name: the name for which to look for.
-
- Returns:
- a plugin info dictionary
- None, if not found
- """
- all = self.PluginForName(name)
- if not all: return None
- return all[0]
diff --git a/chrome/test/pyautolib/policy_base.py b/chrome/test/pyautolib/policy_base.py
deleted file mode 100644
index 023dfca..0000000
--- a/chrome/test/pyautolib/policy_base.py
+++ /dev/null
@@ -1,586 +0,0 @@
-# Copyright (c) 2012 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.
-
-"""Base class for tests that need to update the policies enforced by Chrome.
-
-Subclasses can call SetUserPolicy (ChromeOS, Linux, Windows) and
-SetDevicePolicy (ChromeOS only) with a dictionary of the policies to install.
-
-The current implementation depends on the platform. The implementations might
-change in the future, but tests relying on the above calls will keep working.
-"""
-
-# On ChromeOS, a mock DMServer is started and enterprise enrollment faked
-# against it. The mock DMServer then serves user and device policy to Chrome.
-#
-# For this setup to work, the DNS, GAIA and TPM (if present) are mocked as well:
-#
-# * The mock DNS resolves all addresses to 127.0.0.1. This allows the mock GAIA
-# to handle all login attempts. It also eliminates the impact of flaky network
-# connections on tests. Beware though that no cloud services can be accessed
-# due to this DNS redirect.
-#
-# * The mock GAIA permits login with arbitrary credentials and accepts any OAuth
-# tokens sent to it for verification as valid.
-#
-# * When running on a real device, its TPM is disabled. If the TPM were enabled,
-# enrollment could not be undone without a reboot. Disabling the TPM makes
-# cryptohomed behave as if no TPM was present, allowing enrollment to be
-# undone by removing the install attributes.
-#
-# To disable the TPM, 0 must be written to /sys/class/misc/tpm0/device/enabled.
-# Since this file is not writeable, a tpmfs is mounted that shadows the file
-# with a writeable copy.
-
-import json
-import logging
-import os
-import subprocess
-
-import pyauto
-
-if pyauto.PyUITest.IsChromeOS():
- import sys
- import warnings
-
- import pyauto_paths
-
- # Ignore deprecation warnings, they make our output more cluttered.
- warnings.filterwarnings('ignore', category=DeprecationWarning)
-
- # Find the path to the pyproto and add it to sys.path.
- # Prepend it so that google.protobuf is loaded from here.
- for path in pyauto_paths.GetBuildDirs():
- p = os.path.join(path, 'pyproto')
- if os.path.isdir(p):
- sys.path = [p, os.path.join(p, 'chrome', 'browser', 'policy',
- 'proto')] + sys.path
- break
- sys.path.append('/usr/local') # to import autotest libs.
-
- import dbus
- import device_management_backend_pb2 as dm
- import pyauto_utils
- import string
- import tempfile
- import urllib
- import urllib2
- import uuid
- from autotest.cros import auth_server
- from autotest.cros import constants
- from autotest.cros import cros_ui
- from autotest.cros import dns_server
-elif pyauto.PyUITest.IsWin():
- import _winreg as winreg
-elif pyauto.PyUITest.IsMac():
- import getpass
- import plistlib
-
-# ASN.1 object identifier for PKCS#1/RSA.
-PKCS1_RSA_OID = '\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01'
-
-TPM_SYSFS_PATH = '/sys/class/misc/tpm0'
-TPM_SYSFS_ENABLED_FILE = os.path.join(TPM_SYSFS_PATH, 'device/enabled')
-
-
-class PolicyTestBase(pyauto.PyUITest):
- """A base class for tests that need to set up and modify policies.
-
- Subclasses can use the methods SetUserPolicy (ChromeOS, Linux, Windows) and
- SetDevicePolicy (ChromeOS only) to set the policies seen by Chrome.
- """
-
- if pyauto.PyUITest.IsChromeOS():
- # TODO(bartfab): Extend the C++ wrapper that starts the mock DMServer so
- # that an owner can be passed in. Without this, the server will assume that
- # the owner is user@example.com and for consistency, so must we.
- owner = 'user@example.com'
- # Subclasses may override these credentials to fake enrollment into another
- # mode or use different device and machine IDs.
- mode = 'enterprise'
- device_id = string.upper(str(uuid.uuid4()))
- machine_id = 'CROSTEST'
-
- _auth_server = None
- _dns_server = None
-
- def ShouldAutoLogin(self):
- return False
-
- @staticmethod
- def _Call(command, check=False):
- """Invokes a subprocess and optionally asserts the return value is zero."""
- with open(os.devnull, 'w') as devnull:
- if check:
- return subprocess.check_call(command.split(' '), stdout=devnull)
- else:
- return subprocess.call(command.split(' '), stdout=devnull)
-
- def _WriteFile(self, path, content):
- """Writes content to path, creating any intermediary directories."""
- if not os.path.exists(os.path.dirname(path)):
- os.makedirs(os.path.dirname(path))
- f = open(path, 'w')
- f.write(content)
- f.close()
-
- def _GetTestServerPoliciesFilePath(self):
- """Returns the path of the cloud policy configuration file."""
- assert self.IsChromeOS()
- return os.path.join(self._temp_data_dir, 'device_management')
-
- def _GetHttpURLForDeviceManagement(self):
- """Returns the URL at which the TestServer is serving user policy."""
- assert self.IsChromeOS()
- return self._http_server.GetURL('device_management').spec()
-
- def _RemoveIfExists(self, filename):
- """Removes a file if it exists."""
- if os.path.exists(filename):
- os.remove(filename)
-
- def _StartSessionManagerAndChrome(self):
- """Starts the session manager and Chrome.
-
- Requires that the session manager be stopped already.
- """
- # Ugly hack: session manager will not spawn Chrome if this file exists. That
- # is usually a good thing (to keep the automation channel open), but in this
- # case we really want to restart chrome. PyUITest.setUp() will be called
- # after session manager and chrome have restarted, and will setup the
- # automation channel.
- restore_magic_file = False
- if os.path.exists(constants.DISABLE_BROWSER_RESTART_MAGIC_FILE):
- logging.debug('DISABLE_BROWSER_RESTART_MAGIC_FILE found. '
- 'Removing temporarily for the next restart.')
- restore_magic_file = True
- os.remove(constants.DISABLE_BROWSER_RESTART_MAGIC_FILE)
- assert not os.path.exists(constants.DISABLE_BROWSER_RESTART_MAGIC_FILE)
-
- logging.debug('Starting session manager again')
- cros_ui.start()
-
- # cros_ui.start() waits for the login prompt to be visible, so Chrome has
- # already started once it returns.
- if restore_magic_file:
- open(constants.DISABLE_BROWSER_RESTART_MAGIC_FILE, 'w').close()
- assert os.path.exists(constants.DISABLE_BROWSER_RESTART_MAGIC_FILE)
-
- def _WritePolicyOnChromeOS(self):
- """Updates the mock DMServer's input file with current policy."""
- assert self.IsChromeOS()
- policy_dict = {
- 'google/chromeos/device': self._device_policy,
- 'google/chromeos/user': {
- 'mandatory': self._user_policy,
- 'recommended': {},
- },
- 'managed_users': ['*'],
- }
- self._WriteFile(self._GetTestServerPoliciesFilePath(),
- json.dumps(policy_dict, sort_keys=True, indent=2) + '\n')
-
- @staticmethod
- def _IsCryptohomedReadyOnChromeOS():
- """Checks whether cryptohomed is running and ready to accept DBus calls."""
- assert pyauto.PyUITest.IsChromeOS()
- try:
- bus = dbus.SystemBus()
- proxy = bus.get_object('org.chromium.Cryptohome',
- '/org/chromium/Cryptohome')
- dbus.Interface(proxy, 'org.chromium.CryptohomeInterface')
- except dbus.DBusException:
- return False
- return True
-
- def _ClearInstallAttributesOnChromeOS(self):
- """Resets the install attributes."""
- assert self.IsChromeOS()
- self._RemoveIfExists('/home/.shadow/install_attributes.pb')
- self._Call('restart cryptohomed', check=True)
- assert self.WaitUntil(self._IsCryptohomedReadyOnChromeOS)
-
- def _DMPostRequest(self, request_type, request, headers):
- """Posts a request to the mock DMServer."""
- assert self.IsChromeOS()
- url = self._GetHttpURLForDeviceManagement()
- url += '?' + urllib.urlencode({
- 'deviceid': self.device_id,
- 'oauth_token': 'dummy_oauth_token_that_is_not_checked_anyway',
- 'request': request_type,
- 'devicetype': 2,
- 'apptype': 'Chrome',
- 'agent': 'Chrome',
- })
- response = dm.DeviceManagementResponse()
- response.ParseFromString(urllib2.urlopen(urllib2.Request(
- url, request.SerializeToString(), headers)).read())
- return response
-
- def _DMRegisterDevice(self):
- """Registers with the mock DMServer and returns the DMToken."""
- assert self.IsChromeOS()
- dm_request = dm.DeviceManagementRequest()
- request = dm_request.register_request
- request.type = dm.DeviceRegisterRequest.DEVICE
- request.machine_id = self.machine_id
- dm_response = self._DMPostRequest('register', dm_request, {})
- return dm_response.register_response.device_management_token
-
- def _DMFetchPolicy(self, dm_token):
- """Fetches device policy from the mock DMServer."""
- assert self.IsChromeOS()
- dm_request = dm.DeviceManagementRequest()
- policy_request = dm_request.policy_request
- request = policy_request.request.add()
- request.policy_type = 'google/chromeos/device'
- request.signature_type = dm.PolicyFetchRequest.SHA1_RSA
- headers = {'Authorization': 'GoogleDMToken token=' + dm_token}
- dm_response = self._DMPostRequest('policy', dm_request, headers)
- response = dm_response.policy_response.response[0]
- assert response.policy_data
- assert response.policy_data_signature
- assert response.new_public_key
- return response
-
- def ExtraChromeFlags(self):
- """Sets up Chrome to use cloud policies on ChromeOS."""
- flags = pyauto.PyUITest.ExtraChromeFlags(self)
- if self.IsChromeOS():
- while '--skip-oauth-login' in flags:
- flags.remove('--skip-oauth-login')
- url = self._GetHttpURLForDeviceManagement()
- flags.append('--device-management-url=' + url)
- flags.append('--disable-sync')
- return flags
-
- def _SetUpWithSessionManagerStopped(self):
- """Sets up the test environment after stopping the session manager."""
- assert self.IsChromeOS()
- logging.debug('Stopping session manager')
- cros_ui.stop(allow_fail=True)
-
- # Start mock GAIA server.
- self._auth_server = auth_server.GoogleAuthServer()
- self._auth_server.run()
-
- # Disable TPM if present.
- if os.path.exists(TPM_SYSFS_PATH):
- self._Call('mount -t tmpfs -o size=1k tmpfs %s'
- % os.path.realpath(TPM_SYSFS_PATH), check=True)
- self._WriteFile(TPM_SYSFS_ENABLED_FILE, '0')
-
- # Clear install attributes and restart cryptohomed to pick up the change.
- self._ClearInstallAttributesOnChromeOS()
-
- # Set install attributes to mock enterprise enrollment.
- bus = dbus.SystemBus()
- proxy = bus.get_object('org.chromium.Cryptohome',
- '/org/chromium/Cryptohome')
- install_attributes = {
- 'enterprise.device_id': self.device_id,
- 'enterprise.domain': string.split(self.owner, '@')[-1],
- 'enterprise.mode': self.mode,
- 'enterprise.owned': 'true',
- 'enterprise.user': self.owner
- }
- interface = dbus.Interface(proxy, 'org.chromium.CryptohomeInterface')
- for name, value in install_attributes.iteritems():
- interface.InstallAttributesSet(name, '%s\0' % value)
- interface.InstallAttributesFinalize()
-
- # Start mock DNS server that redirects all traffic to 127.0.0.1.
- self._dns_server = dns_server.LocalDns()
- self._dns_server.run()
-
- # Start mock DMServer.
- source_dir = os.path.normpath(pyauto_paths.GetSourceDir())
- self._temp_data_dir = tempfile.mkdtemp(dir=source_dir)
- logging.debug('TestServer input path: %s' % self._temp_data_dir)
- relative_temp_data_dir = os.path.basename(self._temp_data_dir)
- self._http_server = self.StartHTTPServer(relative_temp_data_dir)
-
- # Initialize the policy served.
- self._device_policy = {}
- self._user_policy = {}
- self._WritePolicyOnChromeOS()
-
- # Register with mock DMServer and retrieve initial device policy blob.
- dm_token = self._DMRegisterDevice()
- policy = self._DMFetchPolicy(dm_token)
-
- # Write the initial device policy blob.
- self._WriteFile(constants.OWNER_KEY_FILE, policy.new_public_key)
- self._WriteFile(constants.SIGNED_POLICY_FILE, policy.SerializeToString())
-
- # Remove any existing vaults.
- self.RemoveAllCryptohomeVaultsOnChromeOS()
-
- # Restart session manager and Chrome.
- self._StartSessionManagerAndChrome()
-
- def _tearDownWithSessionManagerStopped(self):
- """Resets the test environment after stopping the session manager."""
- assert self.IsChromeOS()
- logging.debug('Stopping session manager')
- cros_ui.stop(allow_fail=True)
-
- # Stop mock GAIA server.
- if self._auth_server:
- self._auth_server.stop()
-
- # Reenable TPM if present.
- if os.path.exists(TPM_SYSFS_PATH):
- self._Call('umount %s' % os.path.realpath(TPM_SYSFS_PATH))
-
- # Clear install attributes and restart cryptohomed to pick up the change.
- self._ClearInstallAttributesOnChromeOS()
-
- # Stop mock DNS server.
- if self._dns_server:
- self._dns_server.stop()
-
- # Stop mock DMServer.
- self.StopHTTPServer(self._http_server)
-
- # Clear the policy served.
- pyauto_utils.RemovePath(self._temp_data_dir)
-
- # Remove the device policy blob.
- self._RemoveIfExists(constants.OWNER_KEY_FILE)
- self._RemoveIfExists(constants.SIGNED_POLICY_FILE)
-
- # Remove any existing vaults.
- self.RemoveAllCryptohomeVaultsOnChromeOS()
-
- # Restart session manager and Chrome.
- self._StartSessionManagerAndChrome()
-
- def setUp(self):
- """Sets up the platform for policy testing.
-
- On ChromeOS, part of the setup involves restarting the session manager to
- inject an initial device policy blob.
- """
- if self.IsChromeOS():
- # Perform the remainder of the setup with the device manager stopped.
- try:
- self.WaitForSessionManagerRestart(
- self._SetUpWithSessionManagerStopped)
- except:
- # Destroy the non re-entrant services.
- if self._auth_server:
- self._auth_server.stop()
- if self._dns_server:
- self._dns_server.stop()
- raise
-
- pyauto.PyUITest.setUp(self)
- self._branding = self.GetBrowserInfo()['properties']['branding']
-
- def tearDown(self):
- """Cleans up the policies and related files created in tests."""
- if self.IsChromeOS():
- # Perform the cleanup with the device manager stopped.
- self.WaitForSessionManagerRestart(self._tearDownWithSessionManagerStopped)
- else:
- # On other platforms, there is only user policy to clear.
- self.SetUserPolicy(refresh=False)
-
- pyauto.PyUITest.tearDown(self)
-
- def LoginWithTestAccount(self, account='prod_enterprise_test_user'):
- """Convenience method for logging in with one of the test accounts."""
- assert self.IsChromeOS()
- credentials = self.GetPrivateInfo()[account]
- self.Login(credentials['username'], credentials['password'])
- assert self.GetLoginInfo()['is_logged_in']
-
- def _GetCurrentLoginScreenId(self):
- return self.ExecuteJavascriptInOOBEWebUI(
- """window.domAutomationController.send(
- String(cr.ui.Oobe.getInstance().currentScreen.id));
- """)
-
- def _WaitForLoginScreenId(self, id):
- self.assertTrue(
- self.WaitUntil(function=self._GetCurrentLoginScreenId,
- expect_retval=id),
- msg='Expected login screen "%s" to be visible.' % id)
-
- def _CheckLoginFormLoading(self):
- return self.ExecuteJavascriptInOOBEWebUI(
- """window.domAutomationController.send(
- cr.ui.Oobe.getInstance().currentScreen.loading);
- """)
-
- def PrepareToWaitForLoginFormReload(self):
- self.assertEqual('gaia-signin',
- self._GetCurrentLoginScreenId(),
- msg='Expected the login form to be visible.')
- self.assertTrue(
- self.WaitUntil(function=self._CheckLoginFormLoading,
- expect_retval=False),
- msg='Expected the login form to finish loading.')
- # Set up a sentinel variable that is false now and will toggle to true when
- # the login form starts reloading.
- self.ExecuteJavascriptInOOBEWebUI(
- """var screen = cr.ui.Oobe.getInstance().currentScreen;
- if (!('reload_started' in screen)) {
- screen.orig_loadAuthExtension_ = screen.loadAuthExtension_;
- screen.loadAuthExtension_ = function(data) {
- this.orig_loadAuthExtension_(data);
- if (this.loading)
- this.reload_started = true;
- }
- }
- screen.reload_started = false;
- window.domAutomationController.send(true);""")
-
- def _CheckLoginFormReloaded(self):
- return self.ExecuteJavascriptInOOBEWebUI(
- """window.domAutomationController.send(
- cr.ui.Oobe.getInstance().currentScreen.reload_started &&
- !cr.ui.Oobe.getInstance().currentScreen.loading);
- """)
-
- def WaitForLoginFormReload(self):
- self.assertEqual('gaia-signin',
- self._GetCurrentLoginScreenId(),
- msg='Expected the login form to be visible.')
- self.assertTrue(
- self.WaitUntil(function=self._CheckLoginFormReloaded),
- msg='Expected the login form to finish reloading.')
-
- def _SetUserPolicyChromeOS(self, user_policy=None):
- """Writes the given user policy to the mock DMServer's input file."""
- self._user_policy = user_policy or {}
- self._WritePolicyOnChromeOS()
-
- def _SetUserPolicyWin(self, user_policy=None):
- """Writes the given user policy to the Windows registry."""
- def SetValueEx(key, sub_key, value):
- if isinstance(value, int):
- winreg.SetValueEx(key, sub_key, 0, winreg.REG_DWORD, int(value))
- elif isinstance(value, basestring):
- winreg.SetValueEx(key, sub_key, 0, winreg.REG_SZ, value.encode('ascii'))
- elif isinstance(value, list):
- k = winreg.CreateKey(key, sub_key)
- for index, v in list(enumerate(value)):
- SetValueEx(k, str(index + 1), v)
- winreg.CloseKey(k)
- else:
- raise TypeError('Unsupported data type: "%s"' % value)
-
- assert self.IsWin()
- if self._branding == 'Google Chrome':
- reg_base = r'SOFTWARE\Policies\Google\Chrome'
- else:
- reg_base = r'SOFTWARE\Policies\Chromium'
-
- if subprocess.call(
- r'reg query HKEY_LOCAL_MACHINE\%s' % reg_base) == 0:
- logging.debug(r'Removing %s' % reg_base)
- subprocess.call(r'reg delete HKLM\%s /f' % reg_base)
-
- if user_policy is not None:
- root_key = winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, reg_base)
- for k, v in user_policy.iteritems():
- SetValueEx(root_key, k, v)
- winreg.CloseKey(root_key)
-
- def _SetUserPolicyLinux(self, user_policy=None):
- """Writes the given user policy to the JSON policy file read by Chrome."""
- assert self.IsLinux()
- sudo_cmd_file = os.path.join(os.path.dirname(__file__),
- 'policy_posix_util.py')
-
- if self._branding == 'Google Chrome':
- policies_location_base = '/etc/opt/chrome'
- else:
- policies_location_base = '/etc/chromium'
-
- if os.path.exists(policies_location_base):
- logging.debug('Removing directory %s' % policies_location_base)
- subprocess.call(['suid-python', sudo_cmd_file,
- 'remove_dir', policies_location_base])
-
- if user_policy is not None:
- self._WriteFile('/tmp/chrome.json',
- json.dumps(user_policy, sort_keys=True, indent=2) + '\n')
-
- policies_location = '%s/policies/managed' % policies_location_base
- subprocess.call(['suid-python', sudo_cmd_file,
- 'setup_dir', policies_location])
- subprocess.call(['suid-python', sudo_cmd_file,
- 'perm_dir', policies_location])
- # Copy chrome.json file to the managed directory
- subprocess.call(['suid-python', sudo_cmd_file,
- 'copy', '/tmp/chrome.json', policies_location])
- os.remove('/tmp/chrome.json')
-
- def _SetUserPolicyMac(self, user_policy=None):
- """Writes the given user policy to the plist policy file read by Chrome."""
- assert self.IsMac()
- sudo_cmd_file = os.path.join(os.path.dirname(__file__),
- 'policy_posix_util.py')
-
- if self._branding == 'Google Chrome':
- policies_file_base = 'com.google.Chrome.plist'
- else:
- policies_file_base = 'org.chromium.Chromium.plist'
-
- policies_location = os.path.join('/Library', 'Managed Preferences',
- getpass.getuser())
-
- if os.path.exists(policies_location):
- logging.debug('Removing directory %s' % policies_location)
- subprocess.call(['suid-python', sudo_cmd_file,
- 'remove_dir', policies_location])
-
- if user_policy is not None:
- policies_tmp_file = os.path.join('/tmp', policies_file_base)
- plistlib.writePlist(user_policy, policies_tmp_file)
- subprocess.call(['suid-python', sudo_cmd_file,
- 'setup_dir', policies_location])
- # Copy policy file to the managed directory
- subprocess.call(['suid-python', sudo_cmd_file,
- 'copy', policies_tmp_file, policies_location])
- os.remove(policies_tmp_file)
-
- def SetUserPolicy(self, user_policy=None, refresh=True):
- """Sets the user policy provided as a dict.
-
- Args:
- user_policy: The user policy to set. None clears it.
- refresh: If True, Chrome will refresh and apply the new policy.
- Requires Chrome to be alive for it.
- """
- if self.IsChromeOS():
- self._SetUserPolicyChromeOS(user_policy=user_policy)
- elif self.IsWin():
- self._SetUserPolicyWin(user_policy=user_policy)
- elif self.IsLinux():
- self._SetUserPolicyLinux(user_policy=user_policy)
- elif self.IsMac():
- self._SetUserPolicyMac(user_policy=user_policy)
- else:
- raise NotImplementedError('Not available on this platform.')
-
- if refresh:
- self.RefreshPolicies()
-
- def SetDevicePolicy(self, device_policy=None, refresh=True):
- """Sets the device policy provided as a dict.
-
- Args:
- device_policy: The device policy to set. None clears it.
- refresh: If True, Chrome will refresh and apply the new policy.
- Requires Chrome to be alive for it.
- """
- assert self.IsChromeOS()
- self._device_policy = device_policy or {}
- self._WritePolicyOnChromeOS()
- if refresh:
- self.RefreshPolicies()
diff --git a/chrome/test/pyautolib/policy_posix_util.py b/chrome/test/pyautolib/policy_posix_util.py
deleted file mode 100755
index 420131b..0000000
--- a/chrome/test/pyautolib/policy_posix_util.py
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Helper script to copy policy files into the correct location the machine."""
-
-import os
-import shutil
-import sys
-
-
-def main():
- assert os.geteuid() == 0, 'Need superuser privileges'
- if sys.argv[1] == 'copy':
- assert os.path.isdir(sys.argv[3])
- shutil.copy(sys.argv[2], sys.argv[3])
- dirList = os.listdir(sys.argv[3])
- for fname in dirList:
- filename = os.path.join(sys.argv[3], fname)
- os.chmod(filename, 0755)
- elif sys.argv[1] == 'setup_dir':
- os.makedirs(sys.argv[2])
- elif sys.argv[1] == 'perm_dir':
- os.system('chmod -R 755 "%s/../.."' % sys.argv[2])
- elif sys.argv[1] == 'remove_dir':
- os.system('rm -rf "%s"' % sys.argv[2])
- else:
- print >>sys.stderr, (
- 'Invalid syntax. Possible values are [copy], [setup_dir], '
- '[perm_dir], [remove_dir]')
- return 1
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/chrome/test/pyautolib/prefs_info.py b/chrome/test/pyautolib/prefs_info.py
deleted file mode 100644
index c84998f..0000000
--- a/chrome/test/pyautolib/prefs_info.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# Copyright (c) 2011 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.
-
-"""Python representation for Chromium Preferences.
-
-Obtain one of these from a call to PyUITest::GetPrefsInfo() or
-PyUITest::GetLocalStatePrefsInfo().
-
-Example:
-class MyTest(pyauto.PyUITest):
- def testBasic(self):
- info = self.GetPrefsInfo() # fetch prefs snapshot
- print info.Prefs() # all prefs
- print info.Prefs('session.restore_on_startup') # a single pref
-
-See more tests in chrome/test/functional/prefs.py.
-"""
-
-import simplejson as json
-
-from pyauto_errors import JSONInterfaceError
-
-
-class PrefsInfo(object):
- """Represent info for Chromium preferences.
-
- The info is represented as a hierarchy of prefs values.
- The values could be plain (integer, bool, float) or complex (like
- dictionary, list).
- """
- def __init__(self, prefs_dict):
- """Initialize a PrefsInfo from a json string.
-
- Args:
- prefs_dict: a dictionary as returned by the IPC command 'GetPrefsInfo'.
- A typical dict representing prefs snapshot looks like:
- { u'prefs':
- { u'alternate_error_pages': {u'enabled': True},
- u'autofill': { u'auxiliary_profiles_enabled': False,
- u'default_creditcard': u'',
- u'default_profile': u'',
- u'enabled': True,
- u'infobar_shown': False,
- u'negative_upload_rate': 0.01,
- u'positive_upload_rate': 0.01},
- u'bookmark_bar': {u'show_on_all_tabs': False},
- ...
- ...
- }
- }
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- # JSON string prepared in PrefsInfo() in automation_provider.cc
- self.prefsdict = prefs_dict
- if self.prefsdict.has_key('error'):
- raise JSONInterfaceError(self.prefsdict['error'])
-
- def Prefs(self, path=None):
- """Get preferences.
-
- The preference dictionary (when using path=None) looks like:
-
- { u'alternate_error_pages': {u'enabled': True},
- u'autofill': { u'auxiliary_profiles_enabled': False,
- u'default_creditcard': u'',
- u'default_profile': u'',
- u'enabled': True,
- u'infobar_shown': False,
- u'negative_upload_rate': 0.01,
- u'positive_upload_rate': 0.01},
- u'bookmark_bar': {u'show_on_all_tabs': False},
- ...
- ...
- }
-
- In this case, to fetch the preference value for autofill enabled, use
- 'autofill.enabled' as the path.
-
- Args:
- path: If specified, return the preference item for the given path.
- path is a dot-separated string like "session.restore_on_startup".
- One of the equivalent names in chrome/common/pref_names.h could
- also be used.
-
- Returns:
- preference value. It could be a dictionary (like the example above), a
- list or a plain value.
- None, if prefernece for path not found (if path is given).
- """
- all = self.prefsdict.get('prefs', {})
- if not path: # No path given. Return all prefs.
- return all
- for part in path.split('.'): # Narrow down to the requested prefs path.
- all = all.get(part)
- if all is None: return None
- return all
diff --git a/chrome/test/pyautolib/pyauto.py b/chrome/test/pyautolib/pyauto.py
deleted file mode 100755
index 4f255b1c..0000000
--- a/chrome/test/pyautolib/pyauto.py
+++ /dev/null
@@ -1,5426 +0,0 @@
-#!/usr/bin/env python
-# 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.
-
-"""PyAuto: Python Interface to Chromium's Automation Proxy.
-
-PyAuto uses swig to expose Automation Proxy interfaces to Python.
-For complete documentation on the functionality available,
-run pydoc on this file.
-
-Ref: http://dev.chromium.org/developers/testing/pyauto
-
-
-Include the following in your PyAuto test script to make it run standalone.
-
-from pyauto import Main
-
-if __name__ == '__main__':
- Main()
-
-This script can be used as an executable to fire off other scripts, similar
-to unittest.py
- python pyauto.py test_script
-"""
-
-import cStringIO
-import copy
-import functools
-import hashlib
-import inspect
-import logging
-import optparse
-import os
-import pickle
-import pprint
-import re
-import shutil
-import signal
-import socket
-import stat
-import string
-import subprocess
-import sys
-import tempfile
-import time
-import types
-import unittest
-import urllib
-
-import pyauto_paths
-
-
-def _LocateBinDirs():
- """Setup a few dirs where we expect to find dependency libraries."""
- deps_dirs = [
- os.path.dirname(__file__),
- pyauto_paths.GetThirdPartyDir(),
- os.path.join(pyauto_paths.GetThirdPartyDir(), 'webdriver', 'pylib'),
- ]
- sys.path += map(os.path.normpath, pyauto_paths.GetBuildDirs() + deps_dirs)
-
-_LocateBinDirs()
-
-_PYAUTO_DOC_URL = 'http://dev.chromium.org/developers/testing/pyauto'
-
-try:
- import pyautolib
- # Needed so that all additional classes (like: FilePath, GURL) exposed by
- # swig interface get available in this module.
- from pyautolib import *
-except ImportError:
- print >>sys.stderr, 'Could not locate pyautolib shared libraries. ' \
- 'Did you build?\n Documentation: %s' % _PYAUTO_DOC_URL
- # Mac requires python2.5 even when not the default 'python' (e.g. 10.6)
- if 'darwin' == sys.platform and sys.version_info[:2] != (2,5):
- print >>sys.stderr, '*\n* Perhaps use "python2.5", not "python" ?\n*'
- raise
-
-# Should go after sys.path is set appropriately
-import bookmark_model
-import download_info
-import history_info
-import omnibox_info
-import plugins_info
-import prefs_info
-from pyauto_errors import AutomationCommandFail
-from pyauto_errors import AutomationCommandTimeout
-from pyauto_errors import JavascriptRuntimeError
-from pyauto_errors import JSONInterfaceError
-from pyauto_errors import NTPThumbnailNotShownError
-import pyauto_utils
-import simplejson as json # found in third_party
-
-_CHROME_DRIVER_FACTORY = None
-_DEFAULT_AUTOMATION_TIMEOUT = 45
-_HTTP_SERVER = None
-_REMOTE_PROXY = None
-_OPTIONS = None
-_BROWSER_PID = None
-
-class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
- """Base class for UI Test Cases in Python.
-
- A browser is created before executing each test, and is destroyed after
- each test irrespective of whether the test passed or failed.
-
- You should derive from this class and create methods with 'test' prefix,
- and use methods inherited from PyUITestBase (the C++ side).
-
- Example:
-
- class MyTest(PyUITest):
-
- def testNavigation(self):
- self.NavigateToURL("http://www.google.com")
- self.assertEqual("Google", self.GetActiveTabTitle())
- """
-
- def __init__(self, methodName='runTest', **kwargs):
- """Initialize PyUITest.
-
- When redefining __init__ in a derived class, make sure that:
- o you make a call this __init__
- o __init__ takes methodName as an arg. this is mandated by unittest module
-
- Args:
- methodName: the default method name. Internal use by unittest module
-
- (The rest of the args can be in any order. They can even be skipped in
- which case the defaults will be used.)
-
- clear_profile: If True, clean the profile dir before use. Defaults to True
- homepage: the home page. Defaults to "about:blank"
- """
- # Fetch provided keyword args, or fill in defaults.
- clear_profile = kwargs.get('clear_profile', True)
- homepage = kwargs.get('homepage', 'about:blank')
- self._automation_timeout = _DEFAULT_AUTOMATION_TIMEOUT * 1000
-
- pyautolib.PyUITestBase.__init__(self, clear_profile, homepage)
- self.Initialize(pyautolib.FilePath(self.BrowserPath()))
- unittest.TestCase.__init__(self, methodName)
-
- # Give all pyauto tests easy access to pprint.PrettyPrinter functions.
- self.pprint = pprint.pprint
- self.pformat = pprint.pformat
-
- # Set up remote proxies, if they were requested.
- self.remotes = []
- self.remote = None
- global _REMOTE_PROXY
- if _REMOTE_PROXY:
- self.remotes = _REMOTE_PROXY
- self.remote = _REMOTE_PROXY[0]
-
- def __del__(self):
- pyautolib.PyUITestBase.__del__(self)
-
- def _SetExtraChromeFlags(self):
- """Prepares the browser to launch with the specified extra Chrome flags.
-
- This function is called right before the browser is launched for the first
- time.
- """
- for flag in self.ExtraChromeFlags():
- if flag.startswith('--'):
- flag = flag[2:]
- split_pos = flag.find('=')
- if split_pos >= 0:
- flag_name = flag[:split_pos]
- flag_val = flag[split_pos + 1:]
- self.AppendBrowserLaunchSwitch(flag_name, flag_val)
- else:
- self.AppendBrowserLaunchSwitch(flag)
-
- def __SetUp(self):
- named_channel_id = None
- if _OPTIONS:
- named_channel_id = _OPTIONS.channel_id
- if self.IsChromeOS(): # Enable testing interface on ChromeOS.
- if self.get_clear_profile():
- self.CleanupBrowserProfileOnChromeOS()
- self.EnableCrashReportingOnChromeOS()
- if not named_channel_id:
- named_channel_id = self.EnableChromeTestingOnChromeOS()
- else:
- self._SetExtraChromeFlags() # Flags already previously set for ChromeOS.
- if named_channel_id:
- self._named_channel_id = named_channel_id
- self.UseNamedChannelID(named_channel_id)
- # Initialize automation and fire the browser (does not fire the browser
- # on ChromeOS).
- self.SetUp()
-
- global _BROWSER_PID
- try:
- _BROWSER_PID = self.GetBrowserInfo()['browser_pid']
- except JSONInterfaceError:
- raise JSONInterfaceError('Unable to get browser_pid over automation '
- 'channel on first attempt. Something went very '
- 'wrong. Chrome probably did not launch.')
-
- # Forcibly trigger all plugins to get registered. crbug.com/94123
- # Sometimes flash files loaded too quickly after firing browser
- # ends up getting downloaded, which seems to indicate that the plugin
- # hasn't been registered yet.
- if not self.IsChromeOS():
- self.GetPluginsInfo()
-
- if (self.IsChromeOS() and not self.GetLoginInfo()['is_logged_in'] and
- self.ShouldOOBESkipToLogin()):
- if self.GetOOBEScreenInfo()['screen_name'] != 'login':
- self.SkipToLogin()
- if self.ShouldAutoLogin():
- # Login with default creds.
- sys.path.append('/usr/local') # to import autotest libs
- from autotest.cros import constants
- creds = constants.CREDENTIALS['$default']
- self.Login(creds[0], creds[1])
- assert self.GetLoginInfo()['is_logged_in']
- logging.info('Logged in as %s.' % creds[0])
-
- # If we are connected to any RemoteHosts, create PyAuto
- # instances on the remote sides and set them up too.
- for remote in self.remotes:
- remote.CreateTarget(self)
- remote.setUp()
-
- def setUp(self):
- """Override this method to launch browser differently.
-
- Can be used to prevent launching the browser window by default in case a
- test wants to do some additional setup before firing browser.
-
- When using the named interface, it connects to an existing browser
- instance.
-
- On ChromeOS, a browser showing the login window is started. Tests can
- initiate a user session by calling Login() or LoginAsGuest(). Cryptohome
- vaults or flimflam profiles left over by previous tests can be cleared by
- calling RemoveAllCryptohomeVaults() respectively CleanFlimflamDirs() before
- logging in to improve isolation. Note that clearing flimflam profiles
- requires a flimflam restart, briefly taking down network connectivity and
- slowing down the test. This should be done for tests that use flimflam only.
- """
- self.__SetUp()
-
- def tearDown(self):
- for remote in self.remotes:
- remote.tearDown()
-
- self.TearDown() # Destroy browser
-
- # Method required by the Python standard library unittest.TestCase.
- def runTest(self):
- pass
-
- @staticmethod
- def BrowserPath():
- """Returns the path to Chromium binaries.
-
- Expects the browser binaries to be in the
- same location as the pyautolib binaries.
- """
- return os.path.normpath(os.path.dirname(pyautolib.__file__))
-
- def ExtraChromeFlags(self):
- """Return a list of extra chrome flags to use with Chrome for testing.
-
- These are flags needed to facilitate testing. Override this function to
- use a custom set of Chrome flags.
- """
- auth_ext_path = ('/usr/local/autotest/deps/pyauto_dep/' +
- 'test_src/chrome/browser/resources/gaia_auth')
- if self.IsChromeOS():
- return [
- '--homepage=about:blank',
- '--allow-file-access',
- '--allow-file-access-from-files',
- '--enable-file-cookies',
- '--disable-default-apps',
- '--dom-automation',
- '--skip-oauth-login',
- # Enables injection of test content script for webui login automation
- '--auth-ext-path=%s' % auth_ext_path,
- # Enable automation provider, chromeos net and chromeos login logs
- '--vmodule=*/browser/automation/*=2,*/chromeos/net/*=2,' +
- '*/chromeos/login/*=2',
- ]
- else:
- return []
-
- def ShouldOOBESkipToLogin(self):
- """Determine if we should skip the OOBE flow on ChromeOS.
-
- This makes automation skip the OOBE flow during setUp() and land directly
- to the login screen. Applies only if not logged in already.
-
- Override and return False if OOBE flow is required, for OOBE tests, for
- example. Calling this function directly will have no effect.
-
- Returns:
- True, if the OOBE should be skipped and automation should
- go to the 'Add user' login screen directly
- False, if the OOBE should not be skipped.
- """
- assert self.IsChromeOS()
- return True
-
- def ShouldAutoLogin(self):
- """Determine if we should auto-login on ChromeOS at browser startup.
-
- To be used for tests that expect user to be logged in before running test,
- without caring which user. ShouldOOBESkipToLogin() should return True
- for this to take effect.
-
- Override and return False to not auto login, for tests where login is part
- of the use case.
-
- Returns:
- True, if chrome should auto login after startup.
- False, otherwise.
- """
- assert self.IsChromeOS()
- return True
-
- def CloseChromeOnChromeOS(self):
- """Gracefully exit chrome on ChromeOS."""
-
- def _GetListOfChromePids():
- """Retrieves the list of currently-running Chrome process IDs.
-
- Returns:
- A list of strings, where each string represents a currently-running
- 'chrome' process ID.
- """
- proc = subprocess.Popen(['pgrep', '^chrome$'], stdout=subprocess.PIPE)
- proc.wait()
- return [x.strip() for x in proc.stdout.readlines()]
-
- orig_pids = _GetListOfChromePids()
- subprocess.call(['pkill', '^chrome$'])
-
- def _AreOrigPidsDead(orig_pids):
- """Determines whether all originally-running 'chrome' processes are dead.
-
- Args:
- orig_pids: A list of strings, where each string represents the PID for
- an originally-running 'chrome' process.
-
- Returns:
- True, if all originally-running 'chrome' processes have been killed, or
- False otherwise.
- """
- for new_pid in _GetListOfChromePids():
- if new_pid in orig_pids:
- return False
- return True
-
- self.WaitUntil(lambda: _AreOrigPidsDead(orig_pids))
-
- @staticmethod
- def _IsRootSuid(path):
- """Determine if |path| is a suid-root file."""
- return os.path.isfile(path) and (os.stat(path).st_mode & stat.S_ISUID)
-
- @staticmethod
- def SuidPythonPath():
- """Path to suid_python binary on ChromeOS.
-
- This is typically in the same directory as pyautolib.py
- """
- return os.path.join(PyUITest.BrowserPath(), 'suid-python')
-
- @staticmethod
- def RunSuperuserActionOnChromeOS(action):
- """Run the given action with superuser privs (on ChromeOS).
-
- Uses the suid_actions.py script.
-
- Args:
- action: An action to perform.
- See suid_actions.py for available options.
-
- Returns:
- (stdout, stderr)
- """
- assert PyUITest._IsRootSuid(PyUITest.SuidPythonPath()), \
- 'Did not find suid-root python at %s' % PyUITest.SuidPythonPath()
- file_path = os.path.join(os.path.dirname(__file__), 'chromeos',
- 'suid_actions.py')
- args = [PyUITest.SuidPythonPath(), file_path, '--action=%s' % action]
- proc = subprocess.Popen(
- args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- stdout, stderr = proc.communicate()
- return (stdout, stderr)
-
- def EnableChromeTestingOnChromeOS(self):
- """Enables the named automation interface on chromeos.
-
- Restarts chrome so that you get a fresh instance.
- Also sets some testing-friendly flags for chrome.
-
- Expects suid python to be present in the same dir as pyautolib.py
- """
- assert PyUITest._IsRootSuid(self.SuidPythonPath()), \
- 'Did not find suid-root python at %s' % self.SuidPythonPath()
- file_path = os.path.join(os.path.dirname(__file__), 'chromeos',
- 'enable_testing.py')
- args = [self.SuidPythonPath(), file_path]
- # Pass extra chrome flags for testing
- for flag in self.ExtraChromeFlags():
- args.append('--extra-chrome-flags=%s' % flag)
- assert self.WaitUntil(lambda: self._IsSessionManagerReady(0))
- proc = subprocess.Popen(args, stdout=subprocess.PIPE)
- automation_channel_path = proc.communicate()[0].strip()
- assert len(automation_channel_path), 'Could not enable testing interface'
- return automation_channel_path
-
- @staticmethod
- def EnableCrashReportingOnChromeOS():
- """Enables crash reporting on ChromeOS.
-
- Writes the "/home/chronos/Consent To Send Stats" file with a 32-char
- readable string. See comment in session_manager_setup.sh which does this
- too.
-
- Note that crash reporting will work only if breakpad is built in, ie in a
- 'Google Chrome' build (not Chromium).
- """
- consent_file = '/home/chronos/Consent To Send Stats'
- def _HasValidConsentFile():
- if not os.path.isfile(consent_file):
- return False
- stat = os.stat(consent_file)
- return (len(open(consent_file).read()) and
- (1000, 1000) == (stat.st_uid, stat.st_gid))
- if not _HasValidConsentFile():
- client_id = hashlib.md5('abcdefgh').hexdigest()
- # Consent file creation and chown to chronos needs to be atomic
- # to avoid races with the session_manager. crosbug.com/18413
- # Therefore, create a temp file, chown, then rename it as consent file.
- temp_file = consent_file + '.tmp'
- open(temp_file, 'w').write(client_id)
- # This file must be owned by chronos:chronos!
- os.chown(temp_file, 1000, 1000);
- shutil.move(temp_file, consent_file)
- assert _HasValidConsentFile(), 'Could not create %s' % consent_file
-
- @staticmethod
- def _IsSessionManagerReady(old_pid):
- """Is the ChromeOS session_manager running and ready to accept DBus calls?
-
- Called after session_manager is killed to know when it has restarted.
-
- Args:
- old_pid: The pid that session_manager had before it was killed,
- to ensure that we don't look at the DBus interface
- of an old session_manager process.
- """
- pgrep_process = subprocess.Popen(['pgrep', 'session_manager'],
- stdout=subprocess.PIPE)
- new_pid = pgrep_process.communicate()[0].strip()
- if not new_pid or old_pid == new_pid:
- return False
-
- import dbus
- try:
- bus = dbus.SystemBus()
- proxy = bus.get_object('org.chromium.SessionManager',
- '/org/chromium/SessionManager')
- dbus.Interface(proxy, 'org.chromium.SessionManagerInterface')
- except dbus.DBusException:
- return False
- return True
-
- @staticmethod
- def CleanupBrowserProfileOnChromeOS():
- """Cleanup browser profile dir on ChromeOS.
-
- This does not clear cryptohome.
-
- Browser should not be running, or else there will be locked files.
- """
- profile_dir = '/home/chronos/user'
- for item in os.listdir(profile_dir):
- # Deleting .pki causes stateful partition to get erased.
- if item not in ['log', 'flimflam'] and not item.startswith('.'):
- pyauto_utils.RemovePath(os.path.join(profile_dir, item))
-
- chronos_dir = '/home/chronos'
- for item in os.listdir(chronos_dir):
- if item != 'user' and not item.startswith('.'):
- pyauto_utils.RemovePath(os.path.join(chronos_dir, item))
-
- @staticmethod
- def CleanupFlimflamDirsOnChromeOS():
- """Clean the contents of flimflam profiles and restart flimflam."""
- PyUITest.RunSuperuserActionOnChromeOS('CleanFlimflamDirs')
-
- @staticmethod
- def RemoveAllCryptohomeVaultsOnChromeOS():
- """Remove any existing cryptohome vaults."""
- PyUITest.RunSuperuserActionOnChromeOS('RemoveAllCryptohomeVaults')
-
- @staticmethod
- def _IsInodeNew(path, old_inode):
- """Determine whether an inode has changed. POSIX only.
-
- Args:
- path: The file path to check for changes.
- old_inode: The old inode number.
-
- Returns:
- True if the path exists and its inode number is different from old_inode.
- False otherwise.
- """
- try:
- stat_result = os.stat(path)
- except OSError:
- return False
- if not stat_result:
- return False
- return stat_result.st_ino != old_inode
-
- def RestartBrowser(self, clear_profile=True, pre_launch_hook=None):
- """Restart the browser.
-
- For use with tests that require to restart the browser.
-
- Args:
- clear_profile: If True, the browser profile is cleared before restart.
- Defaults to True, that is restarts browser with a clean
- profile.
- pre_launch_hook: If specified, must be a callable that is invoked before
- the browser is started again. Not supported in ChromeOS.
- """
- if self.IsChromeOS():
- assert pre_launch_hook is None, 'Not supported in ChromeOS'
- self.TearDown()
- if clear_profile:
- self.CleanupBrowserProfileOnChromeOS()
- self.CloseChromeOnChromeOS()
- self.EnableChromeTestingOnChromeOS()
- self.SetUp()
- return
- # Not chromeos
- orig_clear_state = self.get_clear_profile()
- self.CloseBrowserAndServer()
- self.set_clear_profile(clear_profile)
- if pre_launch_hook:
- pre_launch_hook()
- logging.debug('Restarting browser with clear_profile=%s',
- self.get_clear_profile())
- self.LaunchBrowserAndServer()
- self.set_clear_profile(orig_clear_state) # Reset to original state.
-
- @staticmethod
- def DataDir():
- """Returns the path to the data dir chrome/test/data."""
- return os.path.normpath(
- os.path.join(os.path.dirname(__file__), os.pardir, "data"))
-
- @staticmethod
- def ChromeOSDataDir():
- """Returns the path to the data dir chromeos/test/data."""
- return os.path.normpath(
- os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
- "chromeos", "test", "data"))
-
- @staticmethod
- def GetFileURLForPath(*path):
- """Get file:// url for the given path.
-
- Also quotes the url using urllib.quote().
-
- Args:
- path: Variable number of strings that can be joined.
- """
- path_str = os.path.join(*path)
- abs_path = os.path.abspath(path_str)
- if sys.platform == 'win32':
- # Don't quote the ':' in drive letter ( say, C: ) on win.
- # Also, replace '\' with '/' as expected in a file:/// url.
- drive, rest = os.path.splitdrive(abs_path)
- quoted_path = drive.upper() + urllib.quote((rest.replace('\\', '/')))
- return 'file:///' + quoted_path
- else:
- quoted_path = urllib.quote(abs_path)
- return 'file://' + quoted_path
-
- @staticmethod
- def GetFileURLForDataPath(*relative_path):
- """Get file:// url for the given path relative to the chrome test data dir.
-
- Also quotes the url using urllib.quote().
-
- Args:
- relative_path: Variable number of strings that can be joined.
- """
- return PyUITest.GetFileURLForPath(PyUITest.DataDir(), *relative_path)
-
- @staticmethod
- def GetHttpURLForDataPath(*relative_path):
- """Get http:// url for the given path in the data dir.
-
- The URL will be usable only after starting the http server.
- """
- global _HTTP_SERVER
- assert _HTTP_SERVER, 'HTTP Server not yet started'
- return _HTTP_SERVER.GetURL(os.path.join('files', *relative_path)).spec()
-
- @staticmethod
- def ContentDataDir():
- """Get path to content/test/data."""
- return os.path.join(PyUITest.DataDir(), os.pardir, os.pardir, os.pardir,
- 'content', 'test', 'data')
-
- @staticmethod
- def GetFileURLForContentDataPath(*relative_path):
- """Get file:// url for the given path relative to content test data dir.
-
- Also quotes the url using urllib.quote().
-
- Args:
- relative_path: Variable number of strings that can be joined.
- """
- return PyUITest.GetFileURLForPath(PyUITest.ContentDataDir(), *relative_path)
-
- @staticmethod
- def GetFtpURLForDataPath(ftp_server, *relative_path):
- """Get ftp:// url for the given path in the data dir.
-
- Args:
- ftp_server: handle to ftp server, an instance of SpawnedTestServer
- relative_path: any number of path elements
-
- The URL will be usable only after starting the ftp server.
- """
- assert ftp_server, 'FTP Server not yet started'
- return ftp_server.GetURL(os.path.join(*relative_path)).spec()
-
- @staticmethod
- def IsMac():
- """Are we on Mac?"""
- return 'darwin' == sys.platform
-
- @staticmethod
- def IsLinux():
- """Are we on Linux? ChromeOS is linux too."""
- return sys.platform.startswith('linux')
-
- @staticmethod
- def IsWin():
- """Are we on Win?"""
- return 'win32' == sys.platform
-
- @staticmethod
- def IsWin7():
- """Are we on Windows 7?"""
- if not PyUITest.IsWin():
- return False
- ver = sys.getwindowsversion()
- return (ver[3], ver[0], ver[1]) == (2, 6, 1)
-
- @staticmethod
- def IsWinVista():
- """Are we on Windows Vista?"""
- if not PyUITest.IsWin():
- return False
- ver = sys.getwindowsversion()
- return (ver[3], ver[0], ver[1]) == (2, 6, 0)
-
- @staticmethod
- def IsWinXP():
- """Are we on Windows XP?"""
- if not PyUITest.IsWin():
- return False
- ver = sys.getwindowsversion()
- return (ver[3], ver[0], ver[1]) == (2, 5, 1)
-
- @staticmethod
- def IsChromeOS():
- """Are we on ChromeOS (or Chromium OS)?
-
- Checks for "CHROMEOS_RELEASE_NAME=" in /etc/lsb-release.
- """
- lsb_release = '/etc/lsb-release'
- if not PyUITest.IsLinux() or not os.path.isfile(lsb_release):
- return False
- for line in open(lsb_release).readlines():
- if line.startswith('CHROMEOS_RELEASE_NAME='):
- return True
- return False
-
- @staticmethod
- def IsPosix():
- """Are we on Mac/Linux?"""
- return PyUITest.IsMac() or PyUITest.IsLinux()
-
- @staticmethod
- def IsEnUS():
- """Are we en-US?"""
- # TODO: figure out the machine's langugage.
- return True
-
- @staticmethod
- def GetPlatform():
- """Return the platform name."""
- # Since ChromeOS is also Linux, we check for it first.
- if PyUITest.IsChromeOS():
- return 'chromeos'
- elif PyUITest.IsLinux():
- return 'linux'
- elif PyUITest.IsMac():
- return 'mac'
- elif PyUITest.IsWin():
- return 'win'
- else:
- return 'unknown'
-
- @staticmethod
- def EvalDataFrom(filename):
- """Return eval of python code from given file.
-
- The datastructure used in the file will be preserved.
- """
- data_file = os.path.join(filename)
- contents = open(data_file).read()
- try:
- ret = eval(contents)
- except:
- print >>sys.stderr, '%s is an invalid data file.' % data_file
- raise
- return ret
-
- @staticmethod
- def ChromeOSBoard():
- """What is the ChromeOS board name"""
- if PyUITest.IsChromeOS():
- for line in open('/etc/lsb-release'):
- line = line.strip()
- if line.startswith('CHROMEOS_RELEASE_BOARD='):
- return line.split('=')[1]
- return None
-
- @staticmethod
- def Kill(pid):
- """Terminate the given pid.
-
- If the pid refers to a renderer, use KillRendererProcess instead.
- """
- if PyUITest.IsWin():
- subprocess.call(['taskkill.exe', '/T', '/F', '/PID', str(pid)])
- else:
- os.kill(pid, signal.SIGTERM)
-
- @staticmethod
- def GetPrivateInfo():
- """Fetch info from private_tests_info.txt in private dir.
-
- Returns:
- a dictionary of items from private_tests_info.txt
- """
- private_file = os.path.join(
- PyUITest.DataDir(), 'pyauto_private', 'private_tests_info.txt')
- assert os.path.exists(private_file), '%s missing' % private_file
- return PyUITest.EvalDataFrom(private_file)
-
- def WaitUntil(self, function, timeout=-1, retry_sleep=0.25, args=[],
- expect_retval=None, return_retval=False, debug=True):
- """Poll on a condition until timeout.
-
- Waits until the |function| evalues to |expect_retval| or until |timeout|
- secs, whichever occurs earlier.
-
- This is better than using a sleep, since it waits (almost) only as much
- as needed.
-
- WARNING: This method call should be avoided as far as possible in favor
- of a real wait from chromium (like wait-until-page-loaded).
- Only use in case there's really no better option.
-
- EXAMPLES:-
- Wait for "file.txt" to get created:
- WaitUntil(os.path.exists, args=["file.txt"])
-
- Same as above, but using lambda:
- WaitUntil(lambda: os.path.exists("file.txt"))
-
- Args:
- function: the function whose truth value is to be evaluated
- timeout: the max timeout (in secs) for which to wait. The default
- action is to wait for kWaitForActionMaxMsec, as set in
- ui_test.cc
- Use None to wait indefinitely.
- retry_sleep: the sleep interval (in secs) before retrying |function|.
- Defaults to 0.25 secs.
- args: the args to pass to |function|
- expect_retval: the expected return value for |function|. This forms the
- exit criteria. In case this is None (the default),
- |function|'s return value is checked for truth,
- so 'non-empty-string' should match with True
- return_retval: If True, return the value returned by the last call to
- |function()|
- debug: if True, displays debug info at each retry.
-
- Returns:
- The return value of the |function| (when return_retval == True)
- True, if returning when |function| evaluated to True (when
- return_retval == False)
- False, when returning due to timeout
- """
- if timeout == -1: # Default
- timeout = self._automation_timeout / 1000.0
- assert callable(function), "function should be a callable"
- begin = time.time()
- debug_begin = begin
- retval = None
- while timeout is None or time.time() - begin <= timeout:
- retval = function(*args)
- if (expect_retval is None and retval) or \
- (expect_retval is not None and expect_retval == retval):
- return retval if return_retval else True
- if debug and time.time() - debug_begin > 5:
- debug_begin += 5
- if function.func_name == (lambda: True).func_name:
- function_info = inspect.getsource(function).strip()
- else:
- function_info = '%s()' % function.func_name
- logging.debug('WaitUntil(%s:%d %s) still waiting. '
- 'Expecting %s. Last returned %s.',
- os.path.basename(inspect.getsourcefile(function)),
- inspect.getsourcelines(function)[1],
- function_info,
- True if expect_retval is None else expect_retval,
- retval)
- time.sleep(retry_sleep)
- return retval if return_retval else False
-
- def StartFTPServer(self, data_dir):
- """Start a local file server hosting data files over ftp://
-
- Args:
- data_dir: path where ftp files should be served
-
- Returns:
- handle to FTP Server, an instance of SpawnedTestServer
- """
- ftp_server = pyautolib.SpawnedTestServer(
- pyautolib.SpawnedTestServer.TYPE_FTP,
- '127.0.0.1',
- pyautolib.FilePath(data_dir))
- assert ftp_server.Start(), 'Could not start ftp server'
- logging.debug('Started ftp server at "%s".', data_dir)
- return ftp_server
-
- def StopFTPServer(self, ftp_server):
- """Stop the local ftp server."""
- assert ftp_server, 'FTP Server not yet started'
- assert ftp_server.Stop(), 'Could not stop ftp server'
- logging.debug('Stopped ftp server.')
-
- def StartHTTPServer(self, data_dir):
- """Starts a local HTTP SpawnedTestServer serving files from |data_dir|.
-
- Args:
- data_dir: path where the SpawnedTestServer should serve files from.
- This will be appended to the source dir to get the final document root.
-
- Returns:
- handle to the HTTP SpawnedTestServer
- """
- http_server = pyautolib.SpawnedTestServer(
- pyautolib.SpawnedTestServer.TYPE_HTTP,
- '127.0.0.1',
- pyautolib.FilePath(data_dir))
- assert http_server.Start(), 'Could not start HTTP server'
- logging.debug('Started HTTP server at "%s".', data_dir)
- return http_server
-
- def StopHTTPServer(self, http_server):
- assert http_server, 'HTTP server not yet started'
- assert http_server.Stop(), 'Cloud not stop the HTTP server'
- logging.debug('Stopped HTTP server.')
-
- def StartHttpsServer(self, cert_type, data_dir):
- """Starts a local HTTPS SpawnedTestServer serving files from |data_dir|.
-
- Args:
- cert_type: An instance of SSLOptions.ServerCertificate for three
- certificate types: ok, expired, or mismatch.
- data_dir: The path where SpawnedTestServer should serve files from.
- This is appended to the source dir to get the final
- document root.
-
- Returns:
- Handle to the HTTPS SpawnedTestServer
- """
- https_server = pyautolib.SpawnedTestServer(
- pyautolib.SpawnedTestServer.TYPE_HTTPS,
- pyautolib.SSLOptions(cert_type),
- pyautolib.FilePath(data_dir))
- assert https_server.Start(), 'Could not start HTTPS server.'
- logging.debug('Start HTTPS server at "%s".' % data_dir)
- return https_server
-
- def StopHttpsServer(self, https_server):
- assert https_server, 'HTTPS server not yet started.'
- assert https_server.Stop(), 'Could not stop the HTTPS server.'
- logging.debug('Stopped HTTPS server.')
-
- class ActionTimeoutChanger(object):
- """Facilitate temporary changes to PyAuto command timeout.
-
- Automatically resets to original timeout when object is destroyed.
- """
- _saved_timeout = -1 # Saved timeout value
-
- def __init__(self, ui_test, new_timeout):
- """Initialize.
-
- Args:
- ui_test: a PyUITest object
- new_timeout: new timeout to use (in milli secs)
- """
- self._saved_timeout = ui_test._automation_timeout
- ui_test._automation_timeout = new_timeout
- self._ui_test = ui_test
-
- def __del__(self):
- """Reset command_execution_timeout_ms to original value."""
- self._ui_test._automation_timeout = self._saved_timeout
-
- class JavascriptExecutor(object):
- """Abstract base class for JavaScript injection.
-
- Derived classes should override Execute method."""
- def Execute(self, script):
- pass
-
- class JavascriptExecutorInTab(JavascriptExecutor):
- """Wrapper for injecting JavaScript in a tab."""
- def __init__(self, ui_test, tab_index=0, windex=0, frame_xpath=''):
- """Initialize.
-
- Refer to ExecuteJavascript() for the complete argument list
- description.
-
- Args:
- ui_test: a PyUITest object
- """
- self._ui_test = ui_test
- self.windex = windex
- self.tab_index = tab_index
- self.frame_xpath = frame_xpath
-
- def Execute(self, script):
- """Execute script in the tab."""
- return self._ui_test.ExecuteJavascript(script,
- self.tab_index,
- self.windex,
- self.frame_xpath)
-
- class JavascriptExecutorInRenderView(JavascriptExecutor):
- """Wrapper for injecting JavaScript in an extension view."""
- def __init__(self, ui_test, view, frame_xpath=''):
- """Initialize.
-
- Refer to ExecuteJavascriptInRenderView() for the complete argument list
- description.
-
- Args:
- ui_test: a PyUITest object
- """
- self._ui_test = ui_test
- self.view = view
- self.frame_xpath = frame_xpath
-
- def Execute(self, script):
- """Execute script in the render view."""
- return self._ui_test.ExecuteJavascriptInRenderView(script,
- self.view,
- self.frame_xpath)
-
- def _GetResultFromJSONRequestDiagnostics(self):
- """Same as _GetResultFromJSONRequest without throwing a timeout exception.
-
- This method is used to diagnose if a command returns without causing a
- timout exception to be thrown. This should be used for debugging purposes
- only.
-
- Returns:
- True if the request returned; False if it timed out.
- """
- result = self._SendJSONRequest(-1,
- json.dumps({'command': 'GetBrowserInfo',}),
- self._automation_timeout)
- if not result:
- # The diagnostic command did not complete, Chrome is probably in a bad
- # state
- return False
- return True
-
- def _GetResultFromJSONRequest(self, cmd_dict, windex=0, timeout=-1):
- """Issue call over the JSON automation channel and fetch output.
-
- This method packages the given dictionary into a json string, sends it
- over the JSON automation channel, loads the json output string returned,
- and returns it back as a dictionary.
-
- Args:
- cmd_dict: the command dictionary. It must have a 'command' key
- Sample:
- {
- 'command': 'SetOmniboxText',
- 'text': text,
- }
- windex: 0-based window index on which to work. Default: 0 (first window)
- Use -ve windex or None if the automation command does not apply
- to a browser window. Example: for chromeos login
-
- timeout: request timeout (in milliseconds)
-
- Returns:
- a dictionary for the output returned by the automation channel.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- if timeout == -1: # Default
- timeout = self._automation_timeout
- if windex is None: # Do not target any window
- windex = -1
- result = self._SendJSONRequest(windex, json.dumps(cmd_dict), timeout)
- if not result:
- additional_info = 'No information available.'
- # Windows does not support os.kill until Python 2.7.
- if not self.IsWin() and _BROWSER_PID:
- browser_pid_exists = True
- # Does the browser PID exist?
- try:
- # Does not actually kill the process
- os.kill(int(_BROWSER_PID), 0)
- except OSError:
- browser_pid_exists = False
- if browser_pid_exists:
- if self._GetResultFromJSONRequestDiagnostics():
- # Browser info, worked, that means this hook had a problem
- additional_info = ('The browser process ID %d still exists. '
- 'PyAuto was able to obtain browser info. It '
- 'is possible this hook is broken.'
- % _BROWSER_PID)
- else:
- additional_info = ('The browser process ID %d still exists. '
- 'PyAuto was not able to obtain browser info. '
- 'It is possible the browser is hung.'
- % _BROWSER_PID)
- else:
- additional_info = ('The browser process ID %d no longer exists. '
- 'Perhaps the browser crashed.' % _BROWSER_PID)
- elif not _BROWSER_PID:
- additional_info = ('The browser PID was not obtained. Does this test '
- 'have a unique startup configuration?')
- # Mask private data if it is in the JSON dictionary
- cmd_dict_copy = copy.copy(cmd_dict)
- if 'password' in cmd_dict_copy.keys():
- cmd_dict_copy['password'] = '**********'
- if 'username' in cmd_dict_copy.keys():
- cmd_dict_copy['username'] = 'removed_username'
- raise JSONInterfaceError('Automation call %s received empty response. '
- 'Additional information:\n%s' % (cmd_dict_copy,
- additional_info))
- ret_dict = json.loads(result)
- if ret_dict.has_key('error'):
- if ret_dict.get('is_interface_timeout'):
- raise AutomationCommandTimeout(ret_dict['error'])
- elif ret_dict.get('is_interface_error'):
- raise JSONInterfaceError(ret_dict['error'])
- else:
- raise AutomationCommandFail(ret_dict['error'])
- return ret_dict
-
- def NavigateToURL(self, url, windex=0, tab_index=None, navigation_count=1):
- """Navigate the given tab to the given URL.
-
- Note that this method also activates the corresponding tab/window if it's
- not active already. Blocks until |navigation_count| navigations have
- completed.
-
- Args:
- url: The URL to which to navigate, can be a string or GURL object.
- windex: The index of the browser window to work on. Defaults to the first
- window.
- tab_index: The index of the tab to work on. Defaults to the active tab.
- navigation_count: the number of navigations to wait for. Defaults to 1.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- if isinstance(url, GURL):
- url = url.spec()
- if tab_index is None:
- tab_index = self.GetActiveTabIndex(windex)
- cmd_dict = {
- 'command': 'NavigateToURL',
- 'url': url,
- 'windex': windex,
- 'tab_index': tab_index,
- 'navigation_count': navigation_count,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def NavigateToURLAsync(self, url, windex=0, tab_index=None):
- """Initiate a URL navigation.
-
- A wrapper for NavigateToURL with navigation_count set to 0.
- """
- self.NavigateToURL(url, windex, tab_index, 0)
-
- def ApplyAccelerator(self, accelerator, windex=0):
- """Apply the accelerator with the given id.
-
- Note that this method schedules the accelerator, but does not wait for it to
- actually finish doing anything.
-
- Args:
- accelerator: The accelerator id, IDC_BACK, IDC_NEWTAB, etc. The list of
- ids can be found at chrome/app/chrome_command_ids.h.
- windex: The index of the browser window to work on. Defaults to the first
- window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
-
- cmd_dict = {
- 'command': 'ApplyAccelerator',
- 'accelerator': accelerator,
- 'windex': windex,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def RunCommand(self, accelerator, windex=0):
- """Apply the accelerator with the given id and wait for it to finish.
-
- This is like ApplyAccelerator except that it waits for the command to finish
- executing.
-
- Args:
- accelerator: The accelerator id. The list of ids can be found at
- chrome/app/chrome_command_ids.h.
- windex: The index of the browser window to work on. Defaults to the first
- window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'RunCommand',
- 'accelerator': accelerator,
- 'windex': windex,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def IsMenuCommandEnabled(self, accelerator, windex=0):
- """Check if a command is enabled for a window.
-
- Returns true if the command with the given accelerator id is enabled on the
- given window.
-
- Args:
- accelerator: The accelerator id. The list of ids can be found at
- chrome/app/chrome_command_ids.h.
- windex: The index of the browser window to work on. Defaults to the first
- window.
-
- Returns:
- True if the command is enabled for the given window.
- """
- cmd_dict = {
- 'command': 'IsMenuCommandEnabled',
- 'accelerator': accelerator,
- 'windex': windex,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None).get('enabled')
-
- def TabGoForward(self, tab_index=0, windex=0):
- """Navigate a tab forward in history.
-
- Equivalent to clicking the Forward button in the UI. Activates the tab as a
- side effect.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- self.ActivateTab(tab_index, windex)
- self.RunCommand(IDC_FORWARD, windex)
-
- def TabGoBack(self, tab_index=0, windex=0):
- """Navigate a tab backwards in history.
-
- Equivalent to clicking the Back button in the UI. Activates the tab as a
- side effect.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- self.ActivateTab(tab_index, windex)
- self.RunCommand(IDC_BACK, windex)
-
- def ReloadTab(self, tab_index=0, windex=0):
- """Reload the given tab.
-
- Blocks until the page has reloaded.
-
- Args:
- tab_index: The index of the tab to reload. Defaults to 0.
- windex: The index of the browser window to work on. Defaults to the first
- window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- self.ActivateTab(tab_index, windex)
- self.RunCommand(IDC_RELOAD, windex)
-
- def CloseTab(self, tab_index=0, windex=0, wait_until_closed=True):
- """Close the given tab.
-
- Note: Be careful closing the last tab in a window as it may close the
- browser.
-
- Args:
- tab_index: The index of the tab to reload. Defaults to 0.
- windex: The index of the browser window to work on. Defaults to the first
- window.
- wait_until_closed: Whether to block until the tab finishes closing.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'CloseTab',
- 'tab_index': tab_index,
- 'windex': windex,
- 'wait_until_closed': wait_until_closed,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def WaitForTabToBeRestored(self, tab_index=0, windex=0, timeout=-1):
- """Wait for the given tab to be restored.
-
- Args:
- tab_index: The index of the tab to reload. Defaults to 0.
- windex: The index of the browser window to work on. Defaults to the first
- window.
- timeout: Timeout in milliseconds.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'CloseTab',
- 'tab_index': tab_index,
- 'windex': windex,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None, timeout=timeout)
-
- def ReloadActiveTab(self, windex=0):
- """Reload an active tab.
-
- Warning: Depending on the concept of an active tab is dangerous as it can
- change during the test. Use ReloadTab and supply a tab_index explicitly.
-
- Args:
- windex: The index of the browser window to work on. Defaults to the first
- window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- self.ReloadTab(self.GetActiveTabIndex(windex), windex)
-
- def GetActiveTabIndex(self, windex=0):
- """Get the index of the currently active tab in the given browser window.
-
- Warning: Depending on the concept of an active tab is dangerous as it can
- change during the test. Supply the tab_index explicitly, if possible.
-
- Args:
- windex: The index of the browser window to work on. Defaults to the first
- window.
-
- Returns:
- An integer index for the currently active tab.
- """
- cmd_dict = {
- 'command': 'GetActiveTabIndex',
- 'windex': windex,
- }
- return self._GetResultFromJSONRequest(cmd_dict,
- windex=None).get('tab_index')
-
- def ActivateTab(self, tab_index=0, windex=0):
- """Activates the given tab in the specified window.
-
- Warning: Depending on the concept of an active tab is dangerous as it can
- change during the test. Instead use functions that accept a tab_index
- explicitly.
-
- Args:
- tab_index: Integer index of the tab to activate; defaults to 0.
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'ActivateTab',
- 'tab_index': tab_index,
- 'windex': windex,
- }
- self.BringBrowserToFront(windex)
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def BringBrowserToFront(self, windex=0):
- """Activate the browser's window and bring it to front.
-
- Args:
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'BringBrowserToFront',
- 'windex': windex,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def GetBrowserWindowCount(self):
- """Get the browser window count.
-
- Args:
- None.
-
- Returns:
- Integer count of the number of browser windows. Includes popups.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {'command': 'GetBrowserWindowCount'}
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)['count']
-
- def OpenNewBrowserWindow(self, show):
- """Create a new browser window.
-
- Args:
- show: Boolean indicating whether to show the window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'OpenNewBrowserWindow',
- 'show': show,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def CloseBrowserWindow(self, windex=0):
- """Create a new browser window.
-
- Args:
- windex: Index of the browser window to close; defaults to 0.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'CloseBrowserWindow',
- 'windex': windex,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def AppendTab(self, url, windex=0):
- """Append a new tab.
-
- Creates a new tab at the end of given browser window and activates
- it. Blocks until the specified |url| is loaded.
-
- Args:
- url: The url to load, can be string or a GURL object.
- windex: The index of the browser window to work on. Defaults to the first
- window.
-
- Returns:
- True if the url loads successfully in the new tab. False otherwise.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- if isinstance(url, GURL):
- url = url.spec()
- cmd_dict = {
- 'command': 'AppendTab',
- 'url': url,
- 'windex': windex,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None).get('result')
-
- def GetTabCount(self, windex=0):
- """Gets the number of tab in the given browser window.
-
- Args:
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Returns:
- The tab count.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'GetTabCount',
- 'windex': windex,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)['tab_count']
-
- def GetTabInfo(self, tab_index=0, windex=0):
- """Gets information about the specified tab.
-
- Args:
- tab_index: Integer index of the tab to activate; defaults to 0.
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Returns:
- A dictionary containing information about the tab.
- Example:
- { u'title': "Hello World",
- u'url': "http://foo.bar", }
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'GetTabInfo',
- 'tab_index': tab_index,
- 'windex': windex,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def GetActiveTabTitle(self, windex=0):
- """Gets the title of the active tab.
-
- Warning: Depending on the concept of an active tab is dangerous as it can
- change during the test. Use GetTabInfo and supply a tab_index explicitly.
-
- Args:
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Returns:
- The tab title as a string.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- return self.GetTabInfo(self.GetActiveTabIndex(windex), windex)['title']
-
- def GetActiveTabURL(self, windex=0):
- """Gets the URL of the active tab.
-
- Warning: Depending on the concept of an active tab is dangerous as it can
- change during the test. Use GetTabInfo and supply a tab_index explicitly.
-
- Args:
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Returns:
- The tab URL as a GURL object.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- return GURL(str(self.GetTabInfo(self.GetActiveTabIndex(windex),
- windex)['url']))
-
- def ActionOnSSLBlockingPage(self, tab_index=0, windex=0, proceed=True):
- """Take action on an interstitial page.
-
- Calling this when an interstitial page is not showing is an error.
-
- Args:
- tab_index: Integer index of the tab to activate; defaults to 0.
- windex: Integer index of the browser window to use; defaults to the first
- window.
- proceed: Whether to proceed to the URL or not.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'ActionOnSSLBlockingPage',
- 'tab_index': tab_index,
- 'windex': windex,
- 'proceed': proceed,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def GetBookmarkModel(self, windex=0):
- """Return the bookmark model as a BookmarkModel object.
-
- This is a snapshot of the bookmark model; it is not a proxy and
- does not get updated as the bookmark model changes.
- """
- bookmarks_as_json = self._GetBookmarksAsJSON(windex)
- if not bookmarks_as_json:
- raise JSONInterfaceError('Could not resolve browser proxy.')
- return bookmark_model.BookmarkModel(bookmarks_as_json)
-
- def _GetBookmarksAsJSON(self, windex=0):
- """Get bookmarks as a JSON dictionary; used by GetBookmarkModel()."""
- cmd_dict = {
- 'command': 'GetBookmarksAsJSON',
- 'windex': windex,
- }
- self.WaitForBookmarkModelToLoad(windex)
- return self._GetResultFromJSONRequest(cmd_dict,
- windex=None)['bookmarks_as_json']
-
- def WaitForBookmarkModelToLoad(self, windex=0):
- """Gets the status of the bookmark bar as a dictionary.
-
- Args:
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'WaitForBookmarkModelToLoad',
- 'windex': windex,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def GetBookmarkBarStatus(self, windex=0):
- """Gets the status of the bookmark bar as a dictionary.
-
- Args:
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Returns:
- A dictionary.
- Example:
- { u'visible': True,
- u'animating': False,
- u'detached': False, }
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'GetBookmarkBarStatus',
- 'windex': windex,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def GetBookmarkBarStatus(self, windex=0):
- """Gets the status of the bookmark bar as a dictionary.
-
- Args:
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Returns:
- A dictionary.
- Example:
- { u'visible': True,
- u'animating': False,
- u'detached': False, }
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'GetBookmarkBarStatus',
- 'windex': windex,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def GetBookmarkBarStatus(self, windex=0):
- """Gets the status of the bookmark bar as a dictionary.
-
- Args:
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Returns:
- A dictionary.
- Example:
- { u'visible': True,
- u'animating': False,
- u'detached': False, }
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'GetBookmarkBarStatus',
- 'windex': windex,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def GetBookmarkBarVisibility(self, windex=0):
- """Returns the visibility of the bookmark bar.
-
- Args:
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Returns:
- True if the bookmark bar is visible, false otherwise.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- return self.GetBookmarkBarStatus(windex)['visible']
-
- def AddBookmarkGroup(self, parent_id, index, title, windex=0):
- """Adds a bookmark folder.
-
- Args:
- parent_id: The parent bookmark folder.
- index: The location in the parent's list to insert this bookmark folder.
- title: The name of the bookmark folder.
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Returns:
- True if the bookmark bar is detached, false otherwise.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- if isinstance(parent_id, basestring):
- parent_id = int(parent_id)
- cmd_dict = {
- 'command': 'AddBookmark',
- 'parent_id': parent_id,
- 'index': index,
- 'title': title,
- 'is_folder': True,
- 'windex': windex,
- }
- self.WaitForBookmarkModelToLoad(windex)
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def AddBookmarkURL(self, parent_id, index, title, url, windex=0):
- """Add a bookmark URL.
-
- Args:
- parent_id: The parent bookmark folder.
- index: The location in the parent's list to insert this bookmark.
- title: The name of the bookmark.
- url: The url of the bookmark.
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- if isinstance(parent_id, basestring):
- parent_id = int(parent_id)
- cmd_dict = {
- 'command': 'AddBookmark',
- 'parent_id': parent_id,
- 'index': index,
- 'title': title,
- 'url': url,
- 'is_folder': False,
- 'windex': windex,
- }
- self.WaitForBookmarkModelToLoad(windex)
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def ReparentBookmark(self, id, new_parent_id, index, windex=0):
- """Move a bookmark.
-
- Args:
- id: The bookmark to move.
- new_parent_id: The new parent bookmark folder.
- index: The location in the parent's list to insert this bookmark.
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- if isinstance(id, basestring):
- id = int(id)
- if isinstance(new_parent_id, basestring):
- new_parent_id = int(new_parent_id)
- cmd_dict = {
- 'command': 'ReparentBookmark',
- 'id': id,
- 'new_parent_id': new_parent_id,
- 'index': index,
- 'windex': windex,
- }
- self.WaitForBookmarkModelToLoad(windex)
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def SetBookmarkTitle(self, id, title, windex=0):
- """Change the title of a bookmark.
-
- Args:
- id: The bookmark to rename.
- title: The new title for the bookmark.
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- if isinstance(id, basestring):
- id = int(id)
- cmd_dict = {
- 'command': 'SetBookmarkTitle',
- 'id': id,
- 'title': title,
- 'windex': windex,
- }
- self.WaitForBookmarkModelToLoad(windex)
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def SetBookmarkURL(self, id, url, windex=0):
- """Change the URL of a bookmark.
-
- Args:
- id: The bookmark to change.
- url: The new url for the bookmark.
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- if isinstance(id, basestring):
- id = int(id)
- cmd_dict = {
- 'command': 'SetBookmarkURL',
- 'id': id,
- 'url': url,
- 'windex': windex,
- }
- self.WaitForBookmarkModelToLoad(windex)
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def RemoveBookmark(self, id, windex=0):
- """Remove a bookmark.
-
- Args:
- id: The bookmark to remove.
- windex: Integer index of the browser window to use; defaults to the first
- window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- if isinstance(id, basestring):
- id = int(id)
- cmd_dict = {
- 'command': 'RemoveBookmark',
- 'id': id,
- 'windex': windex,
- }
- self.WaitForBookmarkModelToLoad(windex)
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def GetDownloadsInfo(self, windex=0):
- """Return info about downloads.
-
- This includes all the downloads recognized by the history system.
-
- Returns:
- an instance of downloads_info.DownloadInfo
- """
- return download_info.DownloadInfo(
- self._GetResultFromJSONRequest({'command': 'GetDownloadsInfo'},
- windex=windex))
-
- def GetOmniboxInfo(self, windex=0):
- """Return info about Omnibox.
-
- This represents a snapshot of the omnibox. If you expect changes
- you need to call this method again to get a fresh snapshot.
- Note that this DOES NOT shift focus to the omnibox; you've to ensure that
- the omnibox is in focus or else you won't get any interesting info.
-
- It's OK to call this even when the omnibox popup is not showing. In this
- case however, there won't be any matches, but other properties (like the
- current text in the omnibox) will still be fetched.
-
- Due to the nature of the omnibox, this function is sensitive to mouse
- focus. DO NOT HOVER MOUSE OVER OMNIBOX OR CHANGE WINDOW FOCUS WHEN USING
- THIS METHOD.
-
- Args:
- windex: the index of the browser window to work on.
- Default: 0 (first window)
-
- Returns:
- an instance of omnibox_info.OmniboxInfo
- """
- return omnibox_info.OmniboxInfo(
- self._GetResultFromJSONRequest({'command': 'GetOmniboxInfo'},
- windex=windex))
-
- def SetOmniboxText(self, text, windex=0):
- """Enter text into the omnibox. This shifts focus to the omnibox.
-
- Args:
- text: the text to be set.
- windex: the index of the browser window to work on.
- Default: 0 (first window)
- """
- # Ensure that keyword data is loaded from the profile.
- # This would normally be triggered by the user inputting this text.
- self._GetResultFromJSONRequest({'command': 'LoadSearchEngineInfo'})
- cmd_dict = {
- 'command': 'SetOmniboxText',
- 'text': text,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=windex)
-
- # TODO(ace): Remove this hack, update bug 62783.
- def WaitUntilOmniboxReadyHack(self, windex=0):
- """Wait until the omnibox is ready for input.
-
- This is a hack workaround for linux platform, which returns from
- synchronous window creation methods before the omnibox is fully functional.
-
- No-op on non-linux platforms.
-
- Args:
- windex: the index of the browser to work on.
- """
- if self.IsLinux():
- return self.WaitUntil(
- lambda : self.GetOmniboxInfo(windex).Properties('has_focus'))
-
- def WaitUntilOmniboxQueryDone(self, windex=0):
- """Wait until omnibox has finished populating results.
-
- Uses WaitUntil() so the wait duration is capped by the timeout values
- used by automation, which WaitUntil() uses.
-
- Args:
- windex: the index of the browser window to work on.
- Default: 0 (first window)
- """
- return self.WaitUntil(
- lambda : not self.GetOmniboxInfo(windex).IsQueryInProgress())
-
- def OmniboxMovePopupSelection(self, count, windex=0):
- """Move omnibox popup selection up or down.
-
- Args:
- count: number of rows by which to move.
- -ve implies down, +ve implies up
- windex: the index of the browser window to work on.
- Default: 0 (first window)
- """
- cmd_dict = {
- 'command': 'OmniboxMovePopupSelection',
- 'count': count,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=windex)
-
- def OmniboxAcceptInput(self, windex=0):
- """Accepts the current string of text in the omnibox.
-
- This is equivalent to clicking or hiting enter on a popup selection.
- Blocks until the page loads.
-
- Args:
- windex: the index of the browser window to work on.
- Default: 0 (first window)
- """
- cmd_dict = {
- 'command': 'OmniboxAcceptInput',
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=windex)
-
- def GetCookie(self, url, windex=0):
- """Get the value of the cookie at url in context of the specified browser.
-
- Args:
- url: Either a GURL object or url string specifing the cookie url.
- windex: The index of the browser window to work on. Defaults to the first
- window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- if isinstance(url, GURL):
- url = url.spec()
- cmd_dict = {
- 'command': 'GetCookiesInBrowserContext',
- 'url': url,
- 'windex': windex,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)['cookies']
-
- def DeleteCookie(self, url, cookie_name, windex=0):
- """Delete the cookie at url with name cookie_name.
-
- Args:
- url: Either a GURL object or url string specifing the cookie url.
- cookie_name: The name of the cookie to delete as a string.
- windex: The index of the browser window to work on. Defaults to the first
- window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- if isinstance(url, GURL):
- url = url.spec()
- cmd_dict = {
- 'command': 'DeleteCookieInBrowserContext',
- 'url': url,
- 'cookie_name': cookie_name,
- 'windex': windex,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def SetCookie(self, url, value, windex=0):
- """Set the value of the cookie at url to value in the context of a browser.
-
- Args:
- url: Either a GURL object or url string specifing the cookie url.
- value: A string to set as the cookie's value.
- windex: The index of the browser window to work on. Defaults to the first
- window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- if isinstance(url, GURL):
- url = url.spec()
- cmd_dict = {
- 'command': 'SetCookieInBrowserContext',
- 'url': url,
- 'value': value,
- 'windex': windex,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def GetSearchEngineInfo(self, windex=0):
- """Return info about search engines.
-
- Args:
- windex: The window index, default is 0.
-
- Returns:
- An ordered list of dictionaries describing info about each search engine.
-
- Example:
- [ { u'display_url': u'{google:baseURL}search?q=%s',
- u'host': u'www.google.com',
- u'in_default_list': True,
- u'is_default': True,
- u'is_valid': True,
- u'keyword': u'google.com',
- u'path': u'/search',
- u'short_name': u'Google',
- u'supports_replacement': True,
- u'url': u'{google:baseURL}search?q={searchTerms}'},
- { u'display_url': u'http://search.yahoo.com/search?p=%s',
- u'host': u'search.yahoo.com',
- u'in_default_list': True,
- u'is_default': False,
- u'is_valid': True,
- u'keyword': u'yahoo.com',
- u'path': u'/search',
- u'short_name': u'Yahoo!',
- u'supports_replacement': True,
- u'url': u'http://search.yahoo.com/search?p={searchTerms}'},
- """
- # Ensure that the search engine profile is loaded into data model.
- self._GetResultFromJSONRequest({'command': 'LoadSearchEngineInfo'},
- windex=windex)
- cmd_dict = {'command': 'GetSearchEngineInfo'}
- return self._GetResultFromJSONRequest(
- cmd_dict, windex=windex)['search_engines']
-
- def AddSearchEngine(self, title, keyword, url, windex=0):
- """Add a search engine, as done through the search engines UI.
-
- Args:
- title: name for search engine.
- keyword: keyword, used to initiate a custom search from omnibox.
- url: url template for this search engine's query.
- '%s' is replaced by search query string when used to search.
- windex: The window index, default is 0.
- """
- # Ensure that the search engine profile is loaded into data model.
- self._GetResultFromJSONRequest({'command': 'LoadSearchEngineInfo'},
- windex=windex)
- cmd_dict = {'command': 'AddOrEditSearchEngine',
- 'new_title': title,
- 'new_keyword': keyword,
- 'new_url': url}
- self._GetResultFromJSONRequest(cmd_dict, windex=windex)
-
- def EditSearchEngine(self, keyword, new_title, new_keyword, new_url,
- windex=0):
- """Edit info for existing search engine.
-
- Args:
- keyword: existing search engine keyword.
- new_title: new name for this search engine.
- new_keyword: new keyword for this search engine.
- new_url: new url for this search engine.
- windex: The window index, default is 0.
- """
- # Ensure that the search engine profile is loaded into data model.
- self._GetResultFromJSONRequest({'command': 'LoadSearchEngineInfo'},
- windex=windex)
- cmd_dict = {'command': 'AddOrEditSearchEngine',
- 'keyword': keyword,
- 'new_title': new_title,
- 'new_keyword': new_keyword,
- 'new_url': new_url}
- self._GetResultFromJSONRequest(cmd_dict, windex=windex)
-
- def DeleteSearchEngine(self, keyword, windex=0):
- """Delete search engine with given keyword.
-
- Args:
- keyword: the keyword string of the search engine to delete.
- windex: The window index, default is 0.
- """
- # Ensure that the search engine profile is loaded into data model.
- self._GetResultFromJSONRequest({'command': 'LoadSearchEngineInfo'},
- windex=windex)
- cmd_dict = {'command': 'PerformActionOnSearchEngine', 'keyword': keyword,
- 'action': 'delete'}
- self._GetResultFromJSONRequest(cmd_dict, windex=windex)
-
- def MakeSearchEngineDefault(self, keyword, windex=0):
- """Make search engine with given keyword the default search.
-
- Args:
- keyword: the keyword string of the search engine to make default.
- windex: The window index, default is 0.
- """
- # Ensure that the search engine profile is loaded into data model.
- self._GetResultFromJSONRequest({'command': 'LoadSearchEngineInfo'},
- windex=windex)
- cmd_dict = {'command': 'PerformActionOnSearchEngine', 'keyword': keyword,
- 'action': 'default'}
- self._GetResultFromJSONRequest(cmd_dict, windex=windex)
-
- def GetLocalStatePrefsInfo(self):
- """Return info about preferences.
-
- This represents a snapshot of the local state preferences. If you expect
- local state preferences to have changed, you need to call this method again
- to get a fresh snapshot.
-
- Returns:
- an instance of prefs_info.PrefsInfo
- """
- return prefs_info.PrefsInfo(
- self._GetResultFromJSONRequest({'command': 'GetLocalStatePrefsInfo'},
- windex=None))
-
- def SetLocalStatePrefs(self, path, value):
- """Set local state preference for the given path.
-
- Preferences are stored by Chromium as a hierarchical dictionary.
- dot-separated paths can be used to refer to a particular preference.
- example: "session.restore_on_startup"
-
- Some preferences are managed, that is, they cannot be changed by the
- user. It's up to the user to know which ones can be changed. Typically,
- the options available via Chromium preferences can be changed.
-
- Args:
- path: the path the preference key that needs to be changed
- example: "session.restore_on_startup"
- One of the equivalent names in chrome/common/pref_names.h could
- also be used.
- value: the value to be set. It could be plain values like int, bool,
- string or complex ones like list.
- The user has to ensure that the right value is specified for the
- right key. It's useful to dump the preferences first to determine
- what type is expected for a particular preference path.
- """
- cmd_dict = {
- 'command': 'SetLocalStatePrefs',
- 'windex': 0,
- 'path': path,
- 'value': value,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def GetPrefsInfo(self, windex=0):
- """Return info about preferences.
-
- This represents a snapshot of the preferences. If you expect preferences
- to have changed, you need to call this method again to get a fresh
- snapshot.
-
- Args:
- windex: The window index, default is 0.
- Returns:
- an instance of prefs_info.PrefsInfo
- """
- cmd_dict = {
- 'command': 'GetPrefsInfo',
- 'windex': windex,
- }
- return prefs_info.PrefsInfo(
- self._GetResultFromJSONRequest(cmd_dict, windex=None))
-
- def SetPrefs(self, path, value, windex=0):
- """Set preference for the given path.
-
- Preferences are stored by Chromium as a hierarchical dictionary.
- dot-separated paths can be used to refer to a particular preference.
- example: "session.restore_on_startup"
-
- Some preferences are managed, that is, they cannot be changed by the
- user. It's up to the user to know which ones can be changed. Typically,
- the options available via Chromium preferences can be changed.
-
- Args:
- path: the path the preference key that needs to be changed
- example: "session.restore_on_startup"
- One of the equivalent names in chrome/common/pref_names.h could
- also be used.
- value: the value to be set. It could be plain values like int, bool,
- string or complex ones like list.
- The user has to ensure that the right value is specified for the
- right key. It's useful to dump the preferences first to determine
- what type is expected for a particular preference path.
- windex: window index to work on. Defaults to 0 (first window).
- """
- cmd_dict = {
- 'command': 'SetPrefs',
- 'windex': windex,
- 'path': path,
- 'value': value,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def SendWebkitKeyEvent(self, key_type, key_code, tab_index=0, windex=0):
- """Send a webkit key event to the browser.
-
- Args:
- key_type: the raw key type such as 0 for up and 3 for down.
- key_code: the hex value associated with the keypress (virtual key code).
- tab_index: tab index to work on. Defaults to 0 (first tab).
- windex: window index to work on. Defaults to 0 (first window).
- """
- cmd_dict = {
- 'command': 'SendWebkitKeyEvent',
- 'type': key_type,
- 'text': '',
- 'isSystemKey': False,
- 'unmodifiedText': '',
- 'nativeKeyCode': 0,
- 'windowsKeyCode': key_code,
- 'modifiers': 0,
- 'windex': windex,
- 'tab_index': tab_index,
- }
- # Sending request for key event.
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def SendWebkitCharEvent(self, char, tab_index=0, windex=0):
- """Send a webkit char to the browser.
-
- Args:
- char: the char value to be sent to the browser.
- tab_index: tab index to work on. Defaults to 0 (first tab).
- windex: window index to work on. Defaults to 0 (first window).
- """
- cmd_dict = {
- 'command': 'SendWebkitKeyEvent',
- 'type': 2, # kCharType
- 'text': char,
- 'isSystemKey': False,
- 'unmodifiedText': char,
- 'nativeKeyCode': 0,
- 'windowsKeyCode': ord((char).upper()),
- 'modifiers': 0,
- 'windex': windex,
- 'tab_index': tab_index,
- }
- # Sending request for a char.
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def SetDownloadShelfVisible(self, is_visible, windex=0):
- """Set download shelf visibility for the specified browser window.
-
- Args:
- is_visible: A boolean indicating the desired shelf visibility.
- windex: The window index, defaults to 0 (the first window).
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'SetDownloadShelfVisible',
- 'is_visible': is_visible,
- 'windex': windex,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def IsDownloadShelfVisible(self, windex=0):
- """Determine whether the download shelf is visible in the given window.
-
- Args:
- windex: The window index, defaults to 0 (the first window).
-
- Returns:
- A boolean indicating the shelf visibility.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'IsDownloadShelfVisible',
- 'windex': windex,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)['is_visible']
-
- def GetDownloadDirectory(self, tab_index=None, windex=0):
- """Get the path to the download directory.
-
- Warning: Depending on the concept of an active tab is dangerous as it can
- change during the test. Always supply a tab_index explicitly.
-
- Args:
- tab_index: The index of the tab to work on. Defaults to the active tab.
- windex: The index of the browser window to work on. Defaults to 0.
-
- Returns:
- The path to the download directory as a FilePath object.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- if tab_index is None:
- tab_index = self.GetActiveTabIndex(windex)
- cmd_dict = {
- 'command': 'GetDownloadDirectory',
- 'tab_index': tab_index,
- 'windex': windex,
- }
- return FilePath(str(self._GetResultFromJSONRequest(cmd_dict,
- windex=None)['path']))
-
- def WaitForAllDownloadsToComplete(self, pre_download_ids=[], windex=0,
- timeout=-1):
- """Wait for all pending downloads to complete.
-
- This function assumes that any downloads to wait for have already been
- triggered and have started (it is ok if those downloads complete before this
- function is called).
-
- Args:
- pre_download_ids: A list of numbers representing the IDs of downloads that
- exist *before* downloads to wait for have been
- triggered. Defaults to []; use GetDownloadsInfo() to get
- these IDs (only necessary if a test previously
- downloaded files).
- windex: The window index, defaults to 0 (the first window).
- timeout: The maximum amount of time (in milliseconds) to wait for
- downloads to complete.
- """
- cmd_dict = {
- 'command': 'WaitForAllDownloadsToComplete',
- 'pre_download_ids': pre_download_ids,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=windex, timeout=timeout)
-
- def PerformActionOnDownload(self, id, action, window_index=0):
- """Perform the given action on the download with the given id.
-
- Args:
- id: The id of the download.
- action: The action to perform on the download.
- Possible actions:
- 'open': Opens the download (waits until it has completed first).
- 'toggle_open_files_like_this': Toggles the 'Always Open Files
- Of This Type' option.
- 'remove': Removes the file from downloads (not from disk).
- 'decline_dangerous_download': Equivalent to 'Discard' option
- after downloading a dangerous download (ex. an executable).
- 'save_dangerous_download': Equivalent to 'Save' option after
- downloading a dangerous file.
- 'pause': Pause the download. If the download completed before
- this call or is already paused, it's a no-op.
- 'resume': Resume the download. If the download completed before
- this call or was not paused, it's a no-op.
- 'cancel': Cancel the download.
- window_index: The window index, default is 0.
-
- Returns:
- A dictionary representing the updated download item (except in the case
- of 'decline_dangerous_download', 'toggle_open_files_like_this', and
- 'remove', which return an empty dict).
- Example dictionary:
- { u'PercentComplete': 100,
- u'file_name': u'file.txt',
- u'full_path': u'/path/to/file.txt',
- u'id': 0,
- u'is_otr': False,
- u'is_paused': False,
- u'is_temporary': False,
- u'open_when_complete': False,
- u'referrer_url': u'',
- u'state': u'COMPLETE',
- u'danger_type': u'DANGEROUS_FILE',
- u'url': u'file://url/to/file.txt'
- }
- """
- cmd_dict = { # Prepare command for the json interface
- 'command': 'PerformActionOnDownload',
- 'id': id,
- 'action': action
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=window_index)
-
- def DownloadAndWaitForStart(self, file_url, windex=0):
- """Trigger download for the given url and wait for downloads to start.
-
- It waits for download by looking at the download info from Chrome, so
- anything which isn't registered by the history service won't be noticed.
- This is not thread-safe, but it's fine to call this method to start
- downloading multiple files in parallel. That is after starting a
- download, it's fine to start another one even if the first one hasn't
- completed.
- """
- try:
- num_downloads = len(self.GetDownloadsInfo(windex).Downloads())
- except JSONInterfaceError:
- num_downloads = 0
-
- self.NavigateToURL(file_url, windex) # Trigger download.
- # It might take a while for the download to kick in, hold on until then.
- self.assertTrue(self.WaitUntil(
- lambda: len(self.GetDownloadsInfo(windex).Downloads()) >
- num_downloads))
-
- def SetWindowDimensions(
- self, x=None, y=None, width=None, height=None, windex=0):
- """Set window dimensions.
-
- All args are optional and current values will be preserved.
- Arbitrarily large values will be handled gracefully by the browser.
-
- Args:
- x: window origin x
- y: window origin y
- width: window width
- height: window height
- windex: window index to work on. Defaults to 0 (first window)
- """
- cmd_dict = { # Prepare command for the json interface
- 'command': 'SetWindowDimensions',
- }
- if x:
- cmd_dict['x'] = x
- if y:
- cmd_dict['y'] = y
- if width:
- cmd_dict['width'] = width
- if height:
- cmd_dict['height'] = height
- self._GetResultFromJSONRequest(cmd_dict, windex=windex)
-
- def WaitForInfobarCount(self, count, windex=0, tab_index=0):
- """Wait until infobar count becomes |count|.
-
- Note: Wait duration is capped by the automation timeout.
-
- Args:
- count: requested number of infobars
- windex: window index. Defaults to 0 (first window)
- tab_index: tab index Defaults to 0 (first tab)
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- # TODO(phajdan.jr): We need a solid automation infrastructure to handle
- # these cases. See crbug.com/53647.
- def _InfobarCount():
- windows = self.GetBrowserInfo()['windows']
- if windex >= len(windows): # not enough windows
- return -1
- tabs = windows[windex]['tabs']
- if tab_index >= len(tabs): # not enough tabs
- return -1
- return len(tabs[tab_index]['infobars'])
-
- return self.WaitUntil(_InfobarCount, expect_retval=count)
-
- def PerformActionOnInfobar(
- self, action, infobar_index, windex=0, tab_index=0):
- """Perform actions on an infobar.
-
- Args:
- action: the action to be performed.
- Actions depend on the type of the infobar. The user needs to
- call the right action for the right infobar.
- Valid inputs are:
- - "dismiss": closes the infobar (for all infobars)
- - "accept", "cancel": click accept / cancel (for confirm infobars)
- - "allow", "deny": click allow / deny (for media stream infobars)
- infobar_index: 0-based index of the infobar on which to perform the action
- windex: 0-based window index Defaults to 0 (first window)
- tab_index: 0-based tab index. Defaults to 0 (first tab)
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'PerformActionOnInfobar',
- 'action': action,
- 'infobar_index': infobar_index,
- 'tab_index': tab_index,
- }
- if action not in ('dismiss', 'accept', 'allow', 'deny', 'cancel'):
- raise JSONInterfaceError('Invalid action %s' % action)
- self._GetResultFromJSONRequest(cmd_dict, windex=windex)
-
- def GetBrowserInfo(self):
- """Return info about the browser.
-
- This includes things like the version number, the executable name,
- executable path, pid info about the renderer/plugin/extension processes,
- window dimensions. (See sample below)
-
- For notification pid info, see 'GetActiveNotifications'.
-
- Returns:
- a dictionary
-
- Sample:
- { u'browser_pid': 93737,
- # Child processes are the processes for plugins and other workers.
- u'child_process_path': u'.../Chromium.app/Contents/'
- 'Versions/6.0.412.0/Chromium Helper.app/'
- 'Contents/MacOS/Chromium Helper',
- u'child_processes': [ { u'name': u'Shockwave Flash',
- u'pid': 93766,
- u'type': u'Plug-in'}],
- u'extension_views': [ {
- u'name': u'Webpage Screenshot',
- u'pid': 93938,
- u'extension_id': u'dgcoklnmbeljaehamekjpeidmbicddfj',
- u'url': u'chrome-extension://dgcoklnmbeljaehamekjpeidmbicddfj/'
- 'bg.html',
- u'loaded': True,
- u'view': {
- u'render_process_id': 2,
- u'render_view_id': 1},
- u'view_type': u'EXTENSION_BACKGROUND_PAGE'}]
- u'properties': {
- u'BrowserProcessExecutableName': u'Chromium',
- u'BrowserProcessExecutablePath': u'Chromium.app/Contents/MacOS/'
- 'Chromium',
- u'ChromeVersion': u'6.0.412.0',
- u'HelperProcessExecutableName': u'Chromium Helper',
- u'HelperProcessExecutablePath': u'Chromium Helper.app/Contents/'
- 'MacOS/Chromium Helper',
- u'command_line_string': "COMMAND_LINE_STRING --WITH-FLAGS",
- u'branding': 'Chromium',
- u'is_official': False,}
- # The order of the windows and tabs listed here will be the same as
- # what shows up on screen.
- u'windows': [ { u'index': 0,
- u'height': 1134,
- u'incognito': False,
- u'profile_path': u'Default',
- u'fullscreen': False,
- u'visible_page_actions':
- [u'dgcoklnmbeljaehamekjpeidmbicddfj',
- u'osfcklnfasdofpcldmalwpicslasdfgd']
- u'selected_tab': 0,
- u'tabs': [ {
- u'index': 0,
- u'infobars': [],
- u'pinned': True,
- u'renderer_pid': 93747,
- u'url': u'http://www.google.com/' }, {
- u'index': 1,
- u'infobars': [],
- u'pinned': False,
- u'renderer_pid': 93919,
- u'url': u'https://chrome.google.com/'}, {
- u'index': 2,
- u'infobars': [ {
- u'buttons': [u'Allow', u'Deny'],
- u'link_text': u'Learn more',
- u'text': u'slides.html5rocks.com wants to track '
- 'your physical location',
- u'type': u'confirm_infobar'}],
- u'pinned': False,
- u'renderer_pid': 93929,
- u'url': u'http://slides.html5rocks.com/#slide14'},
- ],
- u'type': u'tabbed',
- u'width': 925,
- u'x': 26,
- u'y': 44}]}
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { # Prepare command for the json interface
- 'command': 'GetBrowserInfo',
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def IsAura(self):
- """Is this Aura?"""
- return self.GetBrowserInfo()['properties']['aura']
-
- def GetProcessInfo(self):
- """Returns information about browser-related processes that currently exist.
-
- This will also return information about other currently-running browsers
- besides just Chrome.
-
- Returns:
- A dictionary containing browser-related process information as identified
- by class MemoryDetails in src/chrome/browser/memory_details.h. The
- dictionary contains a single key 'browsers', mapped to a list of
- dictionaries containing information about each browser process name.
- Each of those dictionaries contains a key 'processes', mapped to a list
- of dictionaries containing the specific information for each process
- with the given process name.
-
- The memory values given in |committed_mem| and |working_set_mem| are in
- KBytes.
-
- Sample:
- { 'browsers': [ { 'name': 'Chromium',
- 'process_name': 'chrome',
- 'processes': [ { 'child_process_type': 'Browser',
- 'committed_mem': { 'image': 0,
- 'mapped': 0,
- 'priv': 0},
- 'is_diagnostics': False,
- 'num_processes': 1,
- 'pid': 7770,
- 'product_name': '',
- 'renderer_type': 'Unknown',
- 'titles': [],
- 'version': '',
- 'working_set_mem': { 'priv': 43672,
- 'shareable': 0,
- 'shared': 59251}},
- { 'child_process_type': 'Tab',
- 'committed_mem': { 'image': 0,
- 'mapped': 0,
- 'priv': 0},
- 'is_diagnostics': False,
- 'num_processes': 1,
- 'pid': 7791,
- 'product_name': '',
- 'renderer_type': 'Tab',
- 'titles': ['about:blank'],
- 'version': '',
- 'working_set_mem': { 'priv': 16768,
- 'shareable': 0,
- 'shared': 26256}},
- ...<more processes>...]}]}
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { # Prepare command for the json interface.
- 'command': 'GetProcessInfo',
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def GetNavigationInfo(self, tab_index=0, windex=0):
- """Get info about the navigation state of a given tab.
-
- Args:
- tab_index: The tab index, default is 0.
- window_index: The window index, default is 0.
-
- Returns:
- a dictionary.
- Sample:
-
- { u'favicon_url': u'https://www.google.com/favicon.ico',
- u'page_type': u'NORMAL_PAGE',
- u'ssl': { u'displayed_insecure_content': False,
- u'ran_insecure_content': False,
- u'security_style': u'SECURITY_STYLE_AUTHENTICATED'}}
-
- Values for security_style can be:
- SECURITY_STYLE_UNKNOWN
- SECURITY_STYLE_UNAUTHENTICATED
- SECURITY_STYLE_AUTHENTICATION_BROKEN
- SECURITY_STYLE_AUTHENTICATED
-
- Values for page_type can be:
- NORMAL_PAGE
- ERROR_PAGE
- INTERSTITIAL_PAGE
- """
- cmd_dict = { # Prepare command for the json interface
- 'command': 'GetNavigationInfo',
- 'tab_index': tab_index,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=windex)
-
- def GetSecurityState(self, tab_index=0, windex=0):
- """Get security details for a given tab.
-
- Args:
- tab_index: The tab index, default is 0.
- window_index: The window index, default is 0.
-
- Returns:
- a dictionary.
- Sample:
- { "security_style": SECURITY_STYLE_AUTHENTICATED,
- "ssl_cert_status": 3, // bitmask of status flags
- "insecure_content_status": 1, // bitmask of status flags
- }
- """
- cmd_dict = { # Prepare command for the json interface
- 'command': 'GetSecurityState',
- 'tab_index': tab_index,
- 'windex': windex,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def GetHistoryInfo(self, search_text='', windex=0):
- """Return info about browsing history.
-
- Args:
- search_text: the string to search in history. Defaults to empty string
- which means that all history would be returned. This is
- functionally equivalent to searching for a text in the
- chrome://history UI. So partial matches work too.
- When non-empty, the history items returned will contain a
- "snippet" field corresponding to the snippet visible in
- the chrome://history/ UI.
- windex: index of the browser window, defaults to 0.
-
- Returns:
- an instance of history_info.HistoryInfo
- """
- cmd_dict = { # Prepare command for the json interface
- 'command': 'GetHistoryInfo',
- 'search_text': search_text,
- }
- return history_info.HistoryInfo(
- self._GetResultFromJSONRequest(cmd_dict, windex=windex))
-
- def InstallExtension(self, extension_path, with_ui=False, from_webstore=None,
- windex=0, tab_index=0):
- """Installs an extension from the given path.
-
- The path must be absolute and may be a crx file or an unpacked extension
- directory. Returns the extension ID if successfully installed and loaded.
- Otherwise, throws an exception. The extension must not already be installed.
-
- Args:
- extension_path: The absolute path to the extension to install. If the
- extension is packed, it must have a .crx extension.
- with_ui: Whether the extension install confirmation UI should be shown.
- from_webstore: If True, forces a .crx extension to be recognized as one
- from the webstore. Can be used to force install an extension with
- 'experimental' permissions.
- windex: Integer index of the browser window to use; defaults to 0
- (first window).
-
- Returns:
- The ID of the installed extension.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'InstallExtension',
- 'path': extension_path,
- 'with_ui': with_ui,
- 'windex': windex,
- 'tab_index': tab_index,
- }
-
- if from_webstore:
- cmd_dict['from_webstore'] = True
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)['id']
-
- def GetExtensionsInfo(self, windex=0):
- """Returns information about all installed extensions.
-
- Args:
- windex: Integer index of the browser window to use; defaults to 0
- (first window).
-
- Returns:
- A list of dictionaries representing each of the installed extensions.
- Example:
- [ { u'api_permissions': [u'bookmarks', u'experimental', u'tabs'],
- u'background_url': u'',
- u'description': u'Bookmark Manager',
- u'effective_host_permissions': [u'chrome://favicon/*',
- u'chrome://resources/*'],
- u'host_permissions': [u'chrome://favicon/*', u'chrome://resources/*'],
- u'id': u'eemcgdkfndhakfknompkggombfjjjeno',
- u'is_component': True,
- u'is_internal': False,
- u'name': u'Bookmark Manager',
- u'options_url': u'',
- u'public_key': u'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQcByy+eN9jza\
- zWF/DPn7NW47sW7lgmpk6eKc0BQM18q8hvEM3zNm2n7HkJv/R6f\
- U+X5mtqkDuKvq5skF6qqUF4oEyaleWDFhd1xFwV7JV+/DU7bZ00\
- w2+6gzqsabkerFpoP33ZRIw7OviJenP0c0uWqDWF8EGSyMhB3tx\
- qhOtiQIDAQAB',
- u'version': u'0.1' },
- { u'api_permissions': [...],
- u'background_url': u'chrome-extension://\
- lkdedmbpkaiahjjibfdmpoefffnbdkli/\
- background.html',
- u'description': u'Extension which lets you read your Facebook news \
- feed and wall. You can also post status updates.',
- u'effective_host_permissions': [...],
- u'host_permissions': [...],
- u'id': u'lkdedmbpkaiahjjibfdmpoefffnbdkli',
- u'name': u'Facebook for Google Chrome',
- u'options_url': u'',
- u'public_key': u'...',
- u'version': u'2.0.9'
- u'is_enabled': True,
- u'allowed_in_incognito': True} ]
- """
- cmd_dict = { # Prepare command for the json interface
- 'command': 'GetExtensionsInfo',
- 'windex': windex,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)['extensions']
-
- def UninstallExtensionById(self, id, windex=0):
- """Uninstall the extension with the given id.
-
- Args:
- id: The string id of the extension.
- windex: Integer index of the browser window to use; defaults to 0
- (first window).
-
- Returns:
- True, if the extension was successfully uninstalled, or
- False, otherwise.
- """
- cmd_dict = { # Prepare command for the json interface
- 'command': 'UninstallExtensionById',
- 'id': id,
- 'windex': windex,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)['success']
-
- def SetExtensionStateById(self, id, enable, allow_in_incognito, windex=0):
- """Set extension state: enable/disable, allow/disallow in incognito mode.
-
- Args:
- id: The string id of the extension.
- enable: A boolean, enable extension.
- allow_in_incognito: A boolean, allow extension in incognito.
- windex: Integer index of the browser window to use; defaults to 0
- (first window).
- """
- cmd_dict = { # Prepare command for the json interface
- 'command': 'SetExtensionStateById',
- 'id': id,
- 'enable': enable,
- 'allow_in_incognito': allow_in_incognito,
- 'windex': windex,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def TriggerPageActionById(self, id, tab_index=0, windex=0):
- """Trigger page action asynchronously in the active tab.
-
- The page action icon must be displayed before invoking this function.
-
- Args:
- id: The string id of the extension.
- tab_index: Integer index of the tab to use; defaults to 0 (first tab).
- windex: Integer index of the browser window to use; defaults to 0
- (first window).
- """
- cmd_dict = { # Prepare command for the json interface
- 'command': 'TriggerPageActionById',
- 'id': id,
- 'windex': windex,
- 'tab_index': tab_index,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def TriggerBrowserActionById(self, id, tab_index=0, windex=0):
- """Trigger browser action asynchronously in the active tab.
-
- Args:
- id: The string id of the extension.
- tab_index: Integer index of the tab to use; defaults to 0 (first tab).
- windex: Integer index of the browser window to use; defaults to 0
- (first window).
- """
- cmd_dict = { # Prepare command for the json interface
- 'command': 'TriggerBrowserActionById',
- 'id': id,
- 'windex': windex,
- 'tab_index': tab_index,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def UpdateExtensionsNow(self, windex=0):
- """Auto-updates installed extensions.
-
- Waits until all extensions are updated, loaded, and ready for use.
- This is equivalent to clicking the "Update extensions now" button on the
- chrome://extensions page.
-
- Args:
- windex: Integer index of the browser window to use; defaults to 0
- (first window).
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation returns an error.
- """
- cmd_dict = { # Prepare command for the json interface.
- 'command': 'UpdateExtensionsNow',
- 'windex': windex,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def WaitUntilExtensionViewLoaded(self, name=None, extension_id=None,
- url=None, view_type=None):
- """Wait for a loaded extension view matching all the given properties.
-
- If no matching extension views are found, wait for one to be loaded.
- If there are more than one matching extension view, return one at random.
- Uses WaitUntil so timeout is capped by automation timeout.
- Refer to extension_view dictionary returned in GetBrowserInfo()
- for sample input/output values.
-
- Args:
- name: (optional) Name of the extension.
- extension_id: (optional) ID of the extension.
- url: (optional) URL of the extension view.
- view_type: (optional) Type of the extension view.
- ['EXTENSION_BACKGROUND_PAGE'|'EXTENSION_POPUP'|'EXTENSION_INFOBAR'|
- 'EXTENSION_DIALOG']
-
- Returns:
- The 'view' property of the extension view.
- None, if no view loaded.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation returns an error.
- """
- def _GetExtensionViewLoaded():
- extension_views = self.GetBrowserInfo()['extension_views']
- for extension_view in extension_views:
- if ((name and name != extension_view['name']) or
- (extension_id and extension_id != extension_view['extension_id']) or
- (url and url != extension_view['url']) or
- (view_type and view_type != extension_view['view_type'])):
- continue
- if extension_view['loaded']:
- return extension_view['view']
- return False
-
- if self.WaitUntil(lambda: _GetExtensionViewLoaded()):
- return _GetExtensionViewLoaded()
- return None
-
- def WaitUntilExtensionViewClosed(self, view):
- """Wait for the given extension view to to be closed.
-
- Uses WaitUntil so timeout is capped by automation timeout.
- Refer to extension_view dictionary returned by GetBrowserInfo()
- for sample input value.
-
- Args:
- view: 'view' property of extension view.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation returns an error.
- """
- def _IsExtensionViewClosed():
- extension_views = self.GetBrowserInfo()['extension_views']
- for extension_view in extension_views:
- if view == extension_view['view']:
- return False
- return True
-
- return self.WaitUntil(lambda: _IsExtensionViewClosed())
-
- def GetPluginsInfo(self, windex=0):
- """Return info about plugins.
-
- This is the info available from about:plugins
-
- Returns:
- an instance of plugins_info.PluginsInfo
- """
- return plugins_info.PluginsInfo(
- self._GetResultFromJSONRequest({'command': 'GetPluginsInfo'},
- windex=windex))
-
- def EnablePlugin(self, path):
- """Enable the plugin at the given path.
-
- Use GetPluginsInfo() to fetch path info about a plugin.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'EnablePlugin',
- 'path': path,
- }
- self._GetResultFromJSONRequest(cmd_dict)
-
- def DisablePlugin(self, path):
- """Disable the plugin at the given path.
-
- Use GetPluginsInfo() to fetch path info about a plugin.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'DisablePlugin',
- 'path': path,
- }
- self._GetResultFromJSONRequest(cmd_dict)
-
- def GetTabContents(self, tab_index=0, window_index=0):
- """Get the html contents of a tab (a la "view source").
-
- As an implementation detail, this saves the html in a file, reads
- the file into a buffer, then deletes it.
-
- Args:
- tab_index: tab index, defaults to 0.
- window_index: window index, defaults to 0.
- Returns:
- html content of a page as a string.
- """
- tempdir = tempfile.mkdtemp()
- # Make it writable by chronos on chromeos
- os.chmod(tempdir, 0777)
- filename = os.path.join(tempdir, 'content.html')
- cmd_dict = { # Prepare command for the json interface
- 'command': 'SaveTabContents',
- 'tab_index': tab_index,
- 'filename': filename
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=window_index)
- try:
- f = open(filename)
- all_data = f.read()
- f.close()
- return all_data
- finally:
- shutil.rmtree(tempdir, ignore_errors=True)
-
- def AddSavedPassword(self, password_dict, windex=0):
- """Adds the given username-password combination to the saved passwords.
-
- Args:
- password_dict: a dictionary that represents a password. Example:
- { 'username_value': 'user@example.com', # Required
- 'password_value': 'test.password', # Required
- 'signon_realm': 'https://www.example.com/', # Required
- 'time': 1279317810.0, # Can get from time.time()
- 'origin_url': 'https://www.example.com/login',
- 'username_element': 'username', # The HTML element
- 'password_element': 'password', # The HTML element
- 'submit_element': 'submit', # The HTML element
- 'action_target': 'https://www.example.com/login/',
- 'blacklist': False }
- windex: window index; defaults to 0 (first window).
-
- *Blacklist notes* To blacklist a site, add a blacklist password with the
- following dictionary items: origin_url, signon_realm, username_element,
- password_element, action_target, and 'blacklist': True. Then all sites that
- have password forms matching those are blacklisted.
-
- Returns:
- True if adding the password succeeded, false otherwise. In incognito
- mode, adding the password should fail.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { # Prepare command for the json interface
- 'command': 'AddSavedPassword',
- 'password': password_dict
- }
- return self._GetResultFromJSONRequest(
- cmd_dict, windex=windex)['password_added']
-
- def RemoveSavedPassword(self, password_dict, windex=0):
- """Removes the password matching the provided password dictionary.
-
- Args:
- password_dict: A dictionary that represents a password.
- For an example, see the dictionary in AddSavedPassword.
- windex: The window index, default is 0 (first window).
- """
- cmd_dict = { # Prepare command for the json interface
- 'command': 'RemoveSavedPassword',
- 'password': password_dict
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=windex)
-
- def GetSavedPasswords(self):
- """Return the passwords currently saved.
-
- Returns:
- A list of dictionaries representing each password. For an example
- dictionary see AddSavedPassword documentation. The overall structure will
- be:
- [ {password1 dictionary}, {password2 dictionary} ]
- """
- cmd_dict = { # Prepare command for the json interface
- 'command': 'GetSavedPasswords'
- }
- return self._GetResultFromJSONRequest(cmd_dict)['passwords']
-
- def SetTheme(self, crx_file_path, windex=0):
- """Installs the given theme synchronously.
-
- A theme file is a file with a .crx suffix, like an extension. The theme
- file must be specified with an absolute path. This method call waits until
- the theme is installed and will trigger the "theme installed" infobar.
- If the install is unsuccessful, will throw an exception.
-
- Uses InstallExtension().
-
- Returns:
- The ID of the installed theme.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- return self.InstallExtension(crx_file_path, True, windex)
-
- def GetActiveNotifications(self):
- """Gets a list of the currently active/shown HTML5 notifications.
-
- Returns:
- a list containing info about each active notification, with the
- first item in the list being the notification on the bottom of the
- notification stack. The 'content_url' key can refer to a URL or a data
- URI. The 'pid' key-value pair may be invalid if the notification is
- closing.
-
- SAMPLE:
- [ { u'content_url': u'data:text/html;charset=utf-8,%3C!DOCTYPE%l%3E%0Atm...'
- u'display_source': 'www.corp.google.com',
- u'origin_url': 'http://www.corp.google.com/',
- u'pid': 8505},
- { u'content_url': 'http://www.gmail.com/special_notification.html',
- u'display_source': 'www.gmail.com',
- u'origin_url': 'http://www.gmail.com/',
- u'pid': 9291}]
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- return [x for x in self.GetAllNotifications() if 'pid' in x]
-
- def GetAllNotifications(self):
- """Gets a list of all active and queued HTML5 notifications.
-
- An active notification is one that is currently shown to the user. Chrome's
- notification system will limit the number of notifications shown (currently
- by only allowing a certain percentage of the screen to be taken up by them).
- A notification will be queued if there are too many active notifications.
- Once other notifications are closed, another will be shown from the queue.
-
- Returns:
- a list containing info about each notification, with the first
- item in the list being the notification on the bottom of the
- notification stack. The 'content_url' key can refer to a URL or a data
- URI. The 'pid' key-value pair will only be present for active
- notifications.
-
- SAMPLE:
- [ { u'content_url': u'data:text/html;charset=utf-8,%3C!DOCTYPE%l%3E%0Atm...'
- u'display_source': 'www.corp.google.com',
- u'origin_url': 'http://www.corp.google.com/',
- u'pid': 8505},
- { u'content_url': 'http://www.gmail.com/special_notification.html',
- u'display_source': 'www.gmail.com',
- u'origin_url': 'http://www.gmail.com/'}]
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'GetAllNotifications',
- }
- return self._GetResultFromJSONRequest(cmd_dict)['notifications']
-
- def CloseNotification(self, index):
- """Closes the active HTML5 notification at the given index.
-
- Args:
- index: the index of the notification to close. 0 refers to the
- notification on the bottom of the notification stack.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'CloseNotification',
- 'index': index,
- }
- return self._GetResultFromJSONRequest(cmd_dict)
-
- def WaitForNotificationCount(self, count):
- """Waits for the number of active HTML5 notifications to reach the given
- count.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'WaitForNotificationCount',
- 'count': count,
- }
- self._GetResultFromJSONRequest(cmd_dict)
-
- def FindInPage(self, search_string, forward=True,
- match_case=False, find_next=False,
- tab_index=0, windex=0, timeout=-1):
- """Find the match count for the given search string and search parameters.
- This is equivalent to using the find box.
-
- Args:
- search_string: The string to find on the page.
- forward: Boolean to set if the search direction is forward or backwards
- match_case: Boolean to set for case sensitive search.
- find_next: Boolean to set to continue the search or start from beginning.
- tab_index: The tab index, default is 0.
- windex: The window index, default is 0.
- timeout: request timeout (in milliseconds), default is -1.
-
- Returns:
- number of matches found for the given search string and parameters
- SAMPLE:
- { u'match_count': 10,
- u'match_left': 100,
- u'match_top': 100,
- u'match_right': 200,
- u'match_bottom': 200}
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'FindInPage',
- 'tab_index' : tab_index,
- 'search_string' : search_string,
- 'forward' : forward,
- 'match_case' : match_case,
- 'find_next' : find_next,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=windex,
- timeout=timeout)
-
- def OpenFindInPage(self, windex=0):
- """Opens the "Find in Page" box.
-
- Args:
- windex: Index of the window; defaults to 0.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'OpenFindInPage',
- 'windex' : windex,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def IsFindInPageVisible(self, windex=0):
- """Returns the visibility of the "Find in Page" box.
-
- Args:
- windex: Index of the window; defaults to 0.
-
- Returns:
- A boolean indicating the visibility state of the "Find in Page" box.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'IsFindInPageVisible',
- 'windex' : windex,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)['is_visible']
-
-
- def AddDomEventObserver(self, event_name='', automation_id=-1,
- recurring=False):
- """Adds a DomEventObserver associated with the AutomationEventQueue.
-
- An app raises a matching event in Javascript by calling:
- window.domAutomationController.sendWithId(automation_id, event_name)
-
- Args:
- event_name: The event name to watch for. By default an event is raised
- for any message.
- automation_id: The Automation Id of the sent message. By default all
- messages sent from the window.domAutomationController are
- observed. Note that other PyAuto functions also send
- messages through window.domAutomationController with
- arbirary Automation Ids and they will be observed.
- recurring: If False the observer will be removed after it generates one
- event, otherwise it will continue observing and generating
- events until explicity removed with RemoveEventObserver(id).
-
- Returns:
- The id of the created observer, which can be used with GetNextEvent(id)
- and RemoveEventObserver(id).
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'AddDomEventObserver',
- 'event_name': event_name,
- 'automation_id': automation_id,
- 'recurring': recurring,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)['observer_id']
-
- def AddDomMutationObserver(self, mutation_type, xpath,
- attribute='textContent', expected_value=None,
- automation_id=44444,
- exec_js=None, **kwargs):
- """Sets up an event observer watching for a specific DOM mutation.
-
- Creates an observer that raises an event when a mutation of the given type
- occurs on a DOM node specified by |selector|.
-
- Args:
- mutation_type: One of 'add', 'remove', 'change', or 'exists'.
- xpath: An xpath specifying the DOM node to watch. The node must already
- exist if |mutation_type| is 'change'.
- attribute: Attribute to match |expected_value| against, if given. Defaults
- to 'textContent'.
- expected_value: Optional regular expression to match against the node's
- textContent attribute after the mutation. Defaults to None.
- automation_id: The automation_id used to route the observer javascript
- messages. Defaults to 44444.
- exec_js: A callable of the form f(self, js, **kwargs) used to inject the
- MutationObserver javascript. Defaults to None, which uses
- PyUITest.ExecuteJavascript.
-
- Any additional keyword arguments are passed on to ExecuteJavascript and
- can be used to select the tab where the DOM MutationObserver is created.
-
- Returns:
- The id of the created observer, which can be used with GetNextEvent(id)
- and RemoveEventObserver(id).
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- pyauto_errors.JavascriptRuntimeError if the injected javascript
- MutationObserver returns an error.
- """
- assert mutation_type in ('add', 'remove', 'change', 'exists'), \
- 'Unexpected value "%s" for mutation_type.' % mutation_type
- cmd_dict = {
- 'command': 'AddDomEventObserver',
- 'event_name': '__dom_mutation_observer__:$(id)',
- 'automation_id': automation_id,
- 'recurring': False,
- }
- observer_id = (
- self._GetResultFromJSONRequest(cmd_dict, windex=None)['observer_id'])
- expected_string = ('null' if expected_value is None else '"%s"' %
- expected_value.replace('"', r'\"'))
- jsfile = os.path.join(os.path.abspath(os.path.dirname(__file__)),
- 'dom_mutation_observer.js')
- with open(jsfile, 'r') as f:
- js = ('(' + f.read() + ')(%d, %d, "%s", "%s", "%s", %s);' %
- (automation_id, observer_id, mutation_type,
- xpath.replace('"', r'\"'), attribute, expected_string))
- exec_js = exec_js or PyUITest.ExecuteJavascript
- try:
- jsreturn = exec_js(self, js, **kwargs)
- except JSONInterfaceError:
- raise JSONInterfaceError('Failed to inject DOM mutation observer.')
- if jsreturn != 'success':
- self.RemoveEventObserver(observer_id)
- raise JavascriptRuntimeError(jsreturn)
- return observer_id
-
- def WaitForDomNode(self, xpath, attribute='textContent',
- expected_value=None, exec_js=None, timeout=-1,
- msg='Expected DOM node failed to appear.', **kwargs):
- """Waits until a node specified by an xpath exists in the DOM.
-
- NOTE: This does NOT poll. It returns as soon as the node appears, or
- immediately if the node already exists.
-
- Args:
- xpath: An xpath specifying the DOM node to watch.
- attribute: Attribute to match |expected_value| against, if given. Defaults
- to 'textContent'.
- expected_value: Optional regular expression to match against the node's
- textContent attribute. Defaults to None.
- exec_js: A callable of the form f(self, js, **kwargs) used to inject the
- MutationObserver javascript. Defaults to None, which uses
- PyUITest.ExecuteJavascript.
- msg: An optional error message used if a JSONInterfaceError is caught
- while waiting for the DOM node to appear.
- timeout: Time to wait for the node to exist before raising an exception,
- defaults to the default automation timeout.
-
- Any additional keyword arguments are passed on to ExecuteJavascript and
- can be used to select the tab where the DOM MutationObserver is created.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- pyauto_errors.JavascriptRuntimeError if the injected javascript
- MutationObserver returns an error.
- """
- observer_id = self.AddDomMutationObserver('exists', xpath, attribute,
- expected_value, exec_js=exec_js,
- **kwargs)
- try:
- self.GetNextEvent(observer_id, timeout=timeout)
- except JSONInterfaceError:
- raise JSONInterfaceError(msg)
-
- def GetNextEvent(self, observer_id=-1, blocking=True, timeout=-1):
- """Waits for an observed event to occur.
-
- The returned event is removed from the Event Queue. If there is already a
- matching event in the queue it is returned immediately, otherwise the call
- blocks until a matching event occurs. If blocking is disabled and no
- matching event is in the queue this function will immediately return None.
-
- Args:
- observer_id: The id of the observer to wait for, matches any event by
- default.
- blocking: If True waits until there is a matching event in the queue,
- if False and there is no event waiting in the queue returns None
- immediately.
- timeout: Time to wait for a matching event, defaults to the default
- automation timeout.
-
- Returns:
- Event response dictionary, or None if blocking is disabled and there is no
- matching event in the queue.
- SAMPLE:
- { 'observer_id': 1,
- 'name': 'login completed',
- 'type': 'raised_event'}
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'GetNextEvent',
- 'observer_id' : observer_id,
- 'blocking' : blocking,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None,
- timeout=timeout)
-
- def RemoveEventObserver(self, observer_id):
- """Removes an Event Observer from the AutomationEventQueue.
-
- Expects a valid observer_id.
-
- Args:
- observer_id: The id of the observer to remove.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'RemoveEventObserver',
- 'observer_id' : observer_id,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def ClearEventQueue(self):
- """Removes all events currently in the AutomationEventQueue.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'ClearEventQueue',
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def WaitUntilNavigationCompletes(self, tab_index=0, windex=0):
- """Wait until the specified tab is done navigating.
-
- It is safe to call ExecuteJavascript() as soon as the call returns. If
- there is no outstanding navigation the call will return immediately.
-
- Args:
- tab_index: index of the tab.
- windex: index of the window.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'WaitUntilNavigationCompletes',
- 'tab_index': tab_index,
- 'windex': windex,
- }
- return self._GetResultFromJSONRequest(cmd_dict)
-
- def ExecuteJavascript(self, js, tab_index=0, windex=0, frame_xpath=''):
- """Executes a script in the specified frame of a tab.
-
- By default, execute the script in the top frame of the first tab in the
- first window. The invoked javascript function must send a result back via
- the domAutomationController.send function, or this function will never
- return.
-
- Args:
- js: script to be executed.
- windex: index of the window.
- tab_index: index of the tab.
- frame_xpath: XPath of the frame to execute the script. Default is no
- frame. Example: '//frames[1]'.
-
- Returns:
- a value that was sent back via the domAutomationController.send method
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'ExecuteJavascript',
- 'javascript' : js,
- 'windex' : windex,
- 'tab_index' : tab_index,
- 'frame_xpath' : frame_xpath,
- }
- result = self._GetResultFromJSONRequest(cmd_dict)['result']
- # Wrap result in an array before deserializing because valid JSON has an
- # array or an object as the root.
- json_string = '[' + result + ']'
- return json.loads(json_string)[0]
-
- def ExecuteJavascriptInRenderView(self, js, view, frame_xpath=''):
- """Executes a script in the specified frame of an render view.
-
- The invoked javascript function must send a result back via the
- domAutomationController.send function, or this function will never return.
-
- Args:
- js: script to be executed.
- view: A dictionary representing a unique id for the render view as
- returned for example by.
- self.GetBrowserInfo()['extension_views'][]['view'].
- Example:
- { 'render_process_id': 1,
- 'render_view_id' : 2}
-
- frame_xpath: XPath of the frame to execute the script. Default is no
- frame. Example:
- '//frames[1]'
-
- Returns:
- a value that was sent back via the domAutomationController.send method
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'ExecuteJavascriptInRenderView',
- 'javascript' : js,
- 'view' : view,
- 'frame_xpath' : frame_xpath,
- }
- result = self._GetResultFromJSONRequest(cmd_dict, windex=None)['result']
- # Wrap result in an array before deserializing because valid JSON has an
- # array or an object as the root.
- json_string = '[' + result + ']'
- return json.loads(json_string)[0]
-
- def ExecuteJavascriptInOOBEWebUI(self, js, frame_xpath=''):
- """Executes a script in the specified frame of the OOBE WebUI.
-
- By default, execute the script in the top frame of the OOBE window. This
- also works for all OOBE pages, including the enterprise enrollment
- screen and login page. The invoked javascript function must send a result
- back via the domAutomationController.send function, or this function will
- never return.
-
- Args:
- js: Script to be executed.
- frame_xpath: XPath of the frame to execute the script. Default is no
- frame. Example: '//frames[1]'
-
- Returns:
- A value that was sent back via the domAutomationController.send method.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'ExecuteJavascriptInOOBEWebUI',
-
- 'javascript': js,
- 'frame_xpath': frame_xpath,
- }
- result = self._GetResultFromJSONRequest(cmd_dict, windex=None)['result']
- # Wrap result in an array before deserializing because valid JSON has an
- # array or an object as the root.
- return json.loads('[' + result + ']')[0]
-
-
- def GetDOMValue(self, expr, tab_index=0, windex=0, frame_xpath=''):
- """Executes a Javascript expression and returns the value.
-
- This is a wrapper for ExecuteJavascript, eliminating the need to
- explicitly call domAutomationController.send function.
-
- Args:
- expr: expression value to be returned.
- tab_index: index of the tab.
- windex: index of the window.
- frame_xpath: XPath of the frame to execute the script. Default is no
- frame. Example: '//frames[1]'.
-
- Returns:
- a string that was sent back via the domAutomationController.send method.
- """
- js = 'window.domAutomationController.send(%s);' % expr
- return self.ExecuteJavascript(js, tab_index, windex, frame_xpath)
-
- def CallJavascriptFunc(self, function, args=[], tab_index=0, windex=0):
- """Executes a script which calls a given javascript function.
-
- The invoked javascript function must send a result back via the
- domAutomationController.send function, or this function will never return.
-
- Defaults to first tab in first window.
-
- Args:
- function: name of the function.
- args: list of all the arguments to pass into the called function. These
- should be able to be converted to a string using the |str| function.
- tab_index: index of the tab within the given window.
- windex: index of the window.
-
- Returns:
- a string that was sent back via the domAutomationController.send method
- """
- converted_args = map(lambda arg: json.dumps(arg), args)
- js = '%s(%s)' % (function, ', '.join(converted_args))
- logging.debug('Executing javascript: %s', js)
- return self.ExecuteJavascript(js, tab_index, windex)
-
- def HeapProfilerDump(self, process_type, reason, tab_index=0, windex=0):
- """Dumps a heap profile. It works only on Linux and ChromeOS.
-
- We need an environment variable "HEAPPROFILE" set to a directory and a
- filename prefix, for example, "/tmp/prof". In a case of this example,
- heap profiles will be dumped into "/tmp/prof.(pid).0002.heap",
- "/tmp/prof.(pid).0003.heap", and so on. Nothing happens when this
- function is called without the env.
-
- Also, this requires the --enable-memory-benchmarking command line flag.
-
- Args:
- process_type: A string which is one of 'browser' or 'renderer'.
- reason: A string which describes the reason for dumping a heap profile.
- The reason will be included in the logged message.
- Examples:
- 'To check memory leaking'
- 'For PyAuto tests'
- tab_index: tab index to work on if 'process_type' == 'renderer'.
- Defaults to 0 (first tab).
- windex: window index to work on if 'process_type' == 'renderer'.
- Defaults to 0 (first window).
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- assert process_type in ('browser', 'renderer')
- if self.IsLinux(): # IsLinux() also implies IsChromeOS().
- js = """
- if (!chrome.memoryBenchmarking ||
- !chrome.memoryBenchmarking.isHeapProfilerRunning()) {
- domAutomationController.send('memory benchmarking disabled');
- } else {
- chrome.memoryBenchmarking.heapProfilerDump("%s", "%s");
- domAutomationController.send('success');
- }
- """ % (process_type, reason.replace('"', '\\"'))
- result = self.ExecuteJavascript(js, tab_index, windex)
- if result != 'success':
- raise JSONInterfaceError('Heap profiler dump failed: ' + result)
- else:
- logging.warn('Heap-profiling is not supported in this OS.')
-
- def GetNTPThumbnails(self):
- """Return a list of info about the sites in the NTP most visited section.
- SAMPLE:
- [{ u'title': u'Google',
- u'url': u'http://www.google.com'},
- {
- u'title': u'Yahoo',
- u'url': u'http://www.yahoo.com'}]
- """
- return self._GetNTPInfo()['most_visited']
-
- def GetNTPThumbnailIndex(self, thumbnail):
- """Returns the index of the given NTP thumbnail, or -1 if it is not shown.
-
- Args:
- thumbnail: a thumbnail dict received from |GetNTPThumbnails|
- """
- thumbnails = self.GetNTPThumbnails()
- for i in range(len(thumbnails)):
- if thumbnails[i]['url'] == thumbnail['url']:
- return i
- return -1
-
- def RemoveNTPThumbnail(self, thumbnail):
- """Removes the NTP thumbnail and returns true on success.
-
- Args:
- thumbnail: a thumbnail dict received from |GetNTPThumbnails|
- """
- self._CheckNTPThumbnailShown(thumbnail)
- cmd_dict = {
- 'command': 'RemoveNTPMostVisitedThumbnail',
- 'url': thumbnail['url']
- }
- self._GetResultFromJSONRequest(cmd_dict)
-
- def RestoreAllNTPThumbnails(self):
- """Restores all the removed NTP thumbnails.
- Note:
- the default thumbnails may come back into the Most Visited sites
- section after doing this
- """
- cmd_dict = {
- 'command': 'RestoreAllNTPMostVisitedThumbnails'
- }
- self._GetResultFromJSONRequest(cmd_dict)
-
- def GetNTPDefaultSites(self):
- """Returns a list of URLs for all the default NTP sites, regardless of
- whether they are showing or not.
-
- These sites are the ones present in the NTP on a fresh install of Chrome.
- """
- return self._GetNTPInfo()['default_sites']
-
- def RemoveNTPDefaultThumbnails(self):
- """Removes all thumbnails for default NTP sites, regardless of whether they
- are showing or not."""
- cmd_dict = { 'command': 'RemoveNTPMostVisitedThumbnail' }
- for site in self.GetNTPDefaultSites():
- cmd_dict['url'] = site
- self._GetResultFromJSONRequest(cmd_dict)
-
- def GetNTPRecentlyClosed(self):
- """Return a list of info about the items in the NTP recently closed section.
- SAMPLE:
- [{
- u'type': u'tab',
- u'url': u'http://www.bing.com',
- u'title': u'Bing',
- u'timestamp': 2139082.03912, # Seconds since epoch (Jan 1, 1970)
- u'direction': u'ltr'},
- {
- u'type': u'window',
- u'timestamp': 2130821.90812,
- u'tabs': [
- {
- u'type': u'tab',
- u'url': u'http://www.cnn.com',
- u'title': u'CNN',
- u'timestamp': 2129082.12098,
- u'direction': u'ltr'}]},
- {
- u'type': u'tab',
- u'url': u'http://www.altavista.com',
- u'title': u'Altavista',
- u'timestamp': 21390820.12903,
- u'direction': u'rtl'}]
- """
- return self._GetNTPInfo()['recently_closed']
-
- def GetNTPApps(self):
- """Retrieves information about the apps listed on the NTP.
-
- In the sample data below, the "launch_type" will be one of the following
- strings: "pinned", "regular", "fullscreen", "window", or "unknown".
-
- SAMPLE:
- [
- {
- u'app_launch_index': 2,
- u'description': u'Web Store',
- u'icon_big': u'chrome://theme/IDR_APP_DEFAULT_ICON',
- u'icon_small': u'chrome://favicon/https://chrome.google.com/webstore',
- u'id': u'ahfgeienlihckogmohjhadlkjgocpleb',
- u'is_component_extension': True,
- u'is_disabled': False,
- u'launch_container': 2,
- u'launch_type': u'regular',
- u'launch_url': u'https://chrome.google.com/webstore',
- u'name': u'Chrome Web Store',
- u'options_url': u'',
- },
- {
- u'app_launch_index': 1,
- u'description': u'A countdown app',
- u'icon_big': (u'chrome-extension://aeabikdlfbfeihglecobdkdflahfgcpd/'
- u'countdown128.png'),
- u'icon_small': (u'chrome://favicon/chrome-extension://'
- u'aeabikdlfbfeihglecobdkdflahfgcpd/'
- u'launchLocalPath.html'),
- u'id': u'aeabikdlfbfeihglecobdkdflahfgcpd',
- u'is_component_extension': False,
- u'is_disabled': False,
- u'launch_container': 2,
- u'launch_type': u'regular',
- u'launch_url': (u'chrome-extension://aeabikdlfbfeihglecobdkdflahfgcpd/'
- u'launchLocalPath.html'),
- u'name': u'Countdown',
- u'options_url': u'',
- }
- ]
-
- Returns:
- A list of dictionaries in which each dictionary contains the information
- for a single app that appears in the "Apps" section of the NTP.
- """
- return self._GetNTPInfo()['apps']
-
- def _GetNTPInfo(self):
- """Get info about the New Tab Page (NTP).
-
- This does not retrieve the actual info displayed in a particular NTP; it
- retrieves the current state of internal data that would be used to display
- an NTP. This includes info about the apps, the most visited sites,
- the recently closed tabs and windows, and the default NTP sites.
-
- SAMPLE:
- {
- u'apps': [ ... ],
- u'most_visited': [ ... ],
- u'recently_closed': [ ... ],
- u'default_sites': [ ... ]
- }
-
- Returns:
- A dictionary containing all the NTP info. See details about the different
- sections in their respective methods: GetNTPApps(), GetNTPThumbnails(),
- GetNTPRecentlyClosed(), and GetNTPDefaultSites().
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'GetNTPInfo',
- }
- return self._GetResultFromJSONRequest(cmd_dict)
-
- def _CheckNTPThumbnailShown(self, thumbnail):
- if self.GetNTPThumbnailIndex(thumbnail) == -1:
- raise NTPThumbnailNotShownError()
-
- def LaunchApp(self, app_id, windex=0):
- """Opens the New Tab Page and launches the specified app from it.
-
- This method will not return until after the contents of a new tab for the
- launched app have stopped loading.
-
- Args:
- app_id: The string ID of the app to launch.
- windex: The index of the browser window to work on. Defaults to 0 (the
- first window).
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- self.AppendTab(GURL('chrome://newtab'), windex) # Also activates this tab.
- cmd_dict = {
- 'command': 'LaunchApp',
- 'id': app_id,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=windex)
-
- def SetAppLaunchType(self, app_id, launch_type, windex=0):
- """Sets the launch type for the specified app.
-
- Args:
- app_id: The string ID of the app whose launch type should be set.
- launch_type: The string launch type, which must be one of the following:
- 'pinned': Launch in a pinned tab.
- 'regular': Launch in a regular tab.
- 'fullscreen': Launch in a fullscreen tab.
- 'window': Launch in a new browser window.
- windex: The index of the browser window to work on. Defaults to 0 (the
- first window).
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- self.assertTrue(launch_type in ('pinned', 'regular', 'fullscreen',
- 'window'),
- msg='Unexpected launch type value: "%s"' % launch_type)
- cmd_dict = {
- 'command': 'SetAppLaunchType',
- 'id': app_id,
- 'launch_type': launch_type,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=windex)
-
- def GetV8HeapStats(self, tab_index=0, windex=0):
- """Returns statistics about the v8 heap in the renderer process for a tab.
-
- Args:
- tab_index: The tab index, default is 0.
- window_index: The window index, default is 0.
-
- Returns:
- A dictionary containing v8 heap statistics. Memory values are in bytes.
- Example:
- { 'renderer_id': 6223,
- 'v8_memory_allocated': 21803776,
- 'v8_memory_used': 10565392 }
- """
- cmd_dict = { # Prepare command for the json interface.
- 'command': 'GetV8HeapStats',
- 'tab_index': tab_index,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=windex)
-
- def GetFPS(self, tab_index=0, windex=0):
- """Returns the current FPS associated with the renderer process for a tab.
-
- FPS is the rendered frames per second.
-
- Args:
- tab_index: The tab index, default is 0.
- window_index: The window index, default is 0.
-
- Returns:
- A dictionary containing FPS info.
- Example:
- { 'renderer_id': 23567,
- 'routing_id': 1,
- 'fps': 29.404298782348633 }
- """
- cmd_dict = { # Prepare command for the json interface.
- 'command': 'GetFPS',
- 'tab_index': tab_index,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=windex)
-
- def IsFullscreenForBrowser(self, windex=0):
- """Returns true if the window is currently fullscreen and was initially
- transitioned to fullscreen by a browser (vs tab) mode transition."""
- return self._GetResultFromJSONRequest(
- { 'command': 'IsFullscreenForBrowser' },
- windex=windex).get('result')
-
- def IsFullscreenForTab(self, windex=0):
- """Returns true if fullscreen has been caused by a tab."""
- return self._GetResultFromJSONRequest(
- { 'command': 'IsFullscreenForTab' },
- windex=windex).get('result')
-
- def IsMouseLocked(self, windex=0):
- """Returns true if the mouse is currently locked."""
- return self._GetResultFromJSONRequest(
- { 'command': 'IsMouseLocked' },
- windex=windex).get('result')
-
- def IsMouseLockPermissionRequested(self, windex=0):
- """Returns true if the user is currently prompted to give permision for
- mouse lock."""
- return self._GetResultFromJSONRequest(
- { 'command': 'IsMouseLockPermissionRequested' },
- windex=windex).get('result')
-
- def IsFullscreenPermissionRequested(self, windex=0):
- """Returns true if the user is currently prompted to give permision for
- fullscreen."""
- return self._GetResultFromJSONRequest(
- { 'command': 'IsFullscreenPermissionRequested' },
- windex=windex).get('result')
-
- def IsFullscreenBubbleDisplayed(self, windex=0):
- """Returns true if the fullscreen and mouse lock bubble is currently
- displayed."""
- return self._GetResultFromJSONRequest(
- { 'command': 'IsFullscreenBubbleDisplayed' },
- windex=windex).get('result')
-
- def IsFullscreenBubbleDisplayingButtons(self, windex=0):
- """Returns true if the fullscreen and mouse lock bubble is currently
- displayed and presenting buttons."""
- return self._GetResultFromJSONRequest(
- { 'command': 'IsFullscreenBubbleDisplayingButtons' },
- windex=windex).get('result')
-
- def AcceptCurrentFullscreenOrMouseLockRequest(self, windex=0):
- """Activate the accept button on the fullscreen and mouse lock bubble."""
- return self._GetResultFromJSONRequest(
- { 'command': 'AcceptCurrentFullscreenOrMouseLockRequest' },
- windex=windex)
-
- def DenyCurrentFullscreenOrMouseLockRequest(self, windex=0):
- """Activate the deny button on the fullscreen and mouse lock bubble."""
- return self._GetResultFromJSONRequest(
- { 'command': 'DenyCurrentFullscreenOrMouseLockRequest' },
- windex=windex)
-
- def KillRendererProcess(self, pid):
- """Kills the given renderer process.
-
- This will return only after the browser has received notice of the renderer
- close.
-
- Args:
- pid: the process id of the renderer to kill
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'KillRendererProcess',
- 'pid': pid
- }
- return self._GetResultFromJSONRequest(cmd_dict)
-
- def NewWebDriver(self, port=0):
- """Returns a new remote WebDriver instance.
-
- Args:
- port: The port to start WebDriver on; by default the service selects an
- open port. It is an error to request a port number and request a
- different port later.
-
- Returns:
- selenium.webdriver.remote.webdriver.WebDriver instance
- """
- from chrome_driver_factory import ChromeDriverFactory
- global _CHROME_DRIVER_FACTORY
- if _CHROME_DRIVER_FACTORY is None:
- _CHROME_DRIVER_FACTORY = ChromeDriverFactory(port=port)
- self.assertTrue(_CHROME_DRIVER_FACTORY.GetPort() == port or port == 0,
- msg='Requested a WebDriver on a specific port while already'
- ' running on a different port.')
- return _CHROME_DRIVER_FACTORY.NewChromeDriver(self)
-
- def CreateNewAutomationProvider(self, channel_id):
- """Creates a new automation provider.
-
- The provider will open a named channel in server mode.
- Args:
- channel_id: the channel_id to open the server channel with
- """
- cmd_dict = {
- 'command': 'CreateNewAutomationProvider',
- 'channel_id': channel_id
- }
- self._GetResultFromJSONRequest(cmd_dict)
-
- def OpenNewBrowserWindowWithNewProfile(self):
- """Creates a new multi-profiles user, and then opens and shows a new
- tabbed browser window with the new profile.
-
- This is equivalent to 'Add new user' action with multi-profiles.
-
- To account for crbug.com/108761 on Win XP, this call polls until the
- profile count increments by 1.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- num_profiles = len(self.GetMultiProfileInfo()['profiles'])
- cmd_dict = { # Prepare command for the json interface
- 'command': 'OpenNewBrowserWindowWithNewProfile'
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
- # TODO(nirnimesh): Remove when crbug.com/108761 is fixed
- self.WaitUntil(
- lambda: len(self.GetMultiProfileInfo()['profiles']),
- expect_retval=(num_profiles + 1))
-
- def OpenProfileWindow(self, path, num_loads=1):
- """Open browser window for an existing profile.
-
- This is equivalent to picking a profile from the multi-profile menu.
-
- Multi-profile should be enabled and the requested profile should already
- exist. Creates a new window for the given profile. Use
- OpenNewBrowserWindowWithNewProfile() to create a new profile.
-
- Args:
- path: profile path of the profile to be opened.
- num_loads: the number of loads to wait for, when a new browser window
- is created. Useful when restoring a window with many tabs.
- """
- cmd_dict = { # Prepare command for the json interface
- 'command': 'OpenProfileWindow',
- 'path': path,
- 'num_loads': num_loads,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def GetMultiProfileInfo(self):
- """Fetch info about all multi-profile users.
-
- Returns:
- A dictionary.
- Sample:
- {
- 'enabled': True,
- 'profiles': [{'name': 'First user',
- 'path': '/tmp/.org.chromium.Chromium.Tyx17X/Default'},
- {'name': 'User 1',
- 'path': '/tmp/.org.chromium.Chromium.Tyx17X/profile_1'}],
- }
-
- Profiles will be listed in the same order as visible in preferences.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { # Prepare command for the json interface
- 'command': 'GetMultiProfileInfo'
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def RefreshPolicies(self):
- """Refreshes all the available policy providers.
-
- Each policy provider will reload its policy source and push the updated
- policies. This call waits for the new policies to be applied; any policies
- installed before this call is issued are guaranteed to be ready after it
- returns.
- """
- # TODO(craigdh): Determine the root cause of RefreshPolicies' flakiness.
- # See crosbug.com/30221
- timeout = PyUITest.ActionTimeoutChanger(self, 3 * 60 * 1000)
- cmd_dict = { 'command': 'RefreshPolicies' }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def SubmitForm(self, form_id, tab_index=0, windex=0, frame_xpath=''):
- """Submits the given form ID, and returns after it has been submitted.
-
- Args:
- form_id: the id attribute of the form to submit.
-
- Returns: true on success.
- """
- js = """
- document.getElementById("%s").submit();
- window.addEventListener("unload", function() {
- window.domAutomationController.send("done");
- });
- """ % form_id
- if self.ExecuteJavascript(js, tab_index, windex, frame_xpath) != 'done':
- return False
- # Wait until the form is submitted and the page completes loading.
- return self.WaitUntil(
- lambda: self.GetDOMValue('document.readyState',
- tab_index, windex, frame_xpath),
- expect_retval='complete')
-
- def SimulateAsanMemoryBug(self):
- """Simulates a memory bug for Address Sanitizer to catch.
-
- Address Sanitizer (if it was built it) will catch the bug and abort
- the process.
- This method returns immediately before it actually causes a crash.
- """
- cmd_dict = { 'command': 'SimulateAsanMemoryBug' }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- ## ChromeOS section
-
- def GetLoginInfo(self):
- """Returns information about login and screen locker state.
-
- This includes things like whether a user is logged in, the username
- of the logged in user, and whether the screen is locked.
-
- Returns:
- A dictionary.
- Sample:
- { u'is_guest': False,
- u'is_owner': True,
- u'email': u'example@gmail.com',
- u'user_image': 2, # non-negative int, 'profile', 'file'
- u'is_screen_locked': False,
- u'login_ui_type': 'nativeui', # or 'webui'
- u'is_logged_in': True}
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'GetLoginInfo' }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def WaitForSessionManagerRestart(self, function):
- """Call a function and wait for the ChromeOS session_manager to restart.
-
- Args:
- function: The function to call.
- """
- assert callable(function)
- pgrep_process = subprocess.Popen(['pgrep', 'session_manager'],
- stdout=subprocess.PIPE)
- old_pid = pgrep_process.communicate()[0].strip()
- function()
- return self.WaitUntil(lambda: self._IsSessionManagerReady(old_pid))
-
- def _WaitForInodeChange(self, path, function):
- """Call a function and wait for the specified file path to change.
-
- Args:
- path: The file path to check for changes.
- function: The function to call.
- """
- assert callable(function)
- old_inode = os.stat(path).st_ino
- function()
- return self.WaitUntil(lambda: self._IsInodeNew(path, old_inode))
-
- def ShowCreateAccountUI(self):
- """Go to the account creation page.
-
- This is the same as clicking the "Create Account" link on the
- ChromeOS login screen. Does not actually create a new account.
- Should be displaying the login screen to work.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'ShowCreateAccountUI' }
- # See note below under LoginAsGuest(). ShowCreateAccountUI() logs
- # the user in as guest in order to access the account creation page.
- assert self._WaitForInodeChange(
- self._named_channel_id,
- lambda: self._GetResultFromJSONRequest(cmd_dict, windex=None)), \
- 'Chrome did not reopen the testing channel after login as guest.'
- self.SetUp()
-
- def SkipToLogin(self, skip_image_selection=True):
- """Skips OOBE to the login screen.
-
- Assumes that we're at the beginning of OOBE.
-
- Args:
- skip_image_selection: Boolean indicating whether the user image selection
- screen should also be skipped.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'SkipToLogin',
- 'skip_image_selection': skip_image_selection }
- result = self._GetResultFromJSONRequest(cmd_dict, windex=None)
- assert result['next_screen'] == 'login', 'Unexpected wizard transition'
-
- def GetOOBEScreenInfo(self):
- """Queries info about the current OOBE screen.
-
- Returns:
- A dictionary with the following keys:
-
- 'screen_name': The title of the current OOBE screen as a string.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'GetOOBEScreenInfo' }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def AcceptOOBENetworkScreen(self):
- """Accepts OOBE network screen and advances to the next one.
-
- Assumes that we're already at the OOBE network screen.
-
- Returns:
- A dictionary with the following keys:
-
- 'next_screen': The title of the next OOBE screen as a string.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'AcceptOOBENetworkScreen' }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def AcceptOOBEEula(self, accepted, usage_stats_reporting=False):
- """Accepts OOBE EULA and advances to the next screen.
-
- Assumes that we're already at the OOBE EULA screen.
-
- Args:
- accepted: Boolean indicating whether the EULA should be accepted.
- usage_stats_reporting: Boolean indicating whether UMA should be enabled.
-
- Returns:
- A dictionary with the following keys:
-
- 'next_screen': The title of the next OOBE screen as a string.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'AcceptOOBEEula',
- 'accepted': accepted,
- 'usage_stats_reporting': usage_stats_reporting }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def CancelOOBEUpdate(self):
- """Skips update on OOBE and advances to the next screen.
-
- Returns:
- A dictionary with the following keys:
-
- 'next_screen': The title of the next OOBE screen as a string.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'CancelOOBEUpdate' }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def PickUserImage(self, image):
- """Chooses image for the newly created user.
-
- Should be called immediately after login.
-
- Args:
- image_type: type of user image to choose. Possible values:
- - "profile": Google profile image
- - non-negative int: one of the default images
-
- Returns:
- A dictionary with the following keys:
-
- 'next_screen': The title of the next OOBE screen as a string.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'PickUserImage',
- 'image': image }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def LoginAsGuest(self):
- """Login to chromeos as a guest user.
-
- Waits until logged in.
- Should be displaying the login screen to work.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'LoginAsGuest' }
- # Currently, logging in as guest causes session_manager to
- # restart Chrome, which will close the testing channel.
- # We need to call SetUp() again to reconnect to the new channel.
- assert self._WaitForInodeChange(
- self._named_channel_id,
- lambda: self._GetResultFromJSONRequest(cmd_dict, windex=None)), \
- 'Chrome did not reopen the testing channel after login as guest.'
- self.SetUp()
-
- def Login(self, username, password, timeout=120 * 1000):
- """Login to chromeos.
-
- Waits until logged in and browser is ready.
- Should be displaying the login screen to work.
-
- Note that in case of webui auth-extension-based login, gaia auth errors
- will not be noticed here, because the browser has no knowledge of it. In
- this case the GetNextEvent automation command will always time out.
-
- Args:
- username: the username to log in as.
- password: the user's password.
- timeout: timeout in ms; defaults to two minutes.
-
- Returns:
- An error string if an error occured.
- None otherwise.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- self._GetResultFromJSONRequest({'command': 'AddLoginEventObserver'},
- windex=None)
- cmd_dict = {
- 'command': 'SubmitLoginForm',
- 'username': username,
- 'password': password,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
- self.AddDomEventObserver('loginfail', automation_id=4444)
- try:
- if self.GetNextEvent(timeout=timeout).get('name') == 'loginfail':
- raise JSONInterfaceError('Login denied by auth server.')
- except JSONInterfaceError as e:
- raise JSONInterfaceError('Login failed. Perhaps Chrome crashed, '
- 'failed to start, or the login flow is '
- 'broken? Error message: %s' % str(e))
-
- def Logout(self):
- """Log out from ChromeOS and wait for session_manager to come up.
-
- This is equivalent to pressing the 'Sign out' button from the
- aura shell tray when logged in.
-
- Should be logged in to work. Re-initializes the automation channel
- after logout.
- """
- clear_profile_orig = self.get_clear_profile()
- self.set_clear_profile(False)
- assert self.GetLoginInfo()['is_logged_in'], \
- 'Trying to log out when already logged out.'
- def _SignOut():
- cmd_dict = { 'command': 'SignOut' }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
- assert self.WaitForSessionManagerRestart(_SignOut), \
- 'Session manager did not restart after logout.'
- self.__SetUp()
- self.set_clear_profile(clear_profile_orig)
-
- def LockScreen(self):
- """Locks the screen on chromeos.
-
- Waits until screen is locked.
- Should be logged in and screen should not be locked to work.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'LockScreen' }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def UnlockScreen(self, password):
- """Unlocks the screen on chromeos, authenticating the user's password first.
-
- Waits until screen is unlocked.
- Screen locker should be active for this to work.
-
- Returns:
- An error string if an error occured.
- None otherwise.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'UnlockScreen',
- 'password': password,
- }
- result = self._GetResultFromJSONRequest(cmd_dict, windex=None)
- return result.get('error_string')
-
- def SignoutInScreenLocker(self):
- """Signs out of chromeos using the screen locker's "Sign out" feature.
-
- Effectively the same as clicking the "Sign out" link on the screen locker.
- Screen should be locked for this to work.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'SignoutInScreenLocker' }
- assert self.WaitForSessionManagerRestart(
- lambda: self._GetResultFromJSONRequest(cmd_dict, windex=None)), \
- 'Session manager did not restart after logout.'
- self.__SetUp()
-
- def GetBatteryInfo(self):
- """Get details about battery state.
-
- Returns:
- A dictionary with the following keys:
-
- 'battery_is_present': bool
- 'line_power_on': bool
- if 'battery_is_present':
- 'battery_percentage': float (0 ~ 100)
- 'battery_fully_charged': bool
- if 'line_power_on':
- 'battery_time_to_full': int (seconds)
- else:
- 'battery_time_to_empty': int (seconds)
-
- If it is still calculating the time left, 'battery_time_to_full'
- and 'battery_time_to_empty' will be absent.
-
- Use 'battery_fully_charged' instead of 'battery_percentage'
- or 'battery_time_to_full' to determine whether the battery
- is fully charged, since the percentage is only approximate.
-
- Sample:
- { u'battery_is_present': True,
- u'line_power_on': False,
- u'battery_time_to_empty': 29617,
- u'battery_percentage': 100.0,
- u'battery_fully_charged': False }
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'GetBatteryInfo' }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def GetPanelInfo(self):
- """Get details about open ChromeOS panels.
-
- A panel is actually a type of browser window, so all of
- this information is also available using GetBrowserInfo().
-
- Returns:
- A dictionary.
- Sample:
- [{ 'incognito': False,
- 'renderer_pid': 4820,
- 'title': u'Downloads',
- 'url': u'chrome://active-downloads/'}]
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- panels = []
- for browser in self.GetBrowserInfo()['windows']:
- if browser['type'] != 'panel':
- continue
-
- panel = {}
- panels.append(panel)
- tab = browser['tabs'][0]
- panel['incognito'] = browser['incognito']
- panel['renderer_pid'] = tab['renderer_pid']
- panel['title'] = self.GetActiveTabTitle(browser['index'])
- panel['url'] = tab['url']
-
- return panels
-
- def EnableSpokenFeedback(self, enabled):
- """Enables or disables spoken feedback accessibility mode.
-
- Args:
- enabled: Boolean value indicating the desired state of spoken feedback.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'EnableSpokenFeedback',
- 'enabled': enabled,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def IsSpokenFeedbackEnabled(self):
- """Check whether spoken feedback accessibility mode is enabled.
-
- Returns:
- True if spoken feedback is enabled, False otherwise.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'IsSpokenFeedbackEnabled', }
- result = self._GetResultFromJSONRequest(cmd_dict, windex=None)
- return result.get('spoken_feedback')
-
- def GetTimeInfo(self, windex=0):
- """Gets info about the ChromeOS status bar clock.
-
- Set the 24-hour clock by using:
- self.SetPrefs('settings.clock.use_24hour_clock', True)
-
- Returns:
- a dictionary.
- Sample:
- {u'display_date': u'Tuesday, July 26, 2011',
- u'display_time': u'4:30',
- u'timezone': u'America/Los_Angeles'}
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'GetTimeInfo' }
- if self.GetLoginInfo()['is_logged_in']:
- return self._GetResultFromJSONRequest(cmd_dict, windex=windex)
- else:
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def SetTimezone(self, timezone):
- """Sets the timezone on ChromeOS. A user must be logged in.
-
- The timezone is the relative path to the timezone file in
- /usr/share/zoneinfo. For example, /usr/share/zoneinfo/America/Los_Angeles is
- 'America/Los_Angeles'. For a list of valid timezones see
- 'chromeos/settings/timezone_settings.cc'.
-
- This method does not return indication of success or failure.
- If the timezone is it falls back to a valid timezone.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'SetTimezone',
- 'timezone': timezone,
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def UpdateCheck(self):
- """Checks for a ChromeOS update. Blocks until finished updating.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'UpdateCheck' }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def GetVolumeInfo(self):
- """Gets the volume and whether the device is muted.
-
- Returns:
- a tuple.
- Sample:
- (47.763456790123456, False)
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'GetVolumeInfo' }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def SetVolume(self, volume):
- """Sets the volume on ChromeOS. Only valid if not muted.
-
- Args:
- volume: The desired volume level as a percent from 0 to 100.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- assert volume >= 0 and volume <= 100
- cmd_dict = {
- 'command': 'SetVolume',
- 'volume': float(volume),
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def SetMute(self, mute):
- """Sets whether ChromeOS is muted or not.
-
- Args:
- mute: True to mute, False to unmute.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'SetMute' }
- cmd_dict = {
- 'command': 'SetMute',
- 'mute': mute,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- # HTML Terminal
-
- def OpenCrosh(self):
- """Open crosh.
-
- Equivalent to pressing Ctrl-Alt-t.
- Opens in the last active (non-incognito) window.
-
- Waits long enough for crosh to load, but does not wait for the crosh
- prompt. Use WaitForHtermText() for that.
- """
- cmd_dict = { 'command': 'OpenCrosh' }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def WaitForHtermText(self, text, msg=None, tab_index=0, windex=0):
- """Waits for the given text in a hterm tab.
-
- Can be used to wait for the crosh> prompt or ssh prompt.
-
- This does not poll. It uses dom mutation observers to wait
- for the given text to show up.
-
- Args:
- text: the text to wait for. Can be a regex.
- msg: the failure message to emit if the text could not be found.
- tab_index: the tab for the hterm tab. Default: 0.
- windex: the window index for the hterm tab. Default: 0.
- """
- self.WaitForDomNode(
- xpath='//*[contains(text(), "%s")]' % text, frame_xpath='//iframe',
- msg=msg, tab_index=tab_index, windex=windex)
-
- def GetHtermRowsText(self, start, end, tab_index=0, windex=0):
- """Fetch rows from a html terminal tab.
-
- Works for both crosh and ssh tab.
- Uses term_.getRowsText(start, end) javascript call.
-
- Args:
- start: start line number (0-based).
- end: the end line (one beyond the line of interest).
- tab_index: the tab for the hterm tab. Default: 0.
- windex: the window index for the hterm tab. Default: 0.
- """
- return self.ExecuteJavascript(
- 'domAutomationController.send(term_.getRowsText(%d, %d))' % (
- start, end),
- tab_index=tab_index, windex=windex)
-
- def SendKeysToHterm(self, text, tab_index=0, windex=0):
- """Send keys to a html terminal tab.
-
- Works for both crosh and ssh tab.
- Uses term_.onVTKeystroke(str) javascript call.
-
- Args:
- text: the text to send.
- tab_index: the tab for the hterm tab. Default: 0.
- windex: the window index for the hterm tab. Default: 0.
- """
- return self.ExecuteJavascript(
- 'term_.onVTKeystroke("%s");'
- 'domAutomationController.send("done")' % text,
- tab_index=tab_index, windex=windex)
-
-
- def GetMemoryStatsChromeOS(self, duration):
- """Identifies and returns different kinds of current memory usage stats.
-
- This function samples values each second for |duration| seconds, then
- outputs the min, max, and ending values for each measurement type.
-
- Args:
- duration: The number of seconds to sample data before outputting the
- minimum, maximum, and ending values for each measurement type.
-
- Returns:
- A dictionary containing memory usage information. Each measurement type
- is associated with the min, max, and ending values from among all
- sampled values. Values are specified in KB.
- {
- 'gem_obj': { # GPU memory usage.
- 'min': ...,
- 'max': ...,
- 'end': ...,
- },
- 'gtt': { ... }, # GPU memory usage (graphics translation table).
- 'mem_free': { ... }, # CPU free memory.
- 'mem_available': { ... }, # CPU available memory.
- 'mem_shared': { ... }, # CPU shared memory.
- 'mem_cached': { ... }, # CPU cached memory.
- 'mem_anon': { ... }, # CPU anon memory (active + inactive).
- 'mem_file': { ... }, # CPU file memory (active + inactive).
- 'mem_slab': { ... }, # CPU slab memory.
- 'browser_priv': { ... }, # Chrome browser private memory.
- 'browser_shared': { ... }, # Chrome browser shared memory.
- 'gpu_priv': { ... }, # Chrome GPU private memory.
- 'gpu_shared': { ... }, # Chrome GPU shared memory.
- 'renderer_priv': { ... }, # Total private memory of all renderers.
- 'renderer_shared': { ... }, # Total shared memory of all renderers.
- }
- """
- logging.debug('Sampling memory information for %d seconds...' % duration)
- stats = {}
-
- for _ in xrange(duration):
- # GPU memory.
- gem_obj_path = '/sys/kernel/debug/dri/0/i915_gem_objects'
- if os.path.exists(gem_obj_path):
- p = subprocess.Popen('grep bytes %s' % gem_obj_path,
- stdout=subprocess.PIPE, shell=True)
- stdout = p.communicate()[0]
-
- gem_obj = re.search(
- '\d+ objects, (\d+) bytes\n', stdout).group(1)
- if 'gem_obj' not in stats:
- stats['gem_obj'] = []
- stats['gem_obj'].append(int(gem_obj) / 1024.0)
-
- gtt_path = '/sys/kernel/debug/dri/0/i915_gem_gtt'
- if os.path.exists(gtt_path):
- p = subprocess.Popen('grep bytes %s' % gtt_path,
- stdout=subprocess.PIPE, shell=True)
- stdout = p.communicate()[0]
-
- gtt = re.search(
- 'Total [\d]+ objects, ([\d]+) bytes', stdout).group(1)
- if 'gtt' not in stats:
- stats['gtt'] = []
- stats['gtt'].append(int(gtt) / 1024.0)
-
- # CPU memory.
- stdout = ''
- with open('/proc/meminfo') as f:
- stdout = f.read()
- mem_free = re.search('MemFree:\s*([\d]+) kB', stdout).group(1)
-
- if 'mem_free' not in stats:
- stats['mem_free'] = []
- stats['mem_free'].append(int(mem_free))
-
- mem_dirty = re.search('Dirty:\s*([\d]+) kB', stdout).group(1)
- mem_active_file = re.search(
- 'Active\(file\):\s*([\d]+) kB', stdout).group(1)
- mem_inactive_file = re.search(
- 'Inactive\(file\):\s*([\d]+) kB', stdout).group(1)
-
- with open('/proc/sys/vm/min_filelist_kbytes') as f:
- mem_min_file = f.read()
-
- # Available memory =
- # MemFree + ActiveFile + InactiveFile - DirtyMem - MinFileMem
- if 'mem_available' not in stats:
- stats['mem_available'] = []
- stats['mem_available'].append(
- int(mem_free) + int(mem_active_file) + int(mem_inactive_file) -
- int(mem_dirty) - int(mem_min_file))
-
- mem_shared = re.search('Shmem:\s*([\d]+) kB', stdout).group(1)
- if 'mem_shared' not in stats:
- stats['mem_shared'] = []
- stats['mem_shared'].append(int(mem_shared))
-
- mem_cached = re.search('Cached:\s*([\d]+) kB', stdout).group(1)
- if 'mem_cached' not in stats:
- stats['mem_cached'] = []
- stats['mem_cached'].append(int(mem_cached))
-
- mem_anon_active = re.search('Active\(anon\):\s*([\d]+) kB',
- stdout).group(1)
- mem_anon_inactive = re.search('Inactive\(anon\):\s*([\d]+) kB',
- stdout).group(1)
- if 'mem_anon' not in stats:
- stats['mem_anon'] = []
- stats['mem_anon'].append(int(mem_anon_active) + int(mem_anon_inactive))
-
- mem_file_active = re.search('Active\(file\):\s*([\d]+) kB',
- stdout).group(1)
- mem_file_inactive = re.search('Inactive\(file\):\s*([\d]+) kB',
- stdout).group(1)
- if 'mem_file' not in stats:
- stats['mem_file'] = []
- stats['mem_file'].append(int(mem_file_active) + int(mem_file_inactive))
-
- mem_slab = re.search('Slab:\s*([\d]+) kB', stdout).group(1)
- if 'mem_slab' not in stats:
- stats['mem_slab'] = []
- stats['mem_slab'].append(int(mem_slab))
-
- # Chrome process memory.
- pinfo = self.GetProcessInfo()['browsers'][0]['processes']
- total_renderer_priv = 0
- total_renderer_shared = 0
- for process in pinfo:
- mem_priv = process['working_set_mem']['priv']
- mem_shared = process['working_set_mem']['shared']
- if process['child_process_type'] == 'Browser':
- if 'browser_priv' not in stats:
- stats['browser_priv'] = []
- stats['browser_priv'].append(int(mem_priv))
- if 'browser_shared' not in stats:
- stats['browser_shared'] = []
- stats['browser_shared'].append(int(mem_shared))
- elif process['child_process_type'] == 'GPU':
- if 'gpu_priv' not in stats:
- stats['gpu_priv'] = []
- stats['gpu_priv'].append(int(mem_priv))
- if 'gpu_shared' not in stats:
- stats['gpu_shared'] = []
- stats['gpu_shared'].append(int(mem_shared))
- elif process['child_process_type'] == 'Tab':
- # Sum the memory of all renderer processes.
- total_renderer_priv += int(mem_priv)
- total_renderer_shared += int(mem_shared)
- if 'renderer_priv' not in stats:
- stats['renderer_priv'] = []
- stats['renderer_priv'].append(int(total_renderer_priv))
- if 'renderer_shared' not in stats:
- stats['renderer_shared'] = []
- stats['renderer_shared'].append(int(total_renderer_shared))
-
- time.sleep(1)
-
- # Compute min, max, and ending values to return.
- result = {}
- for measurement_type in stats:
- values = stats[measurement_type]
- result[measurement_type] = {
- 'min': min(values),
- 'max': max(values),
- 'end': values[-1],
- }
-
- return result
-
- ## ChromeOS section -- end
-
-
-class ExtraBrowser(PyUITest):
- """Launches a new browser with some extra flags.
-
- The new browser is launched with its own fresh profile.
- This class does not apply to ChromeOS.
- """
- def __init__(self, chrome_flags=[], methodName='runTest', **kwargs):
- """Accepts extra chrome flags for launching a new browser instance.
-
- Args:
- chrome_flags: list of extra flags when launching a new browser.
- """
- assert not PyUITest.IsChromeOS(), \
- 'This function cannot be used to launch a new browser in ChromeOS.'
- PyUITest.__init__(self, methodName=methodName, **kwargs)
- self._chrome_flags = chrome_flags
- PyUITest.setUp(self)
-
- def __del__(self):
- """Tears down the browser and then calls super class's destructor"""
- PyUITest.tearDown(self)
- PyUITest.__del__(self)
-
- def ExtraChromeFlags(self):
- """Prepares the browser to launch with specified Chrome flags."""
- return PyUITest.ExtraChromeFlags(self) + self._chrome_flags
-
-
-class _RemoteProxy():
- """Class for PyAuto remote method calls.
-
- Use this class along with RemoteHost.testRemoteHost to establish a PyAuto
- connection with another machine and make remote PyAuto calls. The RemoteProxy
- mimics a PyAuto object, so all json-style PyAuto calls can be made on it.
-
- The remote host acts as a dumb executor that receives method call requests,
- executes them, and sends all of the results back to the RemoteProxy, including
- the return value, thrown exceptions, and console output.
-
- The remote host should be running the same version of PyAuto as the proxy.
- A mismatch could lead to undefined behavior.
-
- Example usage:
- class MyTest(pyauto.PyUITest):
- def testRemoteExample(self):
- remote = pyauto._RemoteProxy(('127.0.0.1', 7410))
- remote.NavigateToURL('http://www.google.com')
- title = remote.GetActiveTabTitle()
- self.assertEqual(title, 'Google')
- """
- class RemoteException(Exception):
- pass
-
- def __init__(self, host):
- self.RemoteConnect(host)
-
- def RemoteConnect(self, host):
- begin = time.time()
- while time.time() - begin < 50:
- self._socket = socket.socket()
- if not self._socket.connect_ex(host):
- break
- time.sleep(0.25)
- else:
- # Make one last attempt, but raise a socket error on failure.
- self._socket = socket.socket()
- self._socket.connect(host)
-
- def RemoteDisconnect(self):
- if self._socket:
- self._socket.shutdown(socket.SHUT_RDWR)
- self._socket.close()
- self._socket = None
-
- def CreateTarget(self, target):
- """Registers the methods and creates a remote instance of a target.
-
- Any RPC calls will then be made on the remote target instance. Note that the
- remote instance will be a brand new instance and will have none of the state
- of the local instance. The target's class should have a constructor that
- takes no arguments.
- """
- self._Call('CreateTarget', target.__class__)
- self._RegisterClassMethods(target)
-
- def _RegisterClassMethods(self, remote_class):
- # Make remote-call versions of all remote_class methods.
- for method_name, _ in inspect.getmembers(remote_class, inspect.ismethod):
- # Ignore private methods and duplicates.
- if method_name[0] in string.letters and \
- getattr(self, method_name, None) is None:
- setattr(self, method_name, functools.partial(self._Call, method_name))
-
- def _Call(self, method_name, *args, **kwargs):
- # Send request.
- request = pickle.dumps((method_name, args, kwargs))
- if self._socket.send(request) != len(request):
- raise self.RemoteException('Error sending remote method call request.')
-
- # Receive response.
- response = self._socket.recv(4096)
- if not response:
- raise self.RemoteException('Client disconnected during method call.')
- result, stdout, stderr, exception = pickle.loads(response)
-
- # Print any output the client captured, throw any exceptions, and return.
- sys.stdout.write(stdout)
- sys.stderr.write(stderr)
- if exception:
- raise self.RemoteException('%s raised by remote client: %s' %
- (exception[0], exception[1]))
- return result
-
-
-class PyUITestSuite(pyautolib.PyUITestSuiteBase, unittest.TestSuite):
- """Base TestSuite for PyAuto UI tests."""
-
- def __init__(self, args):
- pyautolib.PyUITestSuiteBase.__init__(self, args)
-
- # Figure out path to chromium binaries
- browser_dir = os.path.normpath(os.path.dirname(pyautolib.__file__))
- logging.debug('Loading pyauto libs from %s', browser_dir)
- self.InitializeWithPath(pyautolib.FilePath(browser_dir))
- os.environ['PATH'] = browser_dir + os.pathsep + os.environ['PATH']
-
- unittest.TestSuite.__init__(self)
- cr_source_root = os.path.normpath(os.path.join(
- os.path.dirname(__file__), os.pardir, os.pardir, os.pardir))
- self.SetCrSourceRoot(pyautolib.FilePath(cr_source_root))
-
- # Start http server, if needed.
- global _OPTIONS
- if _OPTIONS and not _OPTIONS.no_http_server:
- self._StartHTTPServer()
- if _OPTIONS and _OPTIONS.remote_host:
- self._ConnectToRemoteHosts(_OPTIONS.remote_host.split(','))
-
- def __del__(self):
- # python unittest module is setup such that the suite gets deleted before
- # the test cases, which is odd because our test cases depend on
- # initializtions like exitmanager, autorelease pool provided by the
- # suite. Forcibly delete the test cases before the suite.
- del self._tests
- pyautolib.PyUITestSuiteBase.__del__(self)
-
- global _HTTP_SERVER
- if _HTTP_SERVER:
- self._StopHTTPServer()
-
- global _CHROME_DRIVER_FACTORY
- if _CHROME_DRIVER_FACTORY is not None:
- _CHROME_DRIVER_FACTORY.Stop()
-
- def _StartHTTPServer(self):
- """Start a local file server hosting data files over http://"""
- global _HTTP_SERVER
- assert not _HTTP_SERVER, 'HTTP Server already started'
- http_data_dir = _OPTIONS.http_data_dir
- http_server = pyautolib.SpawnedTestServer(
- pyautolib.SpawnedTestServer.TYPE_HTTP,
- '127.0.0.1',
- pyautolib.FilePath(http_data_dir))
- assert http_server.Start(), 'Could not start http server'
- _HTTP_SERVER = http_server
- logging.debug('Started http server at "%s".', http_data_dir)
-
- def _StopHTTPServer(self):
- """Stop the local http server."""
- global _HTTP_SERVER
- assert _HTTP_SERVER, 'HTTP Server not yet started'
- assert _HTTP_SERVER.Stop(), 'Could not stop http server'
- _HTTP_SERVER = None
- logging.debug('Stopped http server.')
-
- def _ConnectToRemoteHosts(self, addresses):
- """Connect to remote PyAuto instances using a RemoteProxy.
-
- The RemoteHost instances must already be running."""
- global _REMOTE_PROXY
- assert not _REMOTE_PROXY, 'Already connected to a remote host.'
- _REMOTE_PROXY = []
- for address in addresses:
- if address == 'localhost' or address == '127.0.0.1':
- self._StartLocalRemoteHost()
- _REMOTE_PROXY.append(_RemoteProxy((address, 7410)))
-
- def _StartLocalRemoteHost(self):
- """Start a remote PyAuto instance on the local machine."""
- # Add the path to our main class to the RemoteHost's
- # environment, so it can load that class at runtime.
- import __main__
- main_path = os.path.dirname(__main__.__file__)
- env = os.environ
- if env.get('PYTHONPATH', None):
- env['PYTHONPATH'] += ':' + main_path
- else:
- env['PYTHONPATH'] = main_path
-
- # Run it!
- subprocess.Popen([sys.executable, os.path.join(os.path.dirname(__file__),
- 'remote_host.py')], env=env)
-
-
-class _GTestTextTestResult(unittest._TextTestResult):
- """A test result class that can print formatted text results to a stream.
-
- Results printed in conformance with gtest output format, like:
- [ RUN ] autofill.AutofillTest.testAutofillInvalid: "test desc."
- [ OK ] autofill.AutofillTest.testAutofillInvalid
- [ RUN ] autofill.AutofillTest.testFillProfile: "test desc."
- [ OK ] autofill.AutofillTest.testFillProfile
- [ RUN ] autofill.AutofillTest.testFillProfileCrazyCharacters: "Test."
- [ OK ] autofill.AutofillTest.testFillProfileCrazyCharacters
- """
- def __init__(self, stream, descriptions, verbosity):
- unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
-
- def _GetTestURI(self, test):
- if sys.version_info[:2] <= (2, 4):
- return '%s.%s' % (unittest._strclass(test.__class__),
- test._TestCase__testMethodName)
- return '%s.%s.%s' % (test.__class__.__module__,
- test.__class__.__name__,
- test._testMethodName)
-
- def getDescription(self, test):
- return '%s: "%s"' % (self._GetTestURI(test), test.shortDescription())
-
- def startTest(self, test):
- unittest.TestResult.startTest(self, test)
- self.stream.writeln('[ RUN ] %s' % self.getDescription(test))
-
- def addSuccess(self, test):
- unittest.TestResult.addSuccess(self, test)
- self.stream.writeln('[ OK ] %s' % self._GetTestURI(test))
-
- def addError(self, test, err):
- unittest.TestResult.addError(self, test, err)
- self.stream.writeln('[ ERROR ] %s' % self._GetTestURI(test))
-
- def addFailure(self, test, err):
- unittest.TestResult.addFailure(self, test, err)
- self.stream.writeln('[ FAILED ] %s' % self._GetTestURI(test))
-
-
-class PyAutoTextTestRunner(unittest.TextTestRunner):
- """Test Runner for PyAuto tests that displays results in textual format.
-
- Results are displayed in conformance with gtest output.
- """
- def __init__(self, verbosity=1):
- unittest.TextTestRunner.__init__(self,
- stream=sys.stderr,
- verbosity=verbosity)
-
- def _makeResult(self):
- return _GTestTextTestResult(self.stream, self.descriptions, self.verbosity)
-
-
-# Implementation inspired from unittest.main()
-class Main(object):
- """Main program for running PyAuto tests."""
-
- _options, _args = None, None
- _tests_filename = 'PYAUTO_TESTS'
- _platform_map = {
- 'win32': 'win',
- 'darwin': 'mac',
- 'linux2': 'linux',
- 'linux3': 'linux',
- 'chromeos': 'chromeos',
- }
-
- def __init__(self):
- self._ParseArgs()
- self._Run()
-
- def _ParseArgs(self):
- """Parse command line args."""
- parser = optparse.OptionParser()
- parser.add_option(
- '', '--channel-id', type='string', default='',
- help='Name of channel id, if using named interface.')
- parser.add_option(
- '', '--chrome-flags', type='string', default='',
- help='Flags passed to Chrome. This is in addition to the usual flags '
- 'like suppressing first-run dialogs, enabling automation. '
- 'See chrome/common/chrome_switches.cc for the list of flags '
- 'chrome understands.')
- parser.add_option(
- '', '--http-data-dir', type='string',
- default=os.path.join('chrome', 'test', 'data'),
- help='Relative path from which http server should serve files.')
- parser.add_option(
- '-L', '--list-tests', action='store_true', default=False,
- help='List all tests, and exit.')
- parser.add_option(
- '--shard',
- help='Specify sharding params. Example: 1/3 implies split the list of '
- 'tests into 3 groups of which this is the 1st.')
- parser.add_option(
- '', '--log-file', type='string', default=None,
- help='Provide a path to a file to which the logger will log')
- parser.add_option(
- '', '--no-http-server', action='store_true', default=False,
- help='Do not start an http server to serve files in data dir.')
- parser.add_option(
- '', '--remote-host', type='string', default=None,
- help='Connect to remote hosts for remote automation. If "localhost" '
- '"127.0.0.1" is specified, a remote host will be launched '
- 'automatically on the local machine.')
- parser.add_option(
- '', '--repeat', type='int', default=1,
- help='Number of times to repeat the tests. Useful to determine '
- 'flakiness. Defaults to 1.')
- parser.add_option(
- '-S', '--suite', type='string', default='FULL',
- help='Name of the suite to load. Defaults to "FULL".')
- parser.add_option(
- '-v', '--verbose', action='store_true', default=False,
- help='Make PyAuto verbose.')
- parser.add_option(
- '-D', '--wait-for-debugger', action='store_true', default=False,
- help='Block PyAuto on startup for attaching debugger.')
-
- self._options, self._args = parser.parse_args()
- global _OPTIONS
- _OPTIONS = self._options # Export options so other classes can access.
-
- # Set up logging. All log messages will be prepended with a timestamp.
- format = '%(asctime)s %(levelname)-8s %(message)s'
-
- level = logging.INFO
- if self._options.verbose:
- level=logging.DEBUG
-
- logging.basicConfig(level=level, format=format,
- filename=self._options.log_file)
-
- def TestsDir(self):
- """Returns the path to dir containing tests.
-
- This is typically the dir containing the tests description file.
- This method should be overridden by derived class to point to other dirs
- if needed.
- """
- return os.path.dirname(__file__)
-
- @staticmethod
- def _ImportTestsFromName(name):
- """Get a list of all test names from the given string.
-
- Args:
- name: dot-separated string for a module, a test case or a test method.
- Examples: omnibox (a module)
- omnibox.OmniboxTest (a test case)
- omnibox.OmniboxTest.testA (a test method)
-
- Returns:
- [omnibox.OmniboxTest.testA, omnibox.OmniboxTest.testB, ...]
- """
- def _GetTestsFromTestCase(class_obj):
- """Return all test method names from given class object."""
- return [class_obj.__name__ + '.' + x for x in dir(class_obj) if
- x.startswith('test')]
-
- def _GetTestsFromModule(module):
- """Return all test method names from the given module object."""
- tests = []
- for name in dir(module):
- obj = getattr(module, name)
- if (isinstance(obj, (type, types.ClassType)) and
- issubclass(obj, PyUITest) and obj != PyUITest):
- tests.extend([module.__name__ + '.' + x for x in
- _GetTestsFromTestCase(obj)])
- return tests
-
- module = None
- # Locate the module
- parts = name.split('.')
- parts_copy = parts[:]
- while parts_copy:
- try:
- module = __import__('.'.join(parts_copy))
- break
- except ImportError:
- del parts_copy[-1]
- if not parts_copy: raise
- # We have the module. Pick the exact test method or class asked for.
- parts = parts[1:]
- obj = module
- for part in parts:
- obj = getattr(obj, part)
-
- if type(obj) == types.ModuleType:
- return _GetTestsFromModule(obj)
- elif (isinstance(obj, (type, types.ClassType)) and
- issubclass(obj, PyUITest) and obj != PyUITest):
- return [module.__name__ + '.' + x for x in _GetTestsFromTestCase(obj)]
- elif type(obj) == types.UnboundMethodType:
- return [name]
- else:
- logging.warn('No tests in "%s"', name)
- return []
-
- def _HasTestCases(self, module_string):
- """Determines if we have any PyUITest test case classes in the module
- identified by |module_string|."""
- module = __import__(module_string)
- for name in dir(module):
- obj = getattr(module, name)
- if (isinstance(obj, (type, types.ClassType)) and
- issubclass(obj, PyUITest)):
- return True
- return False
-
- def _ExpandTestNames(self, args):
- """Returns a list of tests loaded from the given args.
-
- The given args can be either a module (ex: module1) or a testcase
- (ex: module2.MyTestCase) or a test (ex: module1.MyTestCase.testX)
- or a suite name (ex: @FULL). If empty, the tests in the already imported
- modules are loaded.
-
- Args:
- args: [module1, module2, module3.testcase, module4.testcase.testX]
- These modules or test cases or tests should be importable.
- Suites can be specified by prefixing @. Example: @FULL
-
- Returns:
- a list of expanded test names. Example:
- [
- 'module1.TestCase1.testA',
- 'module1.TestCase1.testB',
- 'module2.TestCase2.testX',
- 'module3.testcase.testY',
- 'module4.testcase.testX'
- ]
- """
-
- def _TestsFromDescriptionFile(suite):
- pyauto_tests_file = os.path.join(self.TestsDir(), self._tests_filename)
- if suite:
- logging.debug("Reading %s (@%s)", pyauto_tests_file, suite)
- else:
- logging.debug("Reading %s", pyauto_tests_file)
- if not os.path.exists(pyauto_tests_file):
- logging.warn("%s missing. Cannot load tests.", pyauto_tests_file)
- return []
- else:
- return self._ExpandTestNamesFrom(pyauto_tests_file, suite)
-
- if not args: # Load tests ourselves
- if self._HasTestCases('__main__'): # we are running a test script
- module_name = os.path.splitext(os.path.basename(sys.argv[0]))[0]
- args.append(module_name) # run the test cases found in it
- else: # run tests from the test description file
- args = _TestsFromDescriptionFile(self._options.suite)
- else: # Check args with @ prefix for suites
- out_args = []
- for arg in args:
- if arg.startswith('@'):
- suite = arg[1:]
- out_args += _TestsFromDescriptionFile(suite)
- else:
- out_args.append(arg)
- args = out_args
- return args
-
- def _ExpandTestNamesFrom(self, filename, suite):
- """Load test names from the given file.
-
- Args:
- filename: the file to read the tests from
- suite: the name of the suite to load from |filename|.
-
- Returns:
- a list of test names
- [module.testcase.testX, module.testcase.testY, ..]
- """
- suites = PyUITest.EvalDataFrom(filename)
- platform = sys.platform
- if PyUITest.IsChromeOS(): # check if it's chromeos
- platform = 'chromeos'
- assert platform in self._platform_map, '%s unsupported' % platform
- def _NamesInSuite(suite_name):
- logging.debug('Expanding suite %s', suite_name)
- platforms = suites.get(suite_name)
- names = platforms.get('all', []) + \
- platforms.get(self._platform_map[platform], [])
- ret = []
- # Recursively include suites if any. Suites begin with @.
- for name in names:
- if name.startswith('@'): # Include another suite
- ret.extend(_NamesInSuite(name[1:]))
- else:
- ret.append(name)
- return ret
-
- assert suite in suites, '%s: No such suite in %s' % (suite, filename)
- all_names = _NamesInSuite(suite)
- args = []
- excluded = []
- # Find all excluded tests. Excluded tests begin with '-'.
- for name in all_names:
- if name.startswith('-'): # Exclude
- excluded.extend(self._ImportTestsFromName(name[1:]))
- else:
- args.extend(self._ImportTestsFromName(name))
- for name in excluded:
- if name in args:
- args.remove(name)
- else:
- logging.warn('Cannot exclude %s. Not included. Ignoring', name)
- if excluded:
- logging.debug('Excluded %d test(s): %s', len(excluded), excluded)
- return args
-
- def _Run(self):
- """Run the tests."""
- if self._options.wait_for_debugger:
- raw_input('Attach debugger to process %s and hit <enter> ' % os.getpid())
-
- suite_args = [sys.argv[0]]
- chrome_flags = self._options.chrome_flags
- # Set CHROME_HEADLESS. It enables crash reporter on posix.
- os.environ['CHROME_HEADLESS'] = '1'
- os.environ['EXTRA_CHROME_FLAGS'] = chrome_flags
- test_names = self._ExpandTestNames(self._args)
-
- # Shard, if requested (--shard).
- if self._options.shard:
- matched = re.match('(\d+)/(\d+)', self._options.shard)
- if not matched:
- print >>sys.stderr, 'Invalid sharding params: %s' % self._options.shard
- sys.exit(1)
- shard_index = int(matched.group(1)) - 1
- num_shards = int(matched.group(2))
- if shard_index < 0 or shard_index >= num_shards:
- print >>sys.stderr, 'Invalid sharding params: %s' % self._options.shard
- sys.exit(1)
- test_names = pyauto_utils.Shard(test_names, shard_index, num_shards)
-
- test_names *= self._options.repeat
- logging.debug("Loading %d tests from %s", len(test_names), test_names)
- if self._options.list_tests: # List tests and exit
- for name in test_names:
- print name
- sys.exit(0)
- pyauto_suite = PyUITestSuite(suite_args)
- loaded_tests = unittest.defaultTestLoader.loadTestsFromNames(test_names)
- pyauto_suite.addTests(loaded_tests)
- verbosity = 1
- if self._options.verbose:
- verbosity = 2
- result = PyAutoTextTestRunner(verbosity=verbosity).run(pyauto_suite)
- del loaded_tests # Need to destroy test cases before the suite
- del pyauto_suite
- successful = result.wasSuccessful()
- if not successful:
- pyauto_tests_file = os.path.join(self.TestsDir(), self._tests_filename)
- print >>sys.stderr, 'Tests can be disabled by editing %s. ' \
- 'Ref: %s' % (pyauto_tests_file, _PYAUTO_DOC_URL)
- sys.exit(not successful)
-
-
-if __name__ == '__main__':
- Main()
diff --git a/chrome/test/pyautolib/pyauto_errors.py b/chrome/test/pyautolib/pyauto_errors.py
deleted file mode 100644
index 5b56aa9..0000000
--- a/chrome/test/pyautolib/pyauto_errors.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (c) 2012 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.
-
-"""PyAuto Errors."""
-
-class JavascriptRuntimeError(RuntimeError):
- """Represent an error raised by injected Javascript."""
- pass
-
-
-class JSONInterfaceError(RuntimeError):
- """Represent an error in the JSON IPC interface."""
- pass
-
-
-class AutomationCommandFail(JSONInterfaceError):
- """Represent an automation command failure.
-
- These failures are passed back from the Chrome side of the IPC.
- """
- pass
-
-
-class AutomationCommandTimeout(JSONInterfaceError):
- """Represent an automation command failure due to timeout."""
- pass
-
-
-class NTPThumbnailNotShownError(RuntimeError):
- """Represent an error while attempting to manipulate a NTP thumbnail.
-
- This is due to it not being visible to a real user.
- """
- pass
diff --git a/chrome/test/pyautolib/pyauto_paths.py b/chrome/test/pyautolib/pyauto_paths.py
deleted file mode 100644
index 412b661..0000000
--- a/chrome/test/pyautolib/pyauto_paths.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (c) 2012 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.
-
-"""Common paths for pyauto tests."""
-
-import os
-import sys
-
-
-def GetSourceDir():
- """Returns src/ directory."""
- script_dir = os.path.abspath(os.path.dirname(__file__))
- return os.path.join(script_dir, os.pardir, os.pardir, os.pardir)
-
-
-def GetThirdPartyDir():
- """Returns src/third_party directory."""
- return os.path.join(GetSourceDir(), 'third_party')
-
-
-def GetBuildDirs():
- """Returns list of possible build directories."""
- # List of dirs that can contain a Debug/Release build.
- outer_dirs = {
- 'linux2': ['out'],
- 'linux3': ['out'],
- 'darwin': ['out', 'xcodebuild'],
- 'win32': ['chrome', 'build', 'out'],
- 'cygwin': ['chrome'],
- }.get(sys.platform, [])
- src_dir = GetSourceDir()
- build_dirs = []
- for dir in outer_dirs:
- build_dirs += [os.path.join(src_dir, dir, 'Debug')]
- build_dirs += [os.path.join(src_dir, dir, 'Release')]
- return build_dirs
-
-
-def GetChromeDriverExe():
- """Returns path to ChromeDriver executable, or None if cannot be found."""
- exe_name = 'chromedriver'
- if sys.platform == 'win32':
- exe_name += '.exe'
-
- import pyautolib
- dir = os.path.dirname(pyautolib.__file__)
- exe = os.path.join(dir, exe_name)
- if os.path.exists(exe):
- return exe
- return None
diff --git a/chrome/test/pyautolib/pyauto_utils.py b/chrome/test/pyautolib/pyauto_utils.py
deleted file mode 100644
index 8b16a8e..0000000
--- a/chrome/test/pyautolib/pyauto_utils.py
+++ /dev/null
@@ -1,277 +0,0 @@
-# Copyright (c) 2012 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.
-
-"""Utilities for PyAuto."""
-
-import httplib
-import logging
-import os
-import shutil
-import socket
-import sys
-import tempfile
-import unittest
-import urlparse
-import zipfile
-
-
-class ExistingPathReplacer(object):
- """Facilitates backing up a given path (file or dir)..
-
- Often you want to manipulate a directory or file for testing but don't want to
- meddle with the existing contents. This class lets you make a backup, and
- reinstate the backup when done. A backup is made in an adjacent directory,
- so you need to make sure you have write permissions to the parent directory.
-
- Works seemlessly in cases where the requested path already exists, or not.
-
- Automatically reinstates the backed up path (if any) when object is deleted.
- """
- _path = ''
- _backup_dir = None # dir to which existing content is backed up
- _backup_basename = ''
-
- def __init__(self, path, path_type='dir'):
- """Initialize the object, making backups if necessary.
-
- Args:
- path: the requested path to file or directory
- path_type: path type. Options: 'file', 'dir'. Default: 'dir'
- """
- assert path_type in ('file', 'dir'), 'Invalid path_type: %s' % path_type
- self._path_type = path_type
- self._path = path
- if os.path.exists(self._path):
- if 'dir' == self._path_type:
- assert os.path.isdir(self._path), '%s is not a directory' % self._path
- else:
- assert os.path.isfile(self._path), '%s is not a file' % self._path
- # take a backup
- self._backup_basename = os.path.basename(self._path)
- self._backup_dir = tempfile.mkdtemp(dir=os.path.dirname(self._path),
- prefix='bkp-' + self._backup_basename)
- logging.info('Backing up %s in %s' % (self._path, self._backup_dir))
- shutil.move(self._path,
- os.path.join(self._backup_dir, self._backup_basename))
- self._CreateRequestedPath()
-
- def __del__(self):
- """Cleanup. Reinstate backup."""
- self._CleanupRequestedPath()
- if self._backup_dir: # Reinstate, if backed up.
- from_path = os.path.join(self._backup_dir, self._backup_basename)
- logging.info('Reinstating backup from %s to %s' % (from_path, self._path))
- shutil.move(from_path, self._path)
- self._RemoveBackupDir()
-
- def _CreateRequestedPath(self):
- # Create intermediate dirs if needed.
- if not os.path.exists(os.path.dirname(self._path)):
- os.makedirs(os.path.dirname(self._path))
- if 'dir' == self._path_type:
- os.mkdir(self._path)
- else:
- open(self._path, 'w').close()
-
- def _CleanupRequestedPath(self):
- if os.path.exists(self._path):
- if os.path.isdir(self._path):
- shutil.rmtree(self._path, ignore_errors=True)
- else:
- os.remove(self._path)
-
- def _RemoveBackupDir(self):
- if self._backup_dir and os.path.isdir(self._backup_dir):
- shutil.rmtree(self._backup_dir, ignore_errors=True)
-
-
-def RemovePath(path):
- """Remove the given path (file or dir)."""
- if os.path.isdir(path):
- shutil.rmtree(path, ignore_errors=True)
- return
- try:
- os.remove(path)
- except OSError:
- pass
-
-
-def UnzipFilenameToDir(filename, dir):
- """Unzip |filename| to directory |dir|.
-
- This works with as low as python2.4 (used on win).
- """
- zf = zipfile.ZipFile(filename)
- pushd = os.getcwd()
- if not os.path.isdir(dir):
- os.mkdir(dir)
- os.chdir(dir)
- # Extract files.
- for info in zf.infolist():
- name = info.filename
- if name.endswith('/'): # dir
- if not os.path.isdir(name):
- os.makedirs(name)
- else: # file
- dir = os.path.dirname(name)
- if not os.path.isdir(dir):
- os.makedirs(dir)
- out = open(name, 'wb')
- out.write(zf.read(name))
- out.close()
- # Set permissions. Permission info in external_attr is shifted 16 bits.
- os.chmod(name, info.external_attr >> 16L)
- os.chdir(pushd)
-
-
-def GetCurrentPlatform():
- """Get a string representation for the current platform.
-
- Returns:
- 'mac', 'win' or 'linux'
- """
- if sys.platform == 'darwin':
- return 'mac'
- if sys.platform == 'win32':
- return 'win'
- if sys.platform.startswith('linux'):
- return 'linux'
- raise RuntimeError('Unknown platform')
-
-
-def PrintPerfResult(graph_name, series_name, data_point, units,
- show_on_waterfall=False):
- """Prints a line to stdout that is specially formatted for the perf bots.
-
- Args:
- graph_name: String name for the graph on which to plot the data.
- series_name: String name for the series (line on the graph) associated with
- the data. This is also the string displayed on the waterfall
- if |show_on_waterfall| is True.
- data_point: Numeric data value to plot on the graph for the current build.
- This can be a single value or an array of values. If an array,
- the graph will plot the average of the values, along with error
- bars.
- units: The string unit of measurement for the given |data_point|.
- show_on_waterfall: Whether or not to display this result directly on the
- buildbot waterfall itself (in the buildbot step running
- this test on the waterfall page, not the stdio page).
- """
- waterfall_indicator = ['', '*'][show_on_waterfall]
- print '%sRESULT %s: %s= %s %s' % (
- waterfall_indicator, graph_name, series_name,
- str(data_point).replace(' ', ''), units)
- sys.stdout.flush()
-
-
-def Shard(ilist, shard_index, num_shards):
- """Shard a given list and return the group at index |shard_index|.
-
- Args:
- ilist: input list
- shard_index: 0-based sharding index
- num_shards: shard count
- """
- chunk_size = len(ilist) / num_shards
- chunk_start = shard_index * chunk_size
- if shard_index == num_shards - 1: # Exhaust the remainder in the last shard.
- chunk_end = len(ilist)
- else:
- chunk_end = chunk_start + chunk_size
- return ilist[chunk_start:chunk_end]
-
-
-def WaitForDomElement(pyauto, driver, xpath):
- """Wait for the UI element to appear.
-
- Args:
- pyauto: an instance of pyauto.PyUITest.
- driver: an instance of chrome driver or a web element.
- xpath: the xpath of the element to wait for.
-
- Returns:
- The element if it is found.
- NoSuchElementException if it is not found.
- """
- pyauto.WaitUntil(lambda: len(driver.find_elements_by_xpath(xpath)) > 0)
- return driver.find_element_by_xpath(xpath)
-
-
-def DoesUrlExist(url):
- """Determines whether a resource exists at the given URL.
-
- Args:
- url: URL to be verified.
-
- Returns:
- True if url exists, otherwise False.
- """
- parsed = urlparse.urlparse(url)
- try:
- conn = httplib.HTTPConnection(parsed.netloc)
- conn.request('HEAD', parsed.path)
- response = conn.getresponse()
- except (socket.gaierror, socket.error):
- return False
- finally:
- conn.close()
- # Follow both permanent (301) and temporary (302) redirects.
- if response.status == 302 or response.status == 301:
- return DoesUrlExist(response.getheader('location'))
- return response.status == 200
-
-
-class _GTestTextTestResult(unittest._TextTestResult):
- """A test result class that can print formatted text results to a stream.
-
- Results printed in conformance with gtest output format, like:
- [ RUN ] autofill.AutofillTest.testAutofillInvalid: "test desc."
- [ OK ] autofill.AutofillTest.testAutofillInvalid
- [ RUN ] autofill.AutofillTest.testFillProfile: "test desc."
- [ OK ] autofill.AutofillTest.testFillProfile
- [ RUN ] autofill.AutofillTest.testFillProfileCrazyCharacters: "Test."
- [ OK ] autofill.AutofillTest.testFillProfileCrazyCharacters
- """
-
- def __init__(self, stream, descriptions, verbosity):
- unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
-
- def _GetTestURI(self, test):
- if sys.version_info[:2] <= (2, 4):
- return '%s.%s' % (unittest._strclass(test.__class__),
- test._TestCase__testMethodName)
- return '%s.%s' % (unittest._strclass(test.__class__), test._testMethodName)
-
- def getDescription(self, test):
- return '%s: "%s"' % (self._GetTestURI(test), test.shortDescription())
-
- def startTest(self, test):
- unittest.TestResult.startTest(self, test)
- self.stream.writeln('[ RUN ] %s' % self.getDescription(test))
-
- def addSuccess(self, test):
- unittest.TestResult.addSuccess(self, test)
- self.stream.writeln('[ OK ] %s' % self._GetTestURI(test))
-
- def addError(self, test, err):
- unittest.TestResult.addError(self, test, err)
- self.stream.writeln('[ ERROR ] %s' % self._GetTestURI(test))
-
- def addFailure(self, test, err):
- unittest.TestResult.addFailure(self, test, err)
- self.stream.writeln('[ FAILED ] %s' % self._GetTestURI(test))
-
-
-class GTestTextTestRunner(unittest.TextTestRunner):
- """Test Runner for displaying test results in textual format.
-
- Results are displayed in conformance with gtest output.
- """
-
- def __init__(self, verbosity=1):
- unittest.TextTestRunner.__init__(self, stream=sys.stderr,
- verbosity=verbosity)
-
- def _makeResult(self):
- return _GTestTextTestResult(self.stream, self.descriptions, self.verbosity)
diff --git a/chrome/test/pyautolib/pyauto_utils_test.py b/chrome/test/pyautolib/pyauto_utils_test.py
deleted file mode 100755
index 3a3a85c..0000000
--- a/chrome/test/pyautolib/pyauto_utils_test.py
+++ /dev/null
@@ -1,86 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-"""Tests for pyauto_utils."""
-
-import glob
-import os
-import shutil
-import tempfile
-import unittest
-
-import pyauto_utils
-
-
-class ExistingPathReplacerTest(unittest.TestCase):
- """Tests for ExistingPathReplacer."""
-
- def setUp(self):
- self._workdir = tempfile.mkdtemp()
- self.assertEqual(0, len(os.listdir(self._workdir)))
-
- def tearDown(self):
- shutil.rmtree(self._workdir, ignore_errors=True)
-
- def _CreateFile(self, path):
- fp = open(path, 'w')
- fp.write('magic')
- fp.close()
-
- def _IsOrigFile(self, path):
- if not os.path.isfile(path):
- return False
- return open(path).read() == 'magic'
-
- def testNonExistingFile(self):
- """Test when the requested file does not exist."""
- myfile = os.path.join(self._workdir, 'myfile.txt')
- self.assertFalse(os.path.isfile(myfile))
- r = pyauto_utils.ExistingPathReplacer(myfile, path_type='file')
- self.assertTrue(os.path.isfile(myfile))
- del r
- self.assertEqual(0, len(os.listdir(self._workdir)))
-
- def testExistingFile(self):
- """Test when the requested file exists."""
- myfile = os.path.join(self._workdir, 'myfile.txt')
- self._CreateFile(myfile)
- self.assertTrue(self._IsOrigFile(myfile))
- r = pyauto_utils.ExistingPathReplacer(myfile, path_type='file')
- self.assertFalse(self._IsOrigFile(myfile))
- self.assertEqual(2, len(os.listdir(self._workdir)))
- del r
- self.assertEqual(1, len(os.listdir(self._workdir)))
- self.assertTrue(self._IsOrigFile(myfile))
-
- def testNonExistingDir(self):
- """Test when the requested dir does not exist."""
- mydir = os.path.join(self._workdir, 'mydir')
- self.assertFalse(os.path.isdir(mydir))
- r = pyauto_utils.ExistingPathReplacer(mydir, path_type='dir')
- self.assertTrue(os.path.isdir(mydir))
- self.assertEqual(0, len(os.listdir(mydir)))
- del r
- self.assertFalse(os.path.isdir(mydir))
-
- def testExistingDir(self):
- """Test when the requested dir exists."""
- # Create a dir with one file
- mydir = os.path.join(self._workdir, 'mydir')
- os.makedirs(mydir)
- self.assertEqual(1, len(os.listdir(self._workdir)))
- myfile = os.path.join(mydir, 'myfile.txt')
- open(myfile, 'w').close()
- self.assertTrue(os.path.isfile(myfile))
- r = pyauto_utils.ExistingPathReplacer(mydir)
- self.assertEqual(2, len(os.listdir(self._workdir)))
- self.assertFalse(os.path.isfile(myfile))
- del r
- self.assertEqual(1, len(os.listdir(self._workdir)))
- self.assertTrue(os.path.isfile(myfile))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/chrome/test/pyautolib/pyautolib.cc b/chrome/test/pyautolib/pyautolib.cc
deleted file mode 100644
index 1a523953..0000000
--- a/chrome/test/pyautolib/pyautolib.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright (c) 2012 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 "base/base_paths.h"
-#include "base/json/json_writer.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/path_service.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
-#include "base/values.h"
-#include "chrome/common/automation_messages.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/test/automation/automation_proxy.h"
-#include "chrome/test/automation/tab_proxy.h"
-#include "chrome/test/pyautolib/pyautolib.h"
-#include "url/gurl.h"
-
-// PyUITestSuiteBase
-PyUITestSuiteBase::PyUITestSuiteBase(int argc, char** argv)
- : UITestSuite(argc, argv) {
-}
-
-PyUITestSuiteBase::~PyUITestSuiteBase() {
-#if defined(OS_MACOSX)
- pool_.Recycle();
-#endif
- Shutdown();
-}
-
-void PyUITestSuiteBase::InitializeWithPath(const base::FilePath& browser_dir) {
- SetBrowserDirectory(browser_dir);
- UITestSuite::Initialize();
-}
-
-void PyUITestSuiteBase::SetCrSourceRoot(const base::FilePath& path) {
- PathService::Override(base::DIR_SOURCE_ROOT, path);
-}
-
-// PyUITestBase
-PyUITestBase::PyUITestBase(bool clear_profile, std::wstring homepage)
- : UITestBase() {
- set_clear_profile(clear_profile);
- set_homepage(base::WideToUTF8(homepage));
- // We add this so that pyauto can execute javascript in the renderer and
- // read values back.
- dom_automation_enabled_ = true;
- message_loop_ = GetSharedMessageLoop(base::MessageLoop::TYPE_DEFAULT);
-}
-
-PyUITestBase::~PyUITestBase() {
-}
-
-// static, refer .h for why it needs to be static
-base::MessageLoop* PyUITestBase::message_loop_ = NULL;
-
-// static
-base::MessageLoop* PyUITestBase::GetSharedMessageLoop(
- base::MessageLoop::Type msg_loop_type) {
- if (!message_loop_) // Create a shared instance of MessageLoop
- message_loop_ = new base::MessageLoop(msg_loop_type);
- return message_loop_;
-}
-
-void PyUITestBase::Initialize(const base::FilePath& browser_dir) {
- UITestBase::SetBrowserDirectory(browser_dir);
-}
-
-ProxyLauncher* PyUITestBase::CreateProxyLauncher() {
- if (named_channel_id_.empty())
- return new AnonymousProxyLauncher(false);
- return new NamedProxyLauncher(named_channel_id_, false, false);
-}
-
-void PyUITestBase::SetUp() {
- UITestBase::SetUp();
-}
-
-void PyUITestBase::TearDown() {
- UITestBase::TearDown();
-}
-
-void PyUITestBase::SetLaunchSwitches() {
- // Clear the homepage because some of the pyauto tests don't work correctly
- // if a URL argument is passed.
- std::string homepage_original;
- std::swap(homepage_original, homepage_);
-
- UITestBase::SetLaunchSwitches();
-
- // However, we *do* want the --homepage switch.
- std::swap(homepage_original, homepage_);
- launch_arguments_.AppendSwitchASCII(switches::kHomePage, homepage_);
-}
-
-AutomationProxy* PyUITestBase::automation() const {
- AutomationProxy* automation_proxy = UITestBase::automation();
- if (!automation_proxy) {
- LOG(FATAL) << "The automation proxy is NULL.";
- }
- return automation_proxy;
-}
-
-std::string PyUITestBase::_SendJSONRequest(int window_index,
- const std::string& request,
- int timeout) {
- std::string response;
- bool success;
- AutomationProxy* automation_sender = automation();
- base::TimeTicks time = base::TimeTicks::Now();
-
- if (!automation_sender) {
- ErrorResponse("Automation proxy does not exist", request, false, &response);
- } else if (!automation_sender->channel()) {
- ErrorResponse("Chrome automation IPC channel was found already broken",
- request, false, &response);
- } else if (!automation_sender->Send(
- new AutomationMsg_SendJSONRequest(window_index, request, &response,
- &success),
- timeout)) {
- RequestFailureResponse(request, base::TimeTicks::Now() - time,
- base::TimeDelta::FromMilliseconds(timeout),
- &response);
- }
- return response;
-}
-
-void PyUITestBase::ErrorResponse(
- const std::string& error_string,
- const std::string& request,
- bool is_timeout,
- std::string* response) {
- base::DictionaryValue error_dict;
- std::string error_msg = base::StringPrintf("%s for %s", error_string.c_str(),
- request.c_str());
- LOG(ERROR) << "Error during automation: " << error_msg;
- error_dict.SetString("error", error_msg);
- error_dict.SetBoolean("is_interface_error", true);
- error_dict.SetBoolean("is_interface_timeout", is_timeout);
- base::JSONWriter::Write(&error_dict, response);
-}
-
-void PyUITestBase::RequestFailureResponse(
- const std::string& request,
- const base::TimeDelta& duration,
- const base::TimeDelta& timeout,
- std::string* response) {
- // TODO(craigdh): Determine timeout directly from IPC's Send().
- if (duration >= timeout) {
- ErrorResponse(
- base::StringPrintf("Chrome automation timed out after %d seconds",
- static_cast<int>(duration.InSeconds())),
- request, true, response);
- } else {
- // TODO(craigdh): Determine specific cause.
- ErrorResponse(
- "Chrome automation failed prior to timing out, did chrome crash?",
- request, false, response);
- }
-}
diff --git a/chrome/test/pyautolib/pyautolib.h b/chrome/test/pyautolib/pyautolib.h
deleted file mode 100644
index f4bcb27..0000000
--- a/chrome/test/pyautolib/pyautolib.h
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright (c) 2012 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.
-//
-// This file declares the C++ side of PyAuto, the python interface to
-// Chromium automation. It access Chromium's internals using Automation Proxy.
-
-#ifndef CHROME_TEST_PYAUTOLIB_PYAUTOLIB_H_
-#define CHROME_TEST_PYAUTOLIB_PYAUTOLIB_H_
-
-#include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
-#include "base/test/test_timeouts.h"
-#include "base/time/time.h"
-#include "chrome/test/ui/ui_test.h"
-#include "chrome/test/ui/ui_test_suite.h"
-
-#if defined(OS_MACOSX)
-#include "base/mac/scoped_nsautorelease_pool.h"
-#endif
-
-class AutomationProxy;
-
-// The C++ style guide forbids using default arguments but I'm taking the
-// liberty of allowing it in this file. The sole purpose of this (and the
-// .cc) is to support the python interface, and default args are allowed in
-// python. Strictly adhering to the guide here would mean having to re-define
-// all methods in python just for the sake of providing default args. This
-// seems cumbersome and unwanted.
-
-// Test Suite for Pyauto tests. All one-time initializations go here.
-class PyUITestSuiteBase : public UITestSuite {
- public:
- PyUITestSuiteBase(int argc, char** argv);
- virtual ~PyUITestSuiteBase();
-
- void InitializeWithPath(const base::FilePath& browser_dir);
-
- void SetCrSourceRoot(const base::FilePath& path);
-
- private:
-#if defined(OS_MACOSX)
- base::mac::ScopedNSAutoreleasePool pool_;
-#endif
-};
-
-// The primary class that interfaces with Automation Proxy.
-// This class is accessed from python using swig.
-class PyUITestBase : public UITestBase {
- public:
- // Only public methods are accessible from swig.
-
- // Constructor. Lookup pyauto.py for doc on these args.
- PyUITestBase(bool clear_profile, std::wstring homepage);
- virtual ~PyUITestBase();
-
- // Initialize the setup. Should be called before launching the browser.
- // |browser_dir| is the path to dir containing chromium binaries.
- void Initialize(const base::FilePath& browser_dir);
-
- void UseNamedChannelID(const std::string& named_channel_id) {
- named_channel_id_ = named_channel_id;
- launcher_.reset(CreateProxyLauncher());
- }
-
- virtual ProxyLauncher* CreateProxyLauncher() OVERRIDE;
-
- // SetUp,TearDown is redeclared as public to make it accessible from swig.
- virtual void SetUp() OVERRIDE;
- virtual void TearDown() OVERRIDE;
-
- // AutomationProxy methods
-
- // Meta-methods. Generic pattern of passing args and response as
- // JSON dict to avoid future use of the SWIG interface and
- // automation proxy additions. Returns response as JSON dict.
- // Use -ve window_index for automation calls not targetted at a browser
- // window. Example: Login call for chromeos.
- std::string _SendJSONRequest(int window_index,
- const std::string& request,
- int timeout);
-
- // Sets a cookie value for a url. Returns true on success.
- bool SetCookie(const GURL& cookie_url, const std::string& value,
- int window_index = 0, int tab_index = 0);
- // Gets a cookie value for the given url.
- std::string GetCookie(const GURL& cookie_url, int window_index = 0,
- int tab_index = 0);
-
- protected:
- // Gets the automation proxy and checks that it exists.
- virtual AutomationProxy* automation() const OVERRIDE;
-
- virtual void SetLaunchSwitches() OVERRIDE;
-
- private:
- // Create JSON error responses.
- void ErrorResponse(const std::string& error_string,
- const std::string& request,
- bool is_timeout,
- std::string* response);
- void RequestFailureResponse(
- const std::string& request,
- const base::TimeDelta& duration,
- const base::TimeDelta& timeout,
- std::string* response);
-
- // Enables PostTask to main thread.
- // Should be shared across multiple instances of PyUITestBase so that this
- // class is re-entrant and multiple instances can be created.
- // This is necessary since python's unittest module creates instances of
- // TestCase at load time itself.
- static base::MessageLoop* GetSharedMessageLoop(
- base::MessageLoop::Type msg_loop_type);
- static base::MessageLoop* message_loop_;
-
- // Path to named channel id.
- std::string named_channel_id_;
-};
-
-#endif // CHROME_TEST_PYAUTOLIB_PYAUTOLIB_H_
diff --git a/chrome/test/pyautolib/pyautolib.i b/chrome/test/pyautolib/pyautolib.i
deleted file mode 100644
index e73637d..0000000
--- a/chrome/test/pyautolib/pyautolib.i
+++ /dev/null
@@ -1,248 +0,0 @@
-// 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.
-//
-// Swig Interface for PyAuto.
-// PyAuto makes the Automation Proxy interface available in Python
-//
-// Running swig as:
-// swig -python -c++ chrome/test/pyautolib/pyautolib.i
-// would generate pyautolib.py, pyautolib_wrap.cxx
-
-// When adding a new class or method, make sure you specify the doc string using
-// %feature("docstring", "doc string goes here") NODENAME;
-// and attach it to your node (class or method). This doc string will be
-// copied over in the generated python classes/methods.
-
-%module(docstring="Python interface to Automation Proxy.") pyautolib
-%feature("autodoc", "1");
-
-%include <cpointer.i>
-%include <std_string.i>
-%include <std_wstring.i>
-
-%include "chrome/test/pyautolib/argc_argv.i"
-
-// NOTE: All files included in this file should also be listed under
-// pyautolib_sources in chrome_tests.gypi.
-
-// Headers that can be swigged directly.
-%include "chrome/app/chrome_command_ids.h"
-%include "chrome/app/chrome_dll_resource.h"
-%include "chrome/common/automation_constants.h"
-%include "chrome/common/pref_names.h"
-%include "content/public/common/page_type.h"
-%include "content/public/common/security_style.h"
-// Must come before cert_status_flags.h
-%include "net/base/net_export.h"
-%ignore net::MapNetErrorToCertStatus(int);
-%include "net/cert/cert_status_flags.h"
-
-%{
-#include "chrome/common/automation_constants.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/test/automation/browser_proxy.h"
-#include "chrome/test/automation/tab_proxy.h"
-#include "chrome/test/pyautolib/pyautolib.h"
-#include "content/public/common/security_style.h"
-#include "net/test/spawned_test_server/spawned_test_server.h"
-%}
-
-// Handle type uint32 conversions as int
-%apply int { uint32 };
-
-// scoped_refptr
-template <class T>
-class scoped_refptr {
- public:
- scoped_refptr();
- scoped_refptr(T* p);
- ~scoped_refptr();
-
- T* get() const;
- T* operator->() const;
-};
-
-// GURL
-%feature("docstring", "Represent a URL. Call spec() to get the string.") GURL;
-class GURL {
- public:
- GURL();
- explicit GURL(const std::string& url_string);
- %feature("docstring", "Get the string representation.") spec;
- const std::string& spec() const;
-};
-
-// FilePath
-namespace base {
-%feature("docstring",
- "Represent a file path. Call value() to get the string.") FilePath;
-class FilePath {
- public:
- %feature("docstring", "Get the string representation.") value;
-#ifdef SWIGWIN
- typedef std::wstring StringType;
-#else
- typedef std::string StringType;
-#endif // SWIGWIN
- const StringType& value() const;
- %feature("docstring", "Construct an empty FilePath from a string.")
- FilePath;
- FilePath();
- explicit FilePath(const StringType& path);
-};
-} // namespace base
-
-class PyUITestSuiteBase {
- public:
- %feature("docstring", "Create the suite.") PyUITestSuiteBase;
- PyUITestSuiteBase(int argc, char** argv);
- virtual ~PyUITestSuiteBase();
-
- %feature("docstring", "Initialize from the path to browser dir.")
- InitializeWithPath;
- void InitializeWithPath(const base::FilePath& browser_dir);
- %feature("docstring", "Set chrome source root path, used in some tests")
- SetCrSourceRoot;
- void SetCrSourceRoot(const base::FilePath& path);
-};
-
-class PyUITestBase {
- public:
- PyUITestBase(bool clear_profile, std::wstring homepage);
-
- %feature("docstring", "Initialize the entire setup. Should be called "
- "before launching the browser. For internal use.") Initialize;
- void Initialize(const base::FilePath& browser_dir);
-
- %feature("docstring", "Appends a command-line switch (with associated value "
- "if given) to the list of switches to be passed to the browser "
- "upon launch. Should be called before launching the browser. "
- "For internal use only.")
- AppendBrowserLaunchSwitch;
- void AppendBrowserLaunchSwitch(const char* name);
- void AppendBrowserLaunchSwitch(const char* name, const char* value);
-
- %feature("docstring", "Begins tracing with the given category_patterns "
- "string.")
- BeginTracing;
- bool BeginTracing(const std::string& category_patterns);
-
- %feature("docstring", "Ends tracing and returns the collected events.")
- EndTracing;
- std::string EndTracing();
-
- void UseNamedChannelID(const std::string& named_channel_id);
-
- %feature("docstring",
- "Fires up the browser and opens a window.") SetUp;
- virtual void SetUp();
- %feature("docstring",
- "Closes all windows and destroys the browser.") TearDown;
- virtual void TearDown();
-
- %feature("docstring", "Launches the browser and IPC testing server.")
- LaunchBrowserAndServer;
- void LaunchBrowserAndServer();
- %feature("docstring", "Closes the browser and IPC testing server.")
- CloseBrowserAndServer;
- void CloseBrowserAndServer();
-
- %feature("docstring", "Determine if the profile is set to be cleared on "
- "next startup.") get_clear_profile;
- bool get_clear_profile() const;
- %feature("docstring", "If False, sets the flag so that the profile is "
- "not cleared on next startup. Useful for persisting profile "
- "across restarts. By default the state is True, to clear profile.")
- set_clear_profile;
- void set_clear_profile(bool clear_profile);
-
- %feature("docstring", "Get the path to profile directory.") user_data_dir;
- base::FilePath user_data_dir() const;
-
- // Meta-method
- %feature("docstring", "Send a sync JSON request to Chrome. "
- "Returns a JSON dict as a response. "
- "Given timeout in milliseconds."
- "Internal method.")
- _SendJSONRequest;
- std::string _SendJSONRequest(int window_index,
- const std::string& request,
- int timeout);
-
- %feature("docstring",
- "Returns empty string if there were no unexpected Chrome asserts or "
- "crashes, a string describing the failures otherwise. As a side "
- "effect, it will fail with EXPECT_EQ macros if this code runs "
- "within a gtest harness.") GetErrorsAndCrashes;
- std::string CheckErrorsAndCrashes() const;
-};
-
-namespace net {
-// SpawnedTestServer
-%feature("docstring",
- "SpawnedTestServer. Serves files in data dir over a local http server")
- SpawnedTestServer;
-class SpawnedTestServer {
- public:
- enum Type {
- TYPE_FTP,
- TYPE_HTTP,
- TYPE_HTTPS,
- };
-
- // Initialize a SpawnedTestServer listening on the specified host
- // (IP or hostname).
- SpawnedTestServer(Type type, const std::string& host,
- const base::FilePath& document_root);
- // Initialize a SpawnedTestServer with a specific set of SSLOptions.
- SpawnedTestServer(Type type,
- const SSLOptions& ssl_options,
- const base::FilePath& document_root);
-
- %feature("docstring", "Start SpawnedTestServer over an ephemeral port") Start;
- bool Start();
-
- %feature("docstring", "Stop SpawnedTestServer") Stop;
- bool Stop();
-
- %feature("docstring", "Get FilePath to the document root") document_root;
- const base::FilePath& document_root() const;
-
- std::string GetScheme() const;
-
- %feature("docstring", "Get URL for a file path") GetURL;
- GURL GetURL(const std::string& path) const;
-};
-
-%extend SpawnedTestServer {
- %feature("docstring", "Get port number.") GetPort;
- int GetPort() const {
- int val = 0;
- $self->server_data().GetInteger("port", &val);
- return val;
- }
-};
-
-}
-// SSLOptions
-%feature("docstring",
- "SSLOptions. Sets one of three types of a cert")
- SSLOptions;
-struct SSLOptions {
- enum ServerCertificate {
- CERT_OK,
- CERT_MISMATCHED_NAME,
- CERT_EXPIRED,
- };
-
- // Initialize a new SSLOptions that will use the specified certificate.
- explicit SSLOptions(ServerCertificate cert);
-};
-
-%{
-typedef net::SpawnedTestServer::SSLOptions SSLOptions;
-%}
-
-%pointer_class(int, int_ptr);
-%pointer_class(uint32, uint32_ptr);
diff --git a/chrome/test/pyautolib/remote_host.py b/chrome/test/pyautolib/remote_host.py
deleted file mode 100755
index c51a6e0..0000000
--- a/chrome/test/pyautolib/remote_host.py
+++ /dev/null
@@ -1,101 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import cStringIO
-import os
-import pickle
-import socket
-import sys
-
-import pyauto
-
-class RemoteHost(object):
- """Class used as a host for tests that use the PyAuto RemoteProxy.
-
- This class fires up a listener which waits for a connection from a RemoteProxy
- and receives method call requests. Run python remote_host.py
- remote_host.RemoteHost.RunHost to start up a PyAuto remote instance that you
- can connect to and automate using pyauto.RemoteProxy.
- """
- def __init__(self, host, *args, **kwargs):
- self.StartSocketServer(host)
-
- def StartSocketServer(self, host):
- listening_socket = socket.socket()
- listening_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- listening_socket.bind(host)
- listening_socket.listen(1)
- print 'Listening for incoming connections on port %d.' % host[1]
- self._socket, address = listening_socket.accept()
- print 'Accepted connection from %s:%d.' % address
-
- while self.Connected():
- self._HandleRPC()
-
- def StopSocketServer(self):
- if self._socket:
- try:
- self._socket.shutdown(socket.SHUT_RDWR)
- self._socket.close()
- except socket.error:
- pass
- self._socket = None
-
- def Connected(self):
- return self._socket
-
- def CreateTarget(self, target_class):
- """Creates an instance of the specified class to serve as the RPC target.
-
- RPC calls can be made on the target.
- """
- self.target = target_class()
-
- def _HandleRPC(self):
- """Receives a method call request over the socket and executes the method.
-
- This method captures stdout and stderr for the duration of the method call,
- and sends those, the return value, and any thrown exceptions back to the
- RemoteProxy.
- """
- # Receive request.
- request = self._socket.recv(4096)
- if not request:
- self.StopSocketServer()
- return
- request = pickle.loads(request)
-
- # Redirect output to strings.
- old_stdout = sys.stdout
- old_stderr = sys.stderr
- sys.stdout = stdout = cStringIO.StringIO()
- sys.stderr = stderr = cStringIO.StringIO()
-
- # Make requested method call.
- result = None
- exception = None
- try:
- if getattr(self, request[0], None):
- result = getattr(self, request[0])(*request[1], **request[2])
- else:
- result = getattr(self.target, request[0])(*request[1], **request[2])
- except BaseException, e:
- exception = (e.__class__.__name__, str(e))
-
- # Put output back to the way it was before.
- sys.stdout = old_stdout
- sys.stderr = old_stderr
-
- # Package up and send the result of the method call.
- response = pickle.dumps((result, stdout.getvalue(), stderr.getvalue(),
- exception))
- if self._socket.send(response) != len(response):
- self.StopSocketServer()
-
-
-if __name__ == '__main__':
- pyauto_suite = pyauto.PyUITestSuite(sys.argv)
- RemoteHost(('', 7410))
- del pyauto_suite
diff --git a/chrome/test/pyautolib/remote_inspector_client.py b/chrome/test/pyautolib/remote_inspector_client.py
deleted file mode 100755
index 95b9cf6..0000000
--- a/chrome/test/pyautolib/remote_inspector_client.py
+++ /dev/null
@@ -1,1211 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-"""Chrome remote inspector utility for pyauto tests.
-
-This script provides a python interface that acts as a front-end for Chrome's
-remote inspector module, communicating via sockets to interact with Chrome in
-the same way that the Developer Tools does. This -- in theory -- should allow
-a pyauto test to do anything that Chrome's Developer Tools does, as long as the
-appropriate communication with the remote inspector is implemented in this
-script.
-
-This script assumes that Chrome is already running on the local machine with
-flag '--remote-debugging-port=9222' to enable remote debugging on port 9222.
-
-To use this module, first create an instance of class RemoteInspectorClient;
-doing this sets up a connection to Chrome's remote inspector. Then call the
-appropriate functions on that object to perform the desired actions with the
-remote inspector. When done, call Stop() on the RemoteInspectorClient object
-to stop communication with the remote inspector.
-
-For example, to take v8 heap snapshots from a pyauto test:
-
-import remote_inspector_client
-my_client = remote_inspector_client.RemoteInspectorClient()
-snapshot_info = my_client.HeapSnapshot(include_summary=True)
-// Do some stuff...
-new_snapshot_info = my_client.HeapSnapshot(include_summary=True)
-my_client.Stop()
-
-It is expected that a test will only use one instance of RemoteInspectorClient
-at a time. If a second instance is instantiated, a RuntimeError will be raised.
-RemoteInspectorClient could be made into a singleton in the future if the need
-for it arises.
-"""
-
-import asyncore
-import datetime
-import logging
-import optparse
-import pprint
-import re
-import simplejson
-import socket
-import sys
-import threading
-import time
-import urllib2
-import urlparse
-
-
-class _DevToolsSocketRequest(object):
- """A representation of a single DevToolsSocket request.
-
- A DevToolsSocket request is used for communication with a remote Chrome
- instance when interacting with the renderer process of a given webpage.
- Requests and results are passed as specially-formatted JSON messages,
- according to a communication protocol defined in WebKit. The string
- representation of this request will be a JSON message that is properly
- formatted according to the communication protocol.
-
- Public Attributes:
- method: The string method name associated with this request.
- id: A unique integer id associated with this request.
- params: A dictionary of input parameters associated with this request.
- results: A dictionary of relevant results obtained from the remote Chrome
- instance that are associated with this request.
- is_fulfilled: A boolean indicating whether or not this request has been sent
- and all relevant results for it have been obtained (i.e., this value is
- True only if all results for this request are known).
- is_fulfilled_condition: A threading.Condition for waiting for the request to
- be fulfilled.
- """
-
- def __init__(self, method, params, message_id):
- """Initialize.
-
- Args:
- method: The string method name for this request.
- message_id: An integer id for this request, which is assumed to be unique
- from among all requests.
- """
- self.method = method
- self.id = message_id
- self.params = params
- self.results = {}
- self.is_fulfilled = False
- self.is_fulfilled_condition = threading.Condition()
-
- def __repr__(self):
- json_dict = {}
- json_dict['method'] = self.method
- json_dict['id'] = self.id
- if self.params:
- json_dict['params'] = self.params
- return simplejson.dumps(json_dict, separators=(',', ':'))
-
-
-class _DevToolsSocketClient(asyncore.dispatcher):
- """Client that communicates with a remote Chrome instance via sockets.
-
- This class works in conjunction with the _RemoteInspectorThread class to
- communicate with a remote Chrome instance following the remote debugging
- communication protocol in WebKit. This class performs the lower-level work
- of socket communication.
-
- Public Attributes:
- handshake_done: A boolean indicating whether or not the client has completed
- the required protocol handshake with the remote Chrome instance.
- inspector_thread: An instance of the _RemoteInspectorThread class that is
- working together with this class to communicate with a remote Chrome
- instance.
- """
-
- def __init__(self, verbose, show_socket_messages, hostname, port, path):
- """Initialize.
-
- Args:
- verbose: A boolean indicating whether or not to use verbose logging.
- show_socket_messages: A boolean indicating whether or not to show the
- socket messages sent/received when communicating with the remote
- Chrome instance.
- hostname: The string hostname of the DevToolsSocket to which to connect.
- port: The integer port number of the DevToolsSocket to which to connect.
- path: The string path of the DevToolsSocket to which to connect.
- """
- asyncore.dispatcher.__init__(self)
-
- self._logger = logging.getLogger('_DevToolsSocketClient')
- self._logger.setLevel([logging.WARNING, logging.DEBUG][verbose])
-
- self._show_socket_messages = show_socket_messages
-
- self._read_buffer = ''
- self._write_buffer = ''
-
- self._socket_buffer_lock = threading.Lock()
-
- self.handshake_done = False
- self.inspector_thread = None
-
- # Connect to the remote Chrome instance and initiate the protocol handshake.
- self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
- self.connect((hostname, port))
-
- fields = [
- 'Upgrade: WebSocket',
- 'Connection: Upgrade',
- 'Host: %s:%d' % (hostname, port),
- 'Origin: http://%s:%d' % (hostname, port),
- 'Sec-WebSocket-Key1: 4k0L66E ZU 8 5 <18 <TK 7 7',
- 'Sec-WebSocket-Key2: s2 20 `# 4| 3 9 U_ 1299',
- ]
- handshake_msg = ('GET %s HTTP/1.1\r\n%s\r\n\r\n\x47\x30\x22\x2D\x5A\x3F'
- '\x47\x58' % (path, '\r\n'.join(fields)))
- self._Write(handshake_msg.encode('utf-8'))
-
- def SendMessage(self, msg):
- """Causes a request message to be sent to the remote Chrome instance.
-
- Args:
- msg: A string message to be sent; assumed to be a JSON message in proper
- format according to the remote debugging protocol in WebKit.
- """
- # According to the communication protocol, each request message sent over
- # the wire must begin with '\x00' and end with '\xff'.
- self._Write('\x00' + msg.encode('utf-8') + '\xff')
-
- def _Write(self, msg):
- """Causes a raw message to be sent to the remote Chrome instance.
-
- Args:
- msg: A raw string message to be sent.
- """
- self._write_buffer += msg
- self.handle_write()
-
- def handle_write(self):
- """Called if a writable socket can be written; overridden from asyncore."""
- self._socket_buffer_lock.acquire()
- if self._write_buffer:
- sent = self.send(self._write_buffer)
- if self._show_socket_messages:
- msg_type = ['Handshake', 'Message'][self._write_buffer[0] == '\x00' and
- self._write_buffer[-1] == '\xff']
- msg = ('========================\n'
- 'Sent %s:\n'
- '========================\n'
- '%s\n'
- '========================') % (msg_type,
- self._write_buffer[:sent-1])
- print msg
- self._write_buffer = self._write_buffer[sent:]
- self._socket_buffer_lock.release()
-
- def handle_read(self):
- """Called when a socket can be read; overridden from asyncore."""
- self._socket_buffer_lock.acquire()
- if self.handshake_done:
- # Process a message reply from the remote Chrome instance.
- self._read_buffer += self.recv(4096)
- pos = self._read_buffer.find('\xff')
- while pos >= 0:
- pos += len('\xff')
- data = self._read_buffer[:pos-len('\xff')]
- pos2 = data.find('\x00')
- if pos2 >= 0:
- data = data[pos2 + 1:]
- self._read_buffer = self._read_buffer[pos:]
- if self._show_socket_messages:
- msg = ('========================\n'
- 'Received Message:\n'
- '========================\n'
- '%s\n'
- '========================') % data
- print msg
- if self.inspector_thread:
- self.inspector_thread.NotifyReply(data)
- pos = self._read_buffer.find('\xff')
- else:
- # Process a handshake reply from the remote Chrome instance.
- self._read_buffer += self.recv(4096)
- pos = self._read_buffer.find('\r\n\r\n')
- if pos >= 0:
- pos += len('\r\n\r\n')
- data = self._read_buffer[:pos]
- self._read_buffer = self._read_buffer[pos:]
- self.handshake_done = True
- if self._show_socket_messages:
- msg = ('=========================\n'
- 'Received Handshake Reply:\n'
- '=========================\n'
- '%s\n'
- '=========================') % data
- print msg
- self._socket_buffer_lock.release()
-
- def handle_close(self):
- """Called when the socket is closed; overridden from asyncore."""
- if self._show_socket_messages:
- msg = ('=========================\n'
- 'Socket closed.\n'
- '=========================')
- print msg
- self.close()
-
- def writable(self):
- """Determines if writes can occur for this socket; overridden from asyncore.
-
- Returns:
- True, if there is something to write to the socket, or
- False, otherwise.
- """
- return len(self._write_buffer) > 0
-
- def handle_expt(self):
- """Called when out-of-band data exists; overridden from asyncore."""
- self.handle_error()
-
- def handle_error(self):
- """Called when an exception is raised; overridden from asyncore."""
- if self._show_socket_messages:
- msg = ('=========================\n'
- 'Socket error.\n'
- '=========================')
- print msg
- self.close()
- self.inspector_thread.ClientSocketExceptionOccurred()
- asyncore.dispatcher.handle_error(self)
-
-
-class _RemoteInspectorThread(threading.Thread):
- """Manages communication using Chrome's remote inspector protocol.
-
- This class works in conjunction with the _DevToolsSocketClient class to
- communicate with a remote Chrome instance following the remote inspector
- communication protocol in WebKit. This class performs the higher-level work
- of managing request and reply messages, whereas _DevToolsSocketClient handles
- the lower-level work of socket communication.
- """
-
- def __init__(self, url, tab_index, tab_filter, verbose, show_socket_messages,
- agent_name):
- """Initialize.
-
- Args:
- url: The base URL to connent to.
- tab_index: The integer index of the tab in the remote Chrome instance to
- use for snapshotting.
- tab_filter: When specified, is run over tabs of the remote Chrome
- instances to choose which one to connect to.
- verbose: A boolean indicating whether or not to use verbose logging.
- show_socket_messages: A boolean indicating whether or not to show the
- socket messages sent/received when communicating with the remote
- Chrome instance.
- """
- threading.Thread.__init__(self)
- self._logger = logging.getLogger('_RemoteInspectorThread')
- self._logger.setLevel([logging.WARNING, logging.DEBUG][verbose])
-
- self._killed = False
- self._requests = []
- self._action_queue = []
- self._action_queue_condition = threading.Condition()
- self._action_specific_callback = None # Callback only for current action.
- self._action_specific_callback_lock = threading.Lock()
- self._general_callbacks = [] # General callbacks that can be long-lived.
- self._general_callbacks_lock = threading.Lock()
- self._condition_to_wait = None
- self._agent_name = agent_name
-
- # Create a DevToolsSocket client and wait for it to complete the remote
- # debugging protocol handshake with the remote Chrome instance.
- result = self._IdentifyDevToolsSocketConnectionInfo(
- url, tab_index, tab_filter)
- self._client = _DevToolsSocketClient(
- verbose, show_socket_messages, result['host'], result['port'],
- result['path'])
- self._client.inspector_thread = self
- while asyncore.socket_map:
- if self._client.handshake_done or self._killed:
- break
- asyncore.loop(timeout=1, count=1, use_poll=True)
-
- def ClientSocketExceptionOccurred(self):
- """Notifies that the _DevToolsSocketClient encountered an exception."""
- self.Kill()
-
- def NotifyReply(self, msg):
- """Notifies of a reply message received from the remote Chrome instance.
-
- Args:
- msg: A string reply message received from the remote Chrome instance;
- assumed to be a JSON message formatted according to the remote
- debugging communication protocol in WebKit.
- """
- reply_dict = simplejson.loads(msg)
-
- # Notify callbacks of this message received from the remote inspector.
- self._action_specific_callback_lock.acquire()
- if self._action_specific_callback:
- self._action_specific_callback(reply_dict)
- self._action_specific_callback_lock.release()
-
- self._general_callbacks_lock.acquire()
- if self._general_callbacks:
- for callback in self._general_callbacks:
- callback(reply_dict)
- self._general_callbacks_lock.release()
-
- if 'result' in reply_dict:
- # This is the result message associated with a previously-sent request.
- request = self.GetRequestWithId(reply_dict['id'])
- if request:
- request.is_fulfilled_condition.acquire()
- request.is_fulfilled_condition.notify()
- request.is_fulfilled_condition.release()
-
- def run(self):
- """Start this thread; overridden from threading.Thread."""
- while not self._killed:
- self._action_queue_condition.acquire()
- if self._action_queue:
- # There's a request to the remote inspector that needs to be processed.
- messages, callback = self._action_queue.pop(0)
- self._action_specific_callback_lock.acquire()
- self._action_specific_callback = callback
- self._action_specific_callback_lock.release()
-
- # Prepare the request list.
- for message_id, message in enumerate(messages):
- self._requests.append(
- _DevToolsSocketRequest(message[0], message[1], message_id))
-
- # Send out each request. Wait until each request is complete before
- # sending the next request.
- for request in self._requests:
- self._FillInParams(request)
- self._client.SendMessage(str(request))
-
- request.is_fulfilled_condition.acquire()
- self._condition_to_wait = request.is_fulfilled_condition
- request.is_fulfilled_condition.wait()
- request.is_fulfilled_condition.release()
-
- if self._killed:
- self._client.close()
- return
-
- # Clean up so things are ready for the next request.
- self._requests = []
-
- self._action_specific_callback_lock.acquire()
- self._action_specific_callback = None
- self._action_specific_callback_lock.release()
-
- # Wait until there is something to process.
- self._condition_to_wait = self._action_queue_condition
- self._action_queue_condition.wait()
- self._action_queue_condition.release()
- self._client.close()
-
- def Kill(self):
- """Notify this thread that it should stop executing."""
- self._killed = True
- # The thread might be waiting on a condition.
- if self._condition_to_wait:
- self._condition_to_wait.acquire()
- self._condition_to_wait.notify()
- self._condition_to_wait.release()
-
- def PerformAction(self, request_messages, reply_message_callback):
- """Notify this thread of an action to perform using the remote inspector.
-
- Args:
- request_messages: A list of strings representing the requests to make
- using the remote inspector.
- reply_message_callback: A callable to be invoked any time a message is
- received from the remote inspector while the current action is
- being performed. The callable should accept a single argument,
- which is a dictionary representing a message received.
- """
- self._action_queue_condition.acquire()
- self._action_queue.append((request_messages, reply_message_callback))
- self._action_queue_condition.notify()
- self._action_queue_condition.release()
-
- def AddMessageCallback(self, callback):
- """Add a callback to invoke for messages received from the remote inspector.
-
- Args:
- callback: A callable to be invoked any time a message is received from the
- remote inspector. The callable should accept a single argument, which
- is a dictionary representing a message received.
- """
- self._general_callbacks_lock.acquire()
- self._general_callbacks.append(callback)
- self._general_callbacks_lock.release()
-
- def RemoveMessageCallback(self, callback):
- """Remove a callback from the set of those to invoke for messages received.
-
- Args:
- callback: A callable to remove from consideration.
- """
- self._general_callbacks_lock.acquire()
- self._general_callbacks.remove(callback)
- self._general_callbacks_lock.release()
-
- def GetRequestWithId(self, request_id):
- """Identifies the request with the specified id.
-
- Args:
- request_id: An integer request id; should be unique for each request.
-
- Returns:
- A request object associated with the given id if found, or
- None otherwise.
- """
- found_request = [x for x in self._requests if x.id == request_id]
- if found_request:
- return found_request[0]
- return None
-
- def GetFirstUnfulfilledRequest(self, method):
- """Identifies the first unfulfilled request with the given method name.
-
- An unfulfilled request is one for which all relevant reply messages have
- not yet been received from the remote inspector.
-
- Args:
- method: The string method name of the request for which to search.
-
- Returns:
- The first request object in the request list that is not yet fulfilled
- and is also associated with the given method name, or
- None if no such request object can be found.
- """
- for request in self._requests:
- if not request.is_fulfilled and request.method == method:
- return request
- return None
-
- def _GetLatestRequestOfType(self, ref_req, method):
- """Identifies the latest specified request before a reference request.
-
- This function finds the latest request with the specified method that
- occurs before the given reference request.
-
- Args:
- ref_req: A reference request from which to start looking.
- method: The string method name of the request for which to search.
-
- Returns:
- The latest _DevToolsSocketRequest object with the specified method,
- if found, or None otherwise.
- """
- start_looking = False
- for request in self._requests[::-1]:
- if request.id == ref_req.id:
- start_looking = True
- elif start_looking:
- if request.method == method:
- return request
- return None
-
- def _FillInParams(self, request):
- """Fills in parameters for requests as necessary before the request is sent.
-
- Args:
- request: The _DevToolsSocketRequest object associated with a request
- message that is about to be sent.
- """
- if request.method == self._agent_name +'.takeHeapSnapshot':
- # We always want detailed v8 heap snapshot information.
- request.params = {'detailed': True}
- elif request.method == self._agent_name + '.getHeapSnapshot':
- # To actually request the snapshot data from a previously-taken snapshot,
- # we need to specify the unique uid of the snapshot we want.
- # The relevant uid should be contained in the last
- # 'Profiler.takeHeapSnapshot' request object.
- last_req = self._GetLatestRequestOfType(request,
- self._agent_name + '.takeHeapSnapshot')
- if last_req and 'uid' in last_req.results:
- request.params = {'uid': last_req.results['uid']}
- elif request.method == self._agent_name + '.getProfile':
- # TODO(eustas): Remove this case after M27 is released.
- last_req = self._GetLatestRequestOfType(request,
- self._agent_name + '.takeHeapSnapshot')
- if last_req and 'uid' in last_req.results:
- request.params = {'type': 'HEAP', 'uid': last_req.results['uid']}
-
- @staticmethod
- def _IdentifyDevToolsSocketConnectionInfo(url, tab_index, tab_filter):
- """Identifies DevToolsSocket connection info from a remote Chrome instance.
-
- Args:
- url: The base URL to connent to.
- tab_index: The integer index of the tab in the remote Chrome instance to
- which to connect.
- tab_filter: When specified, is run over tabs of the remote Chrome instance
- to choose which one to connect to.
-
- Returns:
- A dictionary containing the DevToolsSocket connection info:
- {
- 'host': string,
- 'port': integer,
- 'path': string,
- }
-
- Raises:
- RuntimeError: When DevToolsSocket connection info cannot be identified.
- """
- try:
- f = urllib2.urlopen(url + '/json')
- result = f.read()
- logging.debug(result)
- result = simplejson.loads(result)
- except urllib2.URLError, e:
- raise RuntimeError(
- 'Error accessing Chrome instance debugging port: ' + str(e))
-
- if tab_filter:
- connect_to = filter(tab_filter, result)[0]
- else:
- if tab_index >= len(result):
- raise RuntimeError(
- 'Specified tab index %d doesn\'t exist (%d tabs found)' %
- (tab_index, len(result)))
- connect_to = result[tab_index]
-
- logging.debug(simplejson.dumps(connect_to))
-
- if 'webSocketDebuggerUrl' not in connect_to:
- raise RuntimeError('No socket URL exists for the specified tab.')
-
- socket_url = connect_to['webSocketDebuggerUrl']
- parsed = urlparse.urlparse(socket_url)
- # On ChromeOS, the "ws://" scheme may not be recognized, leading to an
- # incorrect netloc (and empty hostname and port attributes) in |parsed|.
- # Change the scheme to "http://" to fix this.
- if not parsed.hostname or not parsed.port:
- socket_url = 'http' + socket_url[socket_url.find(':'):]
- parsed = urlparse.urlparse(socket_url)
- # Warning: |parsed.scheme| is incorrect after this point.
- return ({'host': parsed.hostname,
- 'port': parsed.port,
- 'path': parsed.path})
-
-
-class _RemoteInspectorDriverThread(threading.Thread):
- """Drives the communication service with the remote inspector."""
-
- def __init__(self):
- """Initialize."""
- threading.Thread.__init__(self)
-
- def run(self):
- """Drives the communication service with the remote inspector."""
- try:
- while asyncore.socket_map:
- asyncore.loop(timeout=1, count=1, use_poll=True)
- except KeyboardInterrupt:
- pass
-
-
-class _V8HeapSnapshotParser(object):
- """Parses v8 heap snapshot data."""
- _CHILD_TYPES = ['context', 'element', 'property', 'internal', 'hidden',
- 'shortcut', 'weak']
- _NODE_TYPES = ['hidden', 'array', 'string', 'object', 'code', 'closure',
- 'regexp', 'number', 'native', 'synthetic']
-
- @staticmethod
- def ParseSnapshotData(raw_data):
- """Parses raw v8 heap snapshot data and returns the summarized results.
-
- The raw heap snapshot data is represented as a JSON object with the
- following keys: 'snapshot', 'nodes', and 'strings'.
-
- The 'snapshot' value provides the 'title' and 'uid' attributes for the
- snapshot. For example:
- { u'title': u'org.webkit.profiles.user-initiated.1', u'uid': 1}
-
- The 'nodes' value is a list of node information from the v8 heap, with a
- special first element that describes the node serialization layout (see
- HeapSnapshotJSONSerializer::SerializeNodes). All other list elements
- contain information about nodes in the v8 heap, according to the
- serialization layout.
-
- The 'strings' value is a list of strings, indexed by values in the 'nodes'
- list to associate nodes with strings.
-
- Args:
- raw_data: A string representing the raw v8 heap snapshot data.
-
- Returns:
- A dictionary containing the summarized v8 heap snapshot data:
- {
- 'total_v8_node_count': integer, # Total number of nodes in the v8 heap.
- 'total_shallow_size': integer, # Total heap size, in bytes.
- }
- """
- total_node_count = 0
- total_shallow_size = 0
- constructors = {}
-
- # TODO(dennisjeffrey): The following line might be slow, especially on
- # ChromeOS. Investigate faster alternatives.
- heap = simplejson.loads(raw_data)
-
- index = 1 # Bypass the special first node list item.
- node_list = heap['nodes']
- while index < len(node_list):
- node_type = node_list[index]
- node_name = node_list[index + 1]
- node_id = node_list[index + 2]
- node_self_size = node_list[index + 3]
- node_retained_size = node_list[index + 4]
- node_dominator = node_list[index + 5]
- node_children_count = node_list[index + 6]
- index += 7
-
- node_children = []
- for i in xrange(node_children_count):
- child_type = node_list[index]
- child_type_string = _V8HeapSnapshotParser._CHILD_TYPES[int(child_type)]
- child_name_index = node_list[index + 1]
- child_to_node = node_list[index + 2]
- index += 3
-
- child_info = {
- 'type': child_type_string,
- 'name_or_index': child_name_index,
- 'to_node': child_to_node,
- }
- node_children.append(child_info)
-
- # Get the constructor string for this node so nodes can be grouped by
- # constructor.
- # See HeapSnapshot.js: WebInspector.HeapSnapshotNode.prototype.
- type_string = _V8HeapSnapshotParser._NODE_TYPES[int(node_type)]
- constructor_name = None
- if type_string == 'hidden':
- constructor_name = '(system)'
- elif type_string == 'object':
- constructor_name = heap['strings'][int(node_name)]
- elif type_string == 'native':
- pos = heap['strings'][int(node_name)].find('/')
- if pos >= 0:
- constructor_name = heap['strings'][int(node_name)][:pos].rstrip()
- else:
- constructor_name = heap['strings'][int(node_name)]
- elif type_string == 'code':
- constructor_name = '(compiled code)'
- else:
- constructor_name = '(' + type_string + ')'
-
- node_obj = {
- 'type': type_string,
- 'name': heap['strings'][int(node_name)],
- 'id': node_id,
- 'self_size': node_self_size,
- 'retained_size': node_retained_size,
- 'dominator': node_dominator,
- 'children_count': node_children_count,
- 'children': node_children,
- }
-
- if constructor_name not in constructors:
- constructors[constructor_name] = []
- constructors[constructor_name].append(node_obj)
-
- total_node_count += 1
- total_shallow_size += node_self_size
-
- # TODO(dennisjeffrey): Have this function also return more detailed v8
- # heap snapshot data when a need for it arises (e.g., using |constructors|).
- result = {}
- result['total_v8_node_count'] = total_node_count
- result['total_shallow_size'] = total_shallow_size
- return result
-
-
-# TODO(dennisjeffrey): The "verbose" option used in this file should re-use
-# pyauto's verbose flag.
-class RemoteInspectorClient(object):
- """Main class for interacting with Chrome's remote inspector.
-
- Upon initialization, a socket connection to Chrome's remote inspector will
- be established. Users of this class should call Stop() to close the
- connection when it's no longer needed.
-
- Public Methods:
- Stop: Close the connection to the remote inspector. Should be called when
- a user is done using this module.
- HeapSnapshot: Takes a v8 heap snapshot and returns the summarized data.
- GetMemoryObjectCounts: Retrieves memory object count information.
- CollectGarbage: Forces a garbage collection.
- StartTimelineEventMonitoring: Starts monitoring for timeline events.
- StopTimelineEventMonitoring: Stops monitoring for timeline events.
- """
-
- # TODO(dennisjeffrey): Allow a user to specify a window index too (not just a
- # tab index), when running through PyAuto.
- def __init__(self, tab_index=0, tab_filter=None,
- verbose=False, show_socket_messages=False,
- url='http://localhost:9222'):
- """Initialize.
-
- Args:
- tab_index: The integer index of the tab in the remote Chrome instance to
- which to connect. Defaults to 0 (the first tab).
- tab_filter: When specified, is run over tabs of the remote Chrome
- instance to choose which one to connect to.
- verbose: A boolean indicating whether or not to use verbose logging.
- show_socket_messages: A boolean indicating whether or not to show the
- socket messages sent/received when communicating with the remote
- Chrome instance.
- """
- self._tab_index = tab_index
- self._tab_filter = tab_filter
- self._verbose = verbose
- self._show_socket_messages = show_socket_messages
-
- self._timeline_started = False
-
- logging.basicConfig()
- self._logger = logging.getLogger('RemoteInspectorClient')
- self._logger.setLevel([logging.WARNING, logging.DEBUG][verbose])
-
- # Creating _RemoteInspectorThread might raise an exception. This prevents an
- # AttributeError in the destructor.
- self._remote_inspector_thread = None
- self._remote_inspector_driver_thread = None
-
- self._version = self._GetVersion(url)
-
- # TODO(loislo): Remove this hack after M28 is released.
- self._agent_name = 'Profiler'
- if self._IsBrowserDayNumberGreaterThan(1470):
- self._agent_name = 'HeapProfiler'
-
- # Start up a thread for long-term communication with the remote inspector.
- self._remote_inspector_thread = _RemoteInspectorThread(
- url, tab_index, tab_filter, verbose, show_socket_messages,
- self._agent_name)
- self._remote_inspector_thread.start()
- # At this point, a connection has already been made to the remote inspector.
-
- # This thread calls asyncore.loop, which activates the channel service.
- self._remote_inspector_driver_thread = _RemoteInspectorDriverThread()
- self._remote_inspector_driver_thread.start()
-
- def __del__(self):
- """Called on destruction of this object."""
- self.Stop()
-
- def Stop(self):
- """Stop/close communication with the remote inspector."""
- if self._remote_inspector_thread:
- self._remote_inspector_thread.Kill()
- self._remote_inspector_thread.join()
- self._remote_inspector_thread = None
- if self._remote_inspector_driver_thread:
- self._remote_inspector_driver_thread.join()
- self._remote_inspector_driver_thread = None
-
- def HeapSnapshot(self, include_summary=False):
- """Takes a v8 heap snapshot.
-
- Returns:
- A dictionary containing information for a single v8 heap
- snapshot that was taken.
- {
- 'url': string, # URL of the webpage that was snapshotted.
- 'raw_data': string, # The raw data as JSON string.
- 'total_v8_node_count': integer, # Total number of nodes in the v8 heap.
- # Only if |include_summary| is True.
- 'total_heap_size': integer, # Total v8 heap size (number of bytes).
- # Only if |include_summary| is True.
- }
- """
- HEAP_SNAPSHOT_MESSAGES = [
- ('Page.getResourceTree', {}),
- ('Debugger.enable', {}),
- (self._agent_name + '.clearProfiles', {}),
- (self._agent_name + '.takeHeapSnapshot', {}),
- (self._agent_name + '.getHeapSnapshot', {}),
- ]
-
- self._current_heap_snapshot = []
- self._url = ''
- self._collected_heap_snapshot_data = {}
-
- done_condition = threading.Condition()
-
- def HandleReply(reply_dict):
- """Processes a reply message received from the remote Chrome instance.
-
- Args:
- reply_dict: A dictionary object representing the reply message received
- from the remote inspector.
- """
- if 'result' in reply_dict:
- # This is the result message associated with a previously-sent request.
- request = self._remote_inspector_thread.GetRequestWithId(
- reply_dict['id'])
- if 'frameTree' in reply_dict['result']:
- self._url = reply_dict['result']['frameTree']['frame']['url']
- elif request.method == self._agent_name + '.getHeapSnapshot':
- # A heap snapshot has been completed. Analyze and output the data.
- self._logger.debug('Heap snapshot taken: %s', self._url)
- # TODO(dennisjeffrey): Parse the heap snapshot on-the-fly as the data
- # is coming in over the wire, so we can avoid storing the entire
- # snapshot string in memory.
- raw_snapshot_data = ''.join(self._current_heap_snapshot)
- self._collected_heap_snapshot_data = {
- 'url': self._url,
- 'raw_data': raw_snapshot_data}
- if include_summary:
- self._logger.debug('Now analyzing heap snapshot...')
- parser = _V8HeapSnapshotParser()
- time_start = time.time()
- self._logger.debug('Raw snapshot data size: %.2f MB',
- len(raw_snapshot_data) / (1024.0 * 1024.0))
- result = parser.ParseSnapshotData(raw_snapshot_data)
- self._logger.debug('Time to parse data: %.2f sec',
- time.time() - time_start)
- count = result['total_v8_node_count']
- self._collected_heap_snapshot_data['total_v8_node_count'] = count
- total_size = result['total_shallow_size']
- self._collected_heap_snapshot_data['total_heap_size'] = total_size
-
- done_condition.acquire()
- done_condition.notify()
- done_condition.release()
- elif 'method' in reply_dict:
- # This is an auxiliary message sent from the remote Chrome instance.
- if reply_dict['method'] == self._agent_name + '.addProfileHeader':
- snapshot_req = (
- self._remote_inspector_thread.GetFirstUnfulfilledRequest(
- self._agent_name + '.takeHeapSnapshot'))
- if snapshot_req:
- snapshot_req.results['uid'] = reply_dict['params']['header']['uid']
- elif reply_dict['method'] == self._agent_name + '.addHeapSnapshotChunk':
- self._current_heap_snapshot.append(reply_dict['params']['chunk'])
-
- # Tell the remote inspector to take a v8 heap snapshot, then wait until
- # the snapshot information is available to return.
- self._remote_inspector_thread.PerformAction(HEAP_SNAPSHOT_MESSAGES,
- HandleReply)
-
- done_condition.acquire()
- done_condition.wait()
- done_condition.release()
-
- return self._collected_heap_snapshot_data
-
- def EvaluateJavaScript(self, expression):
- """Evaluates a JavaScript expression and returns the result.
-
- Sends a message containing the expression to the remote Chrome instance we
- are connected to, and evaluates it in the context of the tab we are
- connected to. Blocks until the result is available and returns it.
-
- Returns:
- A dictionary representing the result.
- """
- EVALUATE_MESSAGES = [
- ('Runtime.evaluate', { 'expression': expression,
- 'objectGroup': 'group',
- 'returnByValue': True }),
- ('Runtime.releaseObjectGroup', { 'objectGroup': 'group' })
- ]
-
- self._result = None
- done_condition = threading.Condition()
-
- def HandleReply(reply_dict):
- """Processes a reply message received from the remote Chrome instance.
-
- Args:
- reply_dict: A dictionary object representing the reply message received
- from the remote Chrome instance.
- """
- if 'result' in reply_dict and 'result' in reply_dict['result']:
- self._result = reply_dict['result']['result']['value']
-
- done_condition.acquire()
- done_condition.notify()
- done_condition.release()
-
- # Tell the remote inspector to evaluate the given expression, then wait
- # until that information is available to return.
- self._remote_inspector_thread.PerformAction(EVALUATE_MESSAGES,
- HandleReply)
-
- done_condition.acquire()
- done_condition.wait()
- done_condition.release()
-
- return self._result
-
- def GetMemoryObjectCounts(self):
- """Retrieves memory object count information.
-
- Returns:
- A dictionary containing the memory object count information:
- {
- 'DOMNodeCount': integer, # Total number of DOM nodes.
- 'EventListenerCount': integer, # Total number of event listeners.
- }
- """
- MEMORY_COUNT_MESSAGES = [
- ('Memory.getDOMCounters', {})
- ]
-
- self._event_listener_count = None
- self._dom_node_count = None
-
- done_condition = threading.Condition()
- def HandleReply(reply_dict):
- """Processes a reply message received from the remote Chrome instance.
-
- Args:
- reply_dict: A dictionary object representing the reply message received
- from the remote Chrome instance.
- """
- if 'result' in reply_dict:
- self._event_listener_count = reply_dict['result']['jsEventListeners']
- self._dom_node_count = reply_dict['result']['nodes']
-
- done_condition.acquire()
- done_condition.notify()
- done_condition.release()
-
- # Tell the remote inspector to collect memory count info, then wait until
- # that information is available to return.
- self._remote_inspector_thread.PerformAction(MEMORY_COUNT_MESSAGES,
- HandleReply)
-
- done_condition.acquire()
- done_condition.wait()
- done_condition.release()
-
- return {
- 'DOMNodeCount': self._dom_node_count,
- 'EventListenerCount': self._event_listener_count,
- }
-
- def CollectGarbage(self):
- """Forces a garbage collection."""
- COLLECT_GARBAGE_MESSAGES = [
- ('Profiler.collectGarbage', {})
- ]
-
- # Tell the remote inspector to do a garbage collect. We can return
- # immediately, since there is no result for which to wait.
- self._remote_inspector_thread.PerformAction(COLLECT_GARBAGE_MESSAGES, None)
-
- def StartTimelineEventMonitoring(self, event_callback):
- """Starts timeline event monitoring.
-
- Args:
- event_callback: A callable to invoke whenever a timeline event is observed
- from the remote inspector. The callable should take a single input,
- which is a dictionary containing the detailed information of a
- timeline event.
- """
- if self._timeline_started:
- self._logger.warning('Timeline monitoring already started.')
- return
- TIMELINE_MESSAGES = [
- ('Timeline.start', {})
- ]
-
- self._event_callback = event_callback
-
- done_condition = threading.Condition()
- def HandleReply(reply_dict):
- """Processes a reply message received from the remote Chrome instance.
-
- Args:
- reply_dict: A dictionary object representing the reply message received
- from the remote Chrome instance.
- """
- if 'result' in reply_dict:
- done_condition.acquire()
- done_condition.notify()
- done_condition.release()
- if reply_dict.get('method') == 'Timeline.eventRecorded':
- self._event_callback(reply_dict['params']['record'])
-
- # Tell the remote inspector to start the timeline.
- self._timeline_callback = HandleReply
- self._remote_inspector_thread.AddMessageCallback(self._timeline_callback)
- self._remote_inspector_thread.PerformAction(TIMELINE_MESSAGES, None)
-
- done_condition.acquire()
- done_condition.wait()
- done_condition.release()
-
- self._timeline_started = True
-
- def StopTimelineEventMonitoring(self):
- """Stops timeline event monitoring."""
- if not self._timeline_started:
- self._logger.warning('Timeline monitoring already stopped.')
- return
- TIMELINE_MESSAGES = [
- ('Timeline.stop', {})
- ]
-
- done_condition = threading.Condition()
- def HandleReply(reply_dict):
- """Processes a reply message received from the remote Chrome instance.
-
- Args:
- reply_dict: A dictionary object representing the reply message received
- from the remote Chrome instance.
- """
- if 'result' in reply_dict:
- done_condition.acquire()
- done_condition.notify()
- done_condition.release()
-
- # Tell the remote inspector to stop the timeline.
- self._remote_inspector_thread.RemoveMessageCallback(self._timeline_callback)
- self._remote_inspector_thread.PerformAction(TIMELINE_MESSAGES, HandleReply)
-
- done_condition.acquire()
- done_condition.wait()
- done_condition.release()
-
- self._timeline_started = False
-
- def _ConvertByteCountToHumanReadableString(self, num_bytes):
- """Converts an integer number of bytes into a human-readable string.
-
- Args:
- num_bytes: An integer number of bytes.
-
- Returns:
- A human-readable string representation of the given number of bytes.
- """
- if num_bytes < 1024:
- return '%d B' % num_bytes
- elif num_bytes < 1048576:
- return '%.2f KB' % (num_bytes / 1024.0)
- else:
- return '%.2f MB' % (num_bytes / 1048576.0)
-
- @staticmethod
- def _GetVersion(endpoint):
- """Fetches version information from a remote Chrome instance.
-
- Args:
- endpoint: The base URL to connent to.
-
- Returns:
- A dictionary containing Browser and Content version information:
- {
- 'Browser': {
- 'major': integer,
- 'minor': integer,
- 'fix': integer,
- 'day': integer
- },
- 'Content': {
- 'name': string,
- 'major': integer,
- 'minor': integer
- }
- }
-
- Raises:
- RuntimeError: When Browser version info can't be fetched or parsed.
- """
- try:
- f = urllib2.urlopen(endpoint + '/json/version')
- result = f.read();
- result = simplejson.loads(result)
- except urllib2.URLError, e:
- raise RuntimeError(
- 'Error accessing Chrome instance debugging port: ' + str(e))
-
- if 'Browser' not in result:
- raise RuntimeError('Browser version is not specified.')
-
- parsed = re.search('^Chrome\/(\d+).(\d+).(\d+).(\d+)', result['Browser'])
- if parsed is None:
- raise RuntimeError('Browser-Version cannot be parsed.')
- try:
- day = int(parsed.group(3))
- browser_info = {
- 'major': int(parsed.group(1)),
- 'minor': int(parsed.group(2)),
- 'day': day,
- 'fix': int(parsed.group(4)),
- }
- except ValueError:
- raise RuntimeError('Browser-Version cannot be parsed.')
-
- if 'WebKit-Version' not in result:
- raise RuntimeError('Content-Version is not specified.')
-
- parsed = re.search('^(\d+)\.(\d+)', result['WebKit-Version'])
- if parsed is None:
- raise RuntimeError('Content-Version cannot be parsed.')
-
- try:
- platform_info = {
- 'name': 'Blink' if day > 1464 else 'WebKit',
- 'major': int(parsed.group(1)),
- 'minor': int(parsed.group(2)),
- }
- except ValueError:
- raise RuntimeError('WebKit-Version cannot be parsed.')
-
- return {
- 'browser': browser_info,
- 'platform': platform_info
- }
-
- def _IsContentVersionNotOlderThan(self, major, minor):
- """Compares remote Browser Content version with specified one.
-
- Args:
- major: Major Webkit version.
- minor: Minor Webkit version.
-
- Returns:
- True if remote Content version is same or newer than specified,
- False otherwise.
-
- Raises:
- RuntimeError: If remote Content version hasn't been fetched yet.
- """
- if not hasattr(self, '_version'):
- raise RuntimeError('Browser version has not been fetched yet.')
- version = self._version['platform']
-
- if version['major'] < major:
- return False
- elif version['major'] == major and version['minor'] < minor:
- return False
- else:
- return True
-
- def _IsBrowserDayNumberGreaterThan(self, day_number):
- """Compares remote Chromium day number with specified one.
-
- Args:
- day_number: Forth part of the chromium version.
-
- Returns:
- True if remote Chromium day number is same or newer than specified,
- False otherwise.
-
- Raises:
- RuntimeError: If remote Chromium version hasn't been fetched yet.
- """
- if not hasattr(self, '_version'):
- raise RuntimeError('Browser revision has not been fetched yet.')
- version = self._version['browser']
-
- return version['day'] > day_number
diff --git a/chrome/test/pyautolib/timer_queue.py b/chrome/test/pyautolib/timer_queue.py
deleted file mode 100644
index b7d668d..0000000
--- a/chrome/test/pyautolib/timer_queue.py
+++ /dev/null
@@ -1,85 +0,0 @@
-# Copyright (c) 2011 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.
-
-import copy
-import threading
-import time
-
-class TimerQueue(threading.Thread):
- """Executes timers at a given interval.
-
- This class provides the ability to run methods at a given interval. All
- methods are fired synchronously. Only one method is running at a time.
-
- Example of using TimerQueue:
- def _fooPrinter(word):
- print('foo : %s' % word)
-
- timers = TimerQueue()
- timers.addTimer(self._fooPrinter, 15, args=('hello',))
- timers.start()
-
- >> hello will be printed after 15 seconds
-
- Note: TimerQueue is a subclass of threading.Thread, call start() to activate;
- do not call run() directly.
- """
-
- def __init__(self):
- """Initializes a TimerQueue object."""
- threading.Thread.__init__(self, name='timer_thread')
- self.timer_queue_lock = threading.Lock()
- self.terminate = False
- self.wait_time = 1
- self.timers = []
-
- def AddTimer(self, method, interval, args=()):
- """Adds a timer to the queue.
-
- Args:
- method: the method to be called at the given interval
- interval: delay between method runs, in seconds
- args: arguments to be passed to the method
- """
- self.timer_queue_lock.acquire()
- next_time = time.time() + interval
- self.timers.append({'method': method, 'interval': interval,
- 'next time': next_time, 'args': copy.copy(args)})
- self.timer_queue_lock.release()
-
- def SetResolution(self, resolution):
- """Sets the timer check frequency, in seconds."""
- self.wait_time = resolution
-
- def RemoveTimer(self, method):
- """Removes a timer from the queue.
-
- Args:
- method: the timer containing the given method to be removed
- """
- self.timer_queue_lock.acquire()
- for timer in self.timers:
- if timer['method'] == method:
- self.timers.remove(timer)
- break
- self.timer_queue_lock.release()
-
- def Stop(self):
- """Stops the timer."""
- self.terminate = True
-
- def run(self):
- """Primary run loop for the timer."""
- while True:
- now = time.time()
- self.timer_queue_lock.acquire()
- for timer in self.timers:
- if timer['next time'] <= now:
- # Use * to break the list into separate arguments
- timer['method'](*timer['args'])
- timer['next time'] += timer['interval']
- self.timer_queue_lock.release()
- if self.terminate:
- return
- time.sleep(self.wait_time)
diff --git a/chrome/test/pyautolib/webdriver.DEPS/DEPS b/chrome/test/pyautolib/webdriver.DEPS/DEPS
deleted file mode 100644
index eb9f473..0000000
--- a/chrome/test/pyautolib/webdriver.DEPS/DEPS
+++ /dev/null
@@ -1,5 +0,0 @@
-deps = {
- # This is only used by the buildbot master config for chrome official.
- 'src/third_party/webdriver/pylib/selenium':
- 'http://selenium.googlecode.com/svn/trunk/py/selenium@18337',
-}