def run_one_test(self, prog, env, symbols_path=None):
        """
        Run a single C++ unit test program remotely.

        Arguments:
        * prog: The path to the test program to run.
        * env: The environment to use for running the program.
        * symbols_path: A path to a directory containing Breakpad-formatted
                        symbol files for producing stack traces on crash.

        Return True if the program exits with a zero status, False otherwise.
        """
        basename = os.path.basename(prog)
        remote_bin = posixpath.join(self.remote_bin_dir, basename)
        log.info("Running test %s", basename)
        buf = StringIO.StringIO()
        returncode = self.device.shell(
            [remote_bin],
            buf,
            env=env,
            cwd=self.remote_home_dir,
            timeout=cppunittests.CPPUnitTests.TEST_PROC_TIMEOUT)
        print >> sys.stdout, buf.getvalue()
        with mozfile.TemporaryDirectory() as tempdir:
            self.device.getDirectory(self.remote_home_dir, tempdir)
            if mozcrash.check_for_crashes(tempdir,
                                          symbols_path,
                                          test_name=basename):
                log.testFail("%s | test crashed", basename)
                return False
        result = returncode == 0
        if not result:
            log.testFail("%s | test failed with return code %s", basename,
                         returncode)
        return result
 def checkForCrashes(self, dump_directory, symbols_path, test_name=None):
     with mozfile.TemporaryDirectory() as dumpDir:
         self.device.pull(self.remoteMinidumpDir, dumpDir)
         crashed = mozcrash.log_crashes(
             self.log, dumpDir, symbols_path, test=test_name
         )
     return crashed
Exemple #3
0
def create_dmg(source_directory, output_dmg, volume_name, extra_files):
    '''
    Create a DMG disk image at the path output_dmg from source_directory.

    Use volume_name as the disk image volume name, and
    use extra_files as a list of tuples of (filename, relative path) to copy
    into the disk image.
    '''
    with mozfile.TemporaryDirectory() as tmpdir:
        stagedir = os.path.join(tmpdir, 'stage')
        os.mkdir(stagedir)
        # Copy the app bundle over using rsync
        rsync(source_directory, stagedir)
        # Copy extra files
        for source, target in extra_files:
            full_target = os.path.join(stagedir, target)
            mkdir(os.path.dirname(full_target))
            shutil.copyfile(source, full_target)
        # Make a symlink to /Applications. The symlink name is a space
        # so we don't have to localize it. The Applications folder icon
        # will be shown in Finder, which should be clear enough for users.
        os.symlink('/Applications', os.path.join(stagedir, ' '))
        # Set the folder attributes to use a custom icon
        set_folder_icon(stagedir)
        chmod(stagedir)
        create_dmg_from_staged(stagedir, output_dmg, tmpdir, volume_name)
Exemple #4
0
 def checkForCrashes(self, dump_directory, symbols_path, test_name=None):
     with mozfile.TemporaryDirectory() as dumpDir:
         self.device.pull(self.remoteMinidumpDir, dumpDir)
         crashed = xpcshell.XPCShellTestThread.checkForCrashes(
             self, dumpDir, symbols_path, test_name)
         self.initDir(self.remoteMinidumpDir)
     return crashed
