Commit 9c621c92 authored by jhorwich@chromium.org's avatar jhorwich@chromium.org

Revert 151717 - Initial checkin of the me2me pyauto automation

- Modified chromoting.py to enable me2me automation
- Added chromoting_helper.py to handle install, uninstall, enable, disable, changepin which requires admin privilege
- Added chromoting.base.py as the base for all chromoting test cases
- Modified chromoting_basic, renamed it it2me_basic and moved it under chromoting dir
- Added auth, me2me_enable, me2me_connect test
- Added a cert and a private key for signing host on mac
- Added mock_pref_pane.* files to mock the pref pane for different scenarios


NOTRY=true

Review URL: https://chromiumcodereview.appspot.com/10821015

TBR=yihongg@chromium.org
Review URL: https://chromiumcodereview.appspot.com/10837266

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@151722 0039d316-1c4b-4281-b951-d872f2087c98
parent 35d86814
......@@ -40,7 +40,7 @@
'bookmarks',
'browser',
'browsing_data',
'chromoting.it2me_basic',
'chromoting_basic',
'codesign',
'content',
'cookies',
......@@ -314,7 +314,7 @@
# You cannot resize the browser window on ChromeOS.
'-browser.BrowserTest.testWindowResize',
# ChromeOS doesn't yet support the chromoting host.
'-chromoting.it2me_basic',
'-chromoting_basic',
# No codesign verification on ChromeOS.
'-codesign',
# Import tests are invalid on ChromeOS since Chrome is the only browser.
......@@ -497,7 +497,7 @@
# Permanently-disabled tests.
# ===========================
# The chromoting webapp isn't currently available when FULL is run.
'-chromoting.it2me_basic',
'-chromoting_basic',
# ==================================================
# Disabled tests that need to be investigated/fixed.
......
#!/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()
# 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 chromoting
import pyauto
class ChromotingBase(chromoting.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 --allow-nacl-socket-api to connect chromoting successfully."""
extra_chrome_flags = ['--allow-nacl-socket-api=*',]
return pyauto.PyUITest.ExtraChromeFlags(self) + extra_chrome_flags
\ No newline at end of file
#!/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."""
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."""
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()
#!/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."""
pyauto.PyUITest.setUp(self)
self.InstallHostDaemon()
webapp = self.InstallExtension(self.GetWebappPath())
self.host.LaunchApp(webapp)
self.host.Authenticate()
self.host.StartMe2Me()
self.host.EnableConnectionsInstalled()
self.client.LaunchApp(webapp)
def tearDown(self):
"""Mainly uninstalls the host daemon."""
self.host.DisableConnections()
self.UninstallHostDaemon()
pyauto.PyUITest.tearDown(self)
def testMe2MeConnectDisconnectReconnectDisconnect(self):
"""Connects, disconnects, reconnects and disconnects"""
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."""
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."""
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."""
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()
#!/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."""
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."""
self.UninstallHostDaemon()
pyauto.PyUITest.tearDown(self)
def testMe2MeEnableDisable(self):
"""Enables/disables remote connections.
This test also exercises different pin conditions.
"""
self.host.EnableConnectionsInstalled(True)
self.host.DisableConnections()
if __name__ == '__main__':
chromoting_base.Main()
#!/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.
"""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()
#!/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 come before chromoting and pyauto.
import chromoting
import pyauto
class ChromotingBasic(chromoting.ChromotingMixIn, pyauto.PyUITest):
"""Basic tests for Chromoting."""
_EXTRA_CHROME_FLAGS = [
'--allow-nacl-socket-api=*',
]
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 setUp(self):
"""Set up test for Chromoting on both local and remote machines.
Installs the Chromoting app, launches it, and authenticates
using the default Chromoting test account.
"""
super(ChromotingBasic, self).setUp()
self._app = self.InstallExtension(self.GetWebappPath())
self.LaunchApp(self._app)
account = self.GetPrivateInfo()['test_chromoting_account']
self.Authenticate(account['username'], account['password'])
def testChromoting(self):
"""Verify that we can start and disconnect from a Chromoting session."""
client_local = (self.remote == None)
host = self
client = self if client_local else self.remote
client_tab_index = 2 if client_local else 1
access_code = host.Share()
self.assertTrue(access_code,
msg='Host attempted to share, but it failed. '
'No access code was found.')
if client_local:
client.LaunchApp(self._app)
self.assertTrue(client.Connect(access_code, True, client_tab_index),
msg='The client attempted to connect to the host, '
'but the chromoting session did not start.')
host.CancelShare()
client.Disconnect(client_tab_index)
if __name__ == '__main__':
pyauto_functional.Main()
This diff is collapsed.
#!/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 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()
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(current_dir, 'chrome', 'test',
'pyautolib', 'chromoting_key.p12')
cert = os.path.join(current_dir, 'chrome', 'test',
'pyautolib', '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.mpkg')
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 unmount "' + 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')
subprocess.call(['open', '-a', uninstall_app])
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, 'org.chromium.chromoting.prefPane')
mock_pref_pane_python = os.path.join(os.getcwd(), 'chrome', 'test',
'functional', 'chromoting',
'mock_pref_pane.py')
shutil.rmtree(mock_pref_pane, True)
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])
shutil.rmtree(pref_pane, True)
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, 'remoting-host.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, 'remoting-host.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()
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment