def __init__(self, options, browsers): from internal.browsers import Browsers from internal.webpagetest import WebPageTest from internal.traffic_shaping import TrafficShaper from internal.adb import Adb from internal.ios_device import iOSDevice self.must_exit = False self.options = options self.capture_display = None self.job = None self.task = None self.xvfb = None self.root_path = os.path.abspath(os.path.dirname(__file__)) self.wpt = WebPageTest(options, os.path.join(self.root_path, "work")) self.persistent_work_dir = self.wpt.get_persistent_dir() self.adb = Adb( self.options, self.persistent_work_dir) if self.options.android else None self.ios = iOSDevice(self.options.device) if self.options.iOS else None self.browsers = Browsers(options, browsers, self.adb, self.ios) self.shaper = TrafficShaper(options) atexit.register(self.cleanup) signal.signal(signal.SIGTERM, self.signal_handler) signal.signal(signal.SIGINT, self.signal_handler) self.image_magick = { 'convert': 'convert', 'compare': 'compare', 'mogrify': 'mogrify' } if platform.system() == "Windows": paths = [os.getenv('ProgramFiles'), os.getenv('ProgramFiles(x86)')] for path in paths: if path is not None and os.path.isdir(path): dirs = sorted(os.listdir(path), reverse=True) for subdir in dirs: if subdir.lower().startswith('imagemagick'): convert = os.path.join(path, subdir, 'convert.exe') compare = os.path.join(path, subdir, 'compare.exe') mogrify = os.path.join(path, subdir, 'mogrify.exe') if os.path.isfile(convert) and \ os.path.isfile(compare) and \ os.path.isfile(mogrify): if convert.find(' ') >= 0: convert = '"{0}"'.format(convert) if compare.find(' ') >= 0: compare = '"{0}"'.format(compare) if mogrify.find(' ') >= 0: mogrify = '"{0}"'.format(mogrify) self.image_magick['convert'] = convert self.image_magick['compare'] = compare self.image_magick['mogrify'] = mogrify break
def __init__(self, options, browsers): from internal.browsers import Browsers from internal.webpagetest import WebPageTest from internal.traffic_shaping import TrafficShaper from internal.adb import Adb from internal.ios_device import iOSDevice self.must_exit = False self.options = options self.capture_display = None self.job = None self.task = None self.xvfb = None self.root_path = os.path.abspath(os.path.dirname(__file__)) self.wpt = WebPageTest(options, os.path.join(self.root_path, "work")) self.persistent_work_dir = self.wpt.get_persistent_dir() self.adb = Adb( self.options, self.persistent_work_dir) if self.options.android else None self.ios = iOSDevice(self.options.device) if self.options.iOS else None self.browsers = Browsers(options, browsers, self.adb, self.ios) self.shaper = TrafficShaper(options) atexit.register(self.cleanup) signal.signal(signal.SIGTERM, self.signal_handler) signal.signal(signal.SIGINT, self.signal_handler)
def main(): """Startup and initialization""" import argparse parser = argparse.ArgumentParser(description='WebPageTest Agent.', prog='wpt-agent') # Basic agent config parser.add_argument('-v', '--verbose', action='count', help="Increase verbosity (specify multiple times for more)." " -vvvv for full debug output.") parser.add_argument('--name', help="Agent name (for the work directory).") parser.add_argument('--exit', type=int, default=0, help='Exit after the specified number of minutes.\n' ' Useful for running in a shell script that does some maintenence\n' ' or updates periodically (like hourly).') parser.add_argument('--dockerized', action='store_true', default=False, help="Agent is running in a docker container.") parser.add_argument('--ec2', action='store_true', default=False, help="Load config settings from EC2 user data.") parser.add_argument('--gce', action='store_true', default=False, help="Load config settings from GCE user data.") parser.add_argument('--alive', help="Watchdog file to update when successfully connected.") parser.add_argument('--log', help="Log critical errors to the given file.") parser.add_argument('--noidle', action='store_true', default=False, help="Do not wait for system idle at startup.") parser.add_argument('--collectversion', action='store_true', default=False, help="Collection browser versions and submit to controller.") # Video capture/display settings parser.add_argument('--xvfb', action='store_true', default=False, help="Use an xvfb virtual display (Linux only).") parser.add_argument('--fps', type=int, choices=xrange(1, 61), default=10, help='Video capture frame rate (defaults to 10). ' 'Valid range is 1-60 (Linux only).') # Server/location configuration parser.add_argument('--server', help="URL for WebPageTest work (i.e. http://www.webpagetest.org/work/).") parser.add_argument('--validcertificate', action='store_true', default=False, help="Validate server certificates (HTTPS server, defaults to False).") parser.add_argument('--location', help="Location ID (as configured in locations.ini on the server).") parser.add_argument('--key', help="Location key (optional).") parser.add_argument('--polling', type=int, default=5, help='Polling interval for work (defaults to 5 seconds).') # Traffic-shaping options (defaults to host-based) parser.add_argument('--shaper', help='Override default traffic shaper. ' 'Current supported values are:\n' ' none - Disable traffic-shaping (i.e. when root is not available)\n.' ' netem,<interface> - Use NetEm for bridging rndis traffic ' '(specify outbound interface). i.e. --shaper netem,eth0\n' ' remote,<server>,<down pipe>,<up pipe> - Connect to the remote server ' 'over ssh and use pre-configured dummynet pipes (ssh keys for root user ' 'should be pre-authorized).') parser.add_argument('--tcpdump', help='Specify an interface to use for tcpdump.') # CPU Throttling parser.add_argument('--throttle', action='store_true', default=False, help='Enable cgroup-based CPU throttling for mobile emulation ' '(Linux only).') # Android options parser.add_argument('--android', action='store_true', default=False, help="Run tests on an attached android device.") parser.add_argument('--device', help="Device ID (only needed if more than one android device attached).") parser.add_argument('--simplert', help="Use SimpleRT for reverse-tethering. The APK should " "be installed manually (adb install simple-rt/simple-rt-1.1.apk) and " "tested once manually (./simple-rt -i eth0 then disconnect and re-connect" " phone) to dismiss any system dialogs. The ethernet interface and DNS " "server should be passed as options:\n" " <interface>,<dns1>: i.e. --simplert eth0,8.8.8.8") parser.add_argument('--gnirehtet', help="Use gnirehtet for reverse-tethering. You will need to manually " "approve the vpn once per mobile device. Valid options are:\n" " <interface>,<dns>: i.e. --gnirehtet eth0,8.8.8.8") parser.add_argument('--vpntether', help="Use vpn-reverse-tether for reverse-tethering. This is the " "recommended way to reverse-tether devices. You will need to manually " "approve the vpn once per mobile device. Valid options are:\n" " <interface>,<dns>: i.e. --vpntether eth0,8.8.8.8") parser.add_argument('--rndis', help="(deprecated) Enable reverse-tethering over rndis. " "Valid options are:\n" " dhcp: Configure interface for DHCP\n" " <ip>/<network>,<gateway>,<dns1>,<dns2>: Static Address. \n" " i.e. 192.168.0.8/24,192.168.0.1,8.8.8.8,8.8.4.4") parser.add_argument('--ping', type=str, default='8.8.8.8', help="Set custom IP or domain to ping for checking network connection " "when using Android devices. Default is 8.8.8.8") parser.add_argument('--temperature', type=int, default=36, help="set custom temperature treshold for device as int") # iOS options parser.add_argument('--iOS', action='store_true', default=False, help="Run tests on an attached iOS device " "(specify serial number in --device).") parser.add_argument('--list', action='store_true', default=False, help="List available iOS devices.") # Options for authenticating the agent with the server parser.add_argument('--username', help="User name if using HTTP Basic auth with WebPageTest server.") parser.add_argument('--password', help="Password if using HTTP Basic auth with WebPageTest server.") parser.add_argument('--cert', help="Client certificate if using certificates to " "authenticate the WebPageTest server connection.") parser.add_argument('--certkey', help="Client-side private key (if not embedded in the cert).") options, _ = parser.parse_known_args() # Make sure we are running python 2.7.11 or newer (required for Windows 8.1) if platform.system() == "Windows": if sys.version_info[0] != 2 or \ sys.version_info[1] != 7 or \ sys.version_info[2] < 11: print "Requires python 2.7.11 (or later)" exit(1) elif sys.version_info[0] != 2 or sys.version_info[1] != 7: print "Requires python 2.7" exit(1) if options.list: from internal.ios_device import iOSDevice ios = iOSDevice() devices = ios.get_devices() print "Available iOS devices:" for device in devices: print device exit(1) # Set up logging log_level = logging.CRITICAL if options.verbose == 1: log_level = logging.ERROR elif options.verbose == 2: log_level = logging.WARNING elif options.verbose == 3: log_level = logging.INFO elif options.verbose >= 4: log_level = logging.DEBUG logging.basicConfig(level=log_level, format="%(asctime)s.%(msecs)03d - %(message)s", datefmt="%H:%M:%S") if options.log: err_log = logging.handlers.RotatingFileHandler(options.log, maxBytes=1000000, backupCount=5, delay=True) err_log.setLevel(logging.ERROR) logging.getLogger().addHandler(err_log) if options.ec2 or options.gce: upgrade_pip_modules() elif platform.system() == "Windows": # recovery for a busted Windows install try: import win32api except ImportError: subprocess.call([sys.executable, '-m', 'pip', 'uninstall', '-y', 'pywin32', 'pypiwin32']) subprocess.call([sys.executable, '-m', 'pip', 'install', 'pywin32', 'pypiwin32']) browsers = None if not options.android and not options.iOS: browsers = find_browsers() if len(browsers) == 0: print "No browsers configured. Check that browsers.ini is present and correct." exit(1) if options.collectversion and platform.system() == "Windows": get_browser_versions(browsers) agent = WPTAgent(options, browsers) if agent.startup(): # Create a work directory relative to where we are running print "Running agent, hit Ctrl+C to exit" agent.run_testing() print "Done"