Exemple #5
0
    def run_one_test(self, prog, env, symbols_path=None):
        """
        Run a single C++ unit test program.

        Arguments:
        * prog: The path to the test program to run.
        * env: The environment to use for running the program.
        * symbols_path: A path to a directory containing Breakpad-formatted
                        symbol files for producing stack traces on crash.

        Return True if the program exits with a zero status, False otherwise.
        """
        basename = os.path.basename(prog)
        log.info("Running test %s", basename)
        with mozfile.TemporaryDirectory() as tempdir:
            proc = mozprocess.ProcessHandler([prog], cwd=tempdir, env=env)
            #TODO: After bug 811320 is fixed, don't let .run() kill the process,
            # instead use a timeout in .wait() and then kill to get a stack.
            proc.run(timeout=CPPUnitTests.TEST_PROC_TIMEOUT,
                     outputTimeout=CPPUnitTests.TEST_PROC_NO_OUTPUT_TIMEOUT)
            proc.wait()
            if proc.timedOut:
                log.testFail("%s | timed out after %d seconds", basename,
                             CPPUnitTests.TEST_PROC_TIMEOUT)
                return False
            if mozcrash.check_for_crashes(tempdir,
                                          symbols_path,
                                          test_name=basename):
                log.testFail("%s | test crashed", basename)
                return False
            result = proc.proc.returncode == 0
            if not result:
                log.testFail("%s | test failed with return code %d", basename,
                             proc.proc.returncode)
            return result
    def run_one_test(self, prog, env, symbols_path=None, interactive=False,
                     timeout_factor=1):
        """
        Run a single C++ unit test program.

        Arguments:
        * prog: The path to the test program to run.
        * env: The environment to use for running the program.
        * symbols_path: A path to a directory containing Breakpad-formatted
                        symbol files for producing stack traces on crash.
        * timeout_factor: An optional test-specific timeout multiplier.

        Return True if the program exits with a zero status, False otherwise.
        """
        basename = os.path.basename(prog)
        self.log.test_start(basename)
        with mozfile.TemporaryDirectory() as tempdir:
            if interactive:
                # For tests run locally, via mach, print output directly
                proc = mozprocess.ProcessHandler([prog],
                                                 cwd=tempdir,
                                                 env=env,
                                                 storeOutput=False)
            else:
                proc = mozprocess.ProcessHandler([prog],
                                                 cwd=tempdir,
                                                 env=env,
                                                 storeOutput=True,
                                                 processOutputLine=lambda _: None)
            # TODO: After bug 811320 is fixed, don't let .run() kill the process,
            # instead use a timeout in .wait() and then kill to get a stack.
            test_timeout = CPPUnitTests.TEST_PROC_TIMEOUT * timeout_factor
            proc.run(timeout=test_timeout,
                     outputTimeout=CPPUnitTests.TEST_PROC_NO_OUTPUT_TIMEOUT)
            proc.wait()
            if proc.output:
                if self.fix_stack:
                    procOutput = [self.fix_stack(l) for l in proc.output]
                else:
                    procOutput = proc.output

                output = "\n%s" % "\n".join(procOutput)
                self.log.process_output(proc.pid, output, command=[prog])
            if proc.timedOut:
                message = "timed out after %d seconds" % CPPUnitTests.TEST_PROC_TIMEOUT
                self.log.test_end(basename, status='TIMEOUT', expected='PASS',
                                  message=message)
                return False
            if mozcrash.check_for_crashes(tempdir, symbols_path,
                                          test_name=basename):
                self.log.test_end(basename, status='CRASH', expected='PASS')
                return False
            result = proc.proc.returncode == 0
            if not result:
                self.log.test_end(basename, status='FAIL', expected='PASS',
                                  message=("test failed with return code %d" %
                                           proc.proc.returncode))
            else:
                self.log.test_end(basename, status='PASS', expected='PASS')
            return result
Exemple #7
0
def create_dmg(source_directory, output_dmg, volume_name, extra_files):
    '''
    Create a DMG disk image at the path output_dmg from source_directory.

    Use volume_name as the disk image volume name, and
    use extra_files as a list of tuples of (filename, relative path) to copy
    into the disk image.
    '''
    if platform.system() not in ('Darwin', 'Linux'):
        raise Exception("Don't know how to build a DMG on '%s'" % platform.system())

    if is_linux:
        check_tools('DMG_TOOL', 'MKFSHFS', 'HFS_TOOL')
    with mozfile.TemporaryDirectory() as tmpdir:
        stagedir = os.path.join(tmpdir, 'stage')
        os.mkdir(stagedir)
        # Copy the app bundle over using rsync
        rsync(source_directory, stagedir)
        # Copy extra files
        for source, target in extra_files:
            full_target = os.path.join(stagedir, target)
            mkdir(os.path.dirname(full_target))
            shutil.copyfile(source, full_target)
        generate_hfs_file(stagedir, tmpdir, volume_name)
        create_app_symlink(stagedir, tmpdir)
        # Set the folder attributes to use a custom icon
        set_folder_icon(stagedir, tmpdir)
        chmod(stagedir)
        create_dmg_from_staged(stagedir, output_dmg, tmpdir, volume_name)
Exemple #8
0
def extract_dmg(dmgfile, output, dsstore=None, icon=None, background=None):
    if platform.system() not in ("Darwin", "Linux"):
        raise Exception("Don't know how to extract a DMG on '%s'" %
                        platform.system())

    if is_linux:
        check_tools("DMG_TOOL", "MKFSHFS", "HFS_TOOL")

    with mozfile.TemporaryDirectory() as tmpdir:
        extract_dmg_contents(dmgfile, tmpdir)
        if os.path.islink(os.path.join(tmpdir, " ")):
            # Rsync will fail on the presence of this symlink
            os.remove(os.path.join(tmpdir, " "))
        rsync(tmpdir, output)

        if dsstore:
            mkdir(os.path.dirname(dsstore))
            rsync(os.path.join(tmpdir, ".DS_Store"), dsstore)
        if background:
            mkdir(os.path.dirname(background))
            rsync(
                os.path.join(tmpdir, ".background",
                             os.path.basename(background)),
                background,
            )
        if icon:
            mkdir(os.path.dirname(icon))
            rsync(os.path.join(tmpdir, ".VolumeIcon.icns"), icon)
Exemple #9
0
    def run_one_test(self,
                     prog,
                     env,
                     symbols_path=None,
                     interactive=False,
                     timeout_factor=1):
        """
        Run a single C++ unit test program remotely.

        Arguments:
        * prog: The path to the test program to run.
        * env: The environment to use for running the program.
        * symbols_path: A path to a directory containing Breakpad-formatted
                        symbol files for producing stack traces on crash.
        * timeout_factor: An optional test-specific timeout multiplier.

        Return True if the program exits with a zero status, False otherwise.
        """
        basename = os.path.basename(prog)
        remote_bin = posixpath.join(self.remote_bin_dir, basename)
        self.log.test_start(basename)
        test_timeout = cppunittests.CPPUnitTests.TEST_PROC_TIMEOUT * timeout_factor

        try:
            output = self.device.shell_output(remote_bin,
                                              env=env,
                                              cwd=self.remote_home_dir,
                                              timeout=test_timeout)
            returncode = 0
        except ADBTimeoutError:
            raise
        except ADBProcessError as e:
            output = e.adb_process.stdout
            returncode = e.adb_process.exitcode

        self.log.process_output(basename,
                                "\n%s" % output,
                                command=[remote_bin])
        with mozfile.TemporaryDirectory() as tempdir:
            self.device.pull(self.remote_home_dir, tempdir)
            if mozcrash.check_for_crashes(tempdir,
                                          symbols_path,
                                          test_name=basename):
                self.log.test_end(basename, status="CRASH", expected="PASS")
                return False
        result = returncode == 0
        if not result:
            self.log.test_end(
                basename,
                status="FAIL",
                expected="PASS",
                message=("test failed with return code %s" % returncode),
            )
        else:
            self.log.test_end(basename, status="PASS", expected="PASS")
        return result
 def checkForCrashes(self, dump_directory, symbols_path, test_name=None):
     if not self.device.dirExists(self.remoteMinidumpDir):
         # The minidumps directory is automatically created when Fennec
         # (first) starts, so its lack of presence is a hint that
         # something went wrong.
         print "Automation Error: No crash directory (%s) found on remote device" % self.remoteMinidumpDir
         # Whilst no crash was found, the run should still display as a failure
         return True
     with mozfile.TemporaryDirectory() as dumpDir:
         self.device.getDirectory(self.remoteMinidumpDir, dumpDir)
         crashed = xpcshell.XPCShellTestThread.checkForCrashes(
             self, dumpDir, symbols_path, test_name)
         self.clearRemoteDir(self.remoteMinidumpDir)
     return crashed
    def run_one_test(self,
                     prog,
                     env,
                     symbols_path=None,
                     interactive=False,
                     timeout_factor=1):
        """
        Run a single C++ unit test program remotely.

        Arguments:
        * prog: The path to the test program to run.
        * env: The environment to use for running the program.
        * symbols_path: A path to a directory containing Breakpad-formatted
                        symbol files for producing stack traces on crash.
        * timeout_factor: An optional test-specific timeout multiplier.

        Return True if the program exits with a zero status, False otherwise.
        """
        basename = os.path.basename(prog)
        remote_bin = posixpath.join(self.remote_bin_dir, basename)
        self.log.test_start(basename)
        buf = StringIO.StringIO()
        test_timeout = cppunittests.CPPUnitTests.TEST_PROC_TIMEOUT * \
            timeout_factor
        returncode = self.device.shell([remote_bin],
                                       buf,
                                       env=env,
                                       cwd=self.remote_home_dir,
                                       timeout=test_timeout)
        self.log.process_output(basename,
                                "\n%s" % buf.getvalue(),
                                command=[remote_bin])
        with mozfile.TemporaryDirectory() as tempdir:
            self.device.getDirectory(self.remote_home_dir, tempdir)
            if mozcrash.check_for_crashes(tempdir,
                                          symbols_path,
                                          test_name=basename):
                self.log.test_end(basename, status='CRASH', expected='PASS')
                return False
        result = returncode == 0
        if not result:
            self.log.test_end(basename,
                              status='FAIL',
                              expected='PASS',
                              message=("test failed with return code %s" %
                                       returncode))
        else:
            self.log.test_end(basename, status='PASS', expected='PASS')
        return result
    def push_libs(self):
        if self.options.local_apk:
            with mozfile.TemporaryDirectory() as tmpdir:
                apk_contents = ZipFile(self.options.local_apk)
                szip = os.path.join(self.options.local_bin, '..', 'host',
                                    'bin', 'szip')
                if not os.path.exists(szip):
                    # Tinderbox builds must run szip from the test package
                    szip = os.path.join(self.options.local_bin, 'host', 'szip')
                if not os.path.exists(szip):
                    # If the test package doesn't contain szip, it means files
                    # are not szipped in the test package.
                    szip = None

                for info in apk_contents.infolist():
                    if info.filename.endswith(".so"):
                        print >> sys.stderr, "Pushing %s.." % info.filename
                        remote_file = posixpath.join(
                            self.remote_bin_dir,
                            os.path.basename(info.filename))
                        apk_contents.extract(info, tmpdir)
                        file = os.path.join(tmpdir, info.filename)
                        if szip:
                            out = subprocess.check_output(
                                [szip, '-d', file], stderr=subprocess.STDOUT)
                        self.device.pushFile(
                            os.path.join(tmpdir, info.filename), remote_file)
            return

        elif self.options.local_lib:
            for file in os.listdir(self.options.local_lib):
                if file.endswith(".so"):
                    print >> sys.stderr, "Pushing %s.." % file
                    remote_file = posixpath.join(self.remote_bin_dir, file)
                    self.device.pushFile(
                        os.path.join(self.options.local_lib, file),
                        remote_file)
            # Additional libraries may be found in a sub-directory such as "lib/armeabi-v7a"
            local_arm_lib = os.path.join(self.options.local_lib, "lib")
            if os.path.isdir(local_arm_lib):
                for root, dirs, files in os.walk(local_arm_lib):
                    for file in files:
                        if (file.endswith(".so")):
                            remote_file = posixpath.join(
                                self.remote_bin_dir, file)
                            self.device.pushFile(os.path.join(root, file),
                                                 remote_file)
Exemple #13
0
    def push_libs(self):
        if self.options.local_apk:
            with mozfile.TemporaryDirectory() as tmpdir:
                apk_contents = ZipFile(self.options.local_apk)

                for info in apk_contents.infolist():
                    if info.filename.endswith(".so"):
                        print("Pushing %s.." % info.filename, file=sys.stderr)
                        remote_file = posixpath.join(
                            self.remote_bin_dir,
                            os.path.basename(info.filename))
                        apk_contents.extract(info, tmpdir)
                        local_file = os.path.join(tmpdir, info.filename)
                        with open(local_file) as f:
                            # Decompress xz-compressed file.
                            if f.read(5)[1:] == "7zXZ":
                                cmd = [
                                    "xz", "-df", "--suffix", ".so", local_file
                                ]
                                subprocess.check_output(cmd)
                                # xz strips the ".so" file suffix.
                                os.rename(local_file[:-3], local_file)
                        self.device.push(local_file, remote_file)

        elif self.options.local_lib:
            for path in os.listdir(self.options.local_lib):
                if path.endswith(".so"):
                    print("Pushing {}..".format(path), file=sys.stderr)
                    remote_file = posixpath.join(self.remote_bin_dir, path)
                    local_file = os.path.join(self.options.local_lib, path)
                    self.device.push(local_file, remote_file)
            # Additional libraries may be found in a sub-directory such as
            # "lib/armeabi-v7a"
            for subdir in ["assets", "lib"]:
                local_arm_lib = os.path.join(self.options.local_lib, subdir)
                if os.path.isdir(local_arm_lib):
                    for root, dirs, paths in os.walk(local_arm_lib):
                        for path in paths:
                            if path.endswith(".so"):
                                print("Pushing {}..".format(path),
                                      file=sys.stderr)
                                remote_file = posixpath.join(
                                    self.remote_bin_dir, path)
                                local_file = os.path.join(root, path)
                                self.device.push(local_file, remote_file)
Exemple #14
0
    def push_libs(self):
        if self.options.local_apk:
            with mozfile.TemporaryDirectory() as tmpdir:
                apk_contents = ZipFile(self.options.local_apk)

                for info in apk_contents.infolist():
                    if info.filename.endswith(".so"):
                        print >> sys.stderr, "Pushing %s.." % info.filename
                        remote_file = posixpath.join(
                            self.remote_bin_dir,
                            os.path.basename(info.filename))
                        apk_contents.extract(info, tmpdir)
                        local_file = os.path.join(tmpdir, info.filename)
                        with open(local_file) as f:
                            # Decompress xz-compressed file.
                            if f.read(5)[1:] == '7zXZ':
                                cmd = [
                                    'xz', '-df', '--suffix', '.so', local_file
                                ]
                                subprocess.check_output(cmd)
                                # xz strips the ".so" file suffix.
                                os.rename(local_file[:-3], local_file)
                        self.device.pushFile(local_file, remote_file)

        elif self.options.local_lib:
            for file in os.listdir(self.options.local_lib):
                if file.endswith(".so"):
                    print >> sys.stderr, "Pushing %s.." % file
                    remote_file = posixpath.join(self.remote_bin_dir, file)
                    local_file = os.path.join(self.options.local_lib, file)
                    self.device.pushFile(local_file, remote_file)
            # Additional libraries may be found in a sub-directory such as "lib/armeabi-v7a"
            for subdir in ["assets", "lib"]:
                local_arm_lib = os.path.join(self.options.local_lib, subdir)
                if os.path.isdir(local_arm_lib):
                    for root, dirs, files in os.walk(local_arm_lib):
                        for file in files:
                            if (file.endswith(".so")):
                                print >> sys.stderr, "Pushing %s.." % file
                                remote_file = posixpath.join(
                                    self.remote_bin_dir, file)
                                local_file = os.path.join(root, file)
                                self.device.pushFile(local_file, remote_file)
Exemple #15
0
def extract_dmg_contents(dmgfile, destdir):
    import buildconfig
    if is_linux:
        with mozfile.TemporaryDirectory() as tmpdir:
            hfs_file = os.path.join(tmpdir, 'firefox.hfs')
            subprocess.check_call([
                    buildconfig.substs['DMG_TOOL'],
                    'extract',
                    dmgfile,
                    hfs_file
                ],
                # dmg is seriously chatty
                stdout=open(os.devnull, 'wb'))
            subprocess.check_call([
                buildconfig.substs['HFS_TOOL'], hfs_file, 'extractall', '/', destdir])
    else:
        unpack_diskimage = os.path.join(buildconfig.topsrcdir, 'build', 'package',
                                        'mac_osx', 'unpack-diskimage')
        unpack_mountpoint = os.path.join(
            '/tmp', '{}-unpack'.format(buildconfig.substs['MOZ_APP_NAME']))
        subprocess.check_call([unpack_diskimage, dmgfile, unpack_mountpoint,
                               destdir])
Exemple #16
0
def extract_dmg_contents(dmgfile, destdir):
    import buildconfig

    if is_linux:
        with mozfile.TemporaryDirectory() as tmpdir:
            hfs_file = os.path.join(tmpdir, "firefox.hfs")
            subprocess.check_call(
                [buildconfig.substs["DMG_TOOL"], "extract", dmgfile, hfs_file],
                # dmg is seriously chatty
                stdout=open(os.devnull, "wb"),
            )
            subprocess.check_call([
                buildconfig.substs["HFS_TOOL"], hfs_file, "extractall", "/",
                destdir
            ])
    else:
        unpack_diskimage = os.path.join(buildconfig.topsrcdir, "build",
                                        "package", "mac_osx",
                                        "unpack-diskimage")
        unpack_mountpoint = os.path.join(
            "/tmp", "{}-unpack".format(buildconfig.substs["MOZ_APP_NAME"]))
        subprocess.check_call(
            [unpack_diskimage, dmgfile, unpack_mountpoint, destdir])
Exemple #17
0
    def run(self):
        if self.options.remote_webserver:
            httpd_host = self.options.remote_webserver.split(':')[0]
        else:
            httpd_host = self.httpd.host
        httpd_port = self.httpd.httpd.server_port

        locations = ServerLocations()
        locations.add_host(host=httpd_host,
                           port=httpd_port,
                           options='primary,privileged')

        #TODO: use Preferences.read when prefs_general.js has been updated
        prefpath = self.options.prefs
        prefs = {}
        prefs.update(Preferences.read_prefs(prefpath))
        interpolation = {
            "server": "%s:%d" % (httpd_host, httpd_port),
            "OOP": "false"
        }
        prefs = json.loads(json.dumps(prefs) % interpolation)
        for pref in prefs:
            prefs[pref] = Preferences.cast(prefs[pref])
        prefs[
            "steeplechase.signalling_server"] = self.options.signalling_server
        prefs["steeplechase.signalling_room"] = str(uuid.uuid4())
        if self.options.timeout is None:
            prefs["steeplechase.timeout"] = 30000
        else:
            prefs["steeplechase.timeout"] = self.options.timeout
        prefs["media.navigator.permission.disabled"] = True
        prefs["media.navigator.streams.fake"] = True

        specialpowers_path = self.options.specialpowers
        threads = []
        results = []
        cond = threading.Condition()
        for info in self.remote_info:
            with mozfile.TemporaryDirectory() as profile_path:
                # Create and push profile
                print "Writing profile for %s..." % info['name']
                prefs["steeplechase.is_initiator"] = info['is_initiator']
                profile = FirefoxProfile(profile=profile_path,
                                         preferences=prefs,
                                         addons=[specialpowers_path],
                                         locations=locations)
                print "Pushing profile to %s..." % info['name']
                remote_profile_path = posixpath.join(info['test_root'],
                                                     "profile")
                info['dm'].mkDir(remote_profile_path)
                info['dm'].pushDir(profile_path, remote_profile_path)
                info['remote_profile_path'] = remote_profile_path

            env = {}
            env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
            env["XPCOM_DEBUG_BREAK"] = "warn"
            env["DISPLAY"] = self.options.remote_xdisplay

            cmd = [
                info['remote_app_path'], "-no-remote", "-profile",
                info['remote_profile_path'],
                'http://%s:%d/index.html' % (httpd_host, httpd_port)
            ]
            print "cmd: %s" % (cmd, )
            t = RunThread(name=info['name'],
                          args=(info['dm'], cmd, env, cond, results))
            threads.append(t)

        for t in threads:
            t.start()

        self.log.info("Waiting for results...")
        pass_count, fail_count = 0, 0
        outputs = {}
        while threads:
            cond.acquire()
            while not results:
                cond.wait()
            thread, result, output = results.pop(0)
            cond.release()
            outputs[thread.name] = output
            passes, failures = result
            #XXX: double-counting tests from both clients. Ok?
            pass_count += passes
            fail_count += failures
            if failures:
                self.log.error("Error in %s" % thread.name)
            threads.remove(thread)
        self.log.info("All clients finished")
        for info in self.remote_info:
            if self.options.log_dest:
                with open(
                        os.path.join(self.options.log_dest,
                                     "%s.log" % info['name']), "wb") as f:
                    f.write(outputs[info['name']])
            if fail_count:
                self.log.info("Log output for %s:", info["name"])
                self.log.info(">>>>>>>")
                for line in outputs[info['name']].splitlines():
                    #TODO: make structured log messages human-readable
                    self.log.info(line)
                self.log.info("<<<<<<<")
        return pass_count, fail_count