Пример #1
0
    def get_object_tree(self):
        """
        Get a tree of :class:`PlainBoxObject` that represents everything that
        PlainBox knows about.

        :returns:
            A :class:`PlainBoxObject` that represents the explorer
            object itself, along with all the children reachable from it.

        This function computes the following set of data::

            the explorer itself
                - all providers
                    - all jobs
                    - all executables
                - all repositories
                    - all storages
        """
        service_obj = PlainBoxObject(self,
                                     name='service object',
                                     group="service")
        # Milk each provider for jobs and test plans
        for provider in self.provider_list:
            provider_obj = PlainBoxObject(
                provider,
                group="provider",
                name=provider.name,
                attrs=OrderedDict((
                    ('broken_i18n',
                     provider.description == provider.tr_description()),
                    ('name', provider.name),
                    ('namespace', provider.namespace),
                    ('version', provider.version),
                    ('description', provider.description),
                    ('tr_description', provider.tr_description()),
                    ('jobs_dir', provider.jobs_dir),
                    ('units_dir', provider.units_dir),
                    ('data_dir', provider.data_dir),
                    ('locale_dir', provider.locale_dir),
                    ('gettext_domain', provider.gettext_domain),
                    ('base_dir', provider.base_dir),
                )))
            for unit in provider.unit_list:
                provider_obj.children.append(self._unit_to_obj(unit))
            service_obj.children.append(provider_obj)
        for storage in WellKnownDirsHelper.get_storage_list():
            storage_obj = PlainBoxObject(storage,
                                         group="storage",
                                         name=storage.location,
                                         attrs=OrderedDict((
                                             ('location', storage.location),
                                             ('session_file',
                                              storage.session_file),
                                         )))
            service_obj.children.append(storage_obj)
        return service_obj
Пример #2
0
 def test_create_remove(self):
     session_prefix = "test_storage-"
     # Create a new storage in the specified directory
     storage = SessionStorage.create(session_prefix)
     session_id = storage.id
     # The location should have been created
     self.assertTrue(os.path.exists(storage.location))
     # And it should be in the directory we indicated
     self.assertEqual(
         os.path.dirname(storage.location),
         os.path.dirname(WellKnownDirsHelper.session_dir(session_id)))
     # Remove the storage now
     storage.remove()
     # And make sure the storage is gone
     self.assertFalse(os.path.exists(storage.location))
Пример #3
0
 def list_sessions(self):
     storage = None
     for storage in WellKnownDirsHelper.get_storage_list():
         if self.ns.only_ids:
             print(storage.id)
             continue
         data = storage.load_checkpoint()
         if len(data) > 0:
             metadata = SessionPeekHelper().peek(data)
             print(_("session {0} app:{1}, flags:{2!r}, title:{3!r}")
                   .format(storage.id, metadata.app_id,
                           sorted(metadata.flags), metadata.title))
         else:
             print(_("session {0} (not saved yet)").format(storage.id))
     if not self.ns.only_ids and storage is None:
         print(_("There are no stored sessions"))
Пример #4
0
    def _handle_last_job_after_resume(self, last_job):
        if last_job is None:
            return
        if self.ctx.args.session_id:
            # session_id is present only if auto-resume is used
            result_dict = {
                'outcome': IJobResult.OUTCOME_PASS,
                'comments': _("Automatically passed after resuming execution"),
            }
            session_share = WellKnownDirsHelper.session_share(
                self.ctx.sa.get_session_id())
            result_path = os.path.join(session_share, '__result')
            if os.path.exists(result_path):
                try:
                    with open(result_path, 'rt') as f:
                        result_dict = json.load(f)
                        # the only really important field in the result is
                        # 'outcome' so let's make sure it doesn't contain
                        # anything stupid
                        if result_dict.get('outcome') not in [
                                'pass', 'fail', 'skip'
                        ]:
                            result_dict['outcome'] = IJobResult.OUTCOME_PASS
                except json.JSONDecodeError as e:
                    pass
            print(
                _("Automatically resuming session. "
                  "Outcome of the previous job: {}".format(
                      result_dict['outcome'])))
            result = MemoryJobResult(result_dict)
            self.ctx.sa.use_job_result(last_job, result)
            return

        print(
            _("Previous session run tried to execute job: {}").format(
                last_job))
        cmd = self._pick_action_cmd([
            Action('s', _("skip that job"), 'skip'),
            Action('p', _("mark it as passed and continue"), 'pass'),
            Action('f', _("mark it as failed and continue"), 'fail'),
            Action('r', _("run it again"), 'run'),
        ], _("What do you want to do with that job?"))
        if cmd == 'skip' or cmd is None:
            result = MemoryJobResult({
                'outcome':
                IJobResult.OUTCOME_SKIP,
                'comments':
                _("Skipped after resuming execution")
            })
        elif cmd == 'pass':
            result = MemoryJobResult({
                'outcome':
                IJobResult.OUTCOME_PASS,
                'comments':
                _("Passed after resuming execution")
            })
        elif cmd == 'fail':
            result = MemoryJobResult({
                'outcome':
                IJobResult.OUTCOME_FAIL,
                'comments':
                _("Failed after resuming execution")
            })
        elif cmd == 'run':
            result = None
        if result:
            self.ctx.sa.use_job_result(last_job, result)
Пример #5
0
 def test_smoke(self):
     session_prefix = "test_storage-"
     storage = SessionStorage(session_prefix)
     session_id = storage.id
     self.assertEqual(storage.location,
                      WellKnownDirsHelper.session_dir(session_id))
Пример #6
0
 def _lookup_storage(self, session_id):
     for storage in WellKnownDirsHelper.get_storage_list():
         if storage.id == session_id:
             return storage
Пример #7
0
def get_execution_environment(job, environ, session_id, nest_dir):
    """
    Get the environment required to execute the specified job:

    :param job:
        job definition with the command and environment definitions
    :param environ:
        A dictionary of environment variables which can be used to load missing
        environment definitions that apply to all jobs. It is used to provide
        values for missing environment variables that are required by the job
        (as expressed by the environ key in the job definition file).
    :param session_id:
        ID of the session that will be used to retrieve the location of session
        data
    :param nest_dir:
        A directory with a nest of symlinks to all executables required to
        execute the specified job. This argument may or may not be used,
        depending on how PATH is passed to the command (via environment or via
        the commant line)
    :return:
        dictionary with the environment to use.
    """
    # Get a proper environment
    env = dict(os.environ)
    if 'reset-locale' in job.get_flag_set():
        # Use non-internationalized environment
        env['LANG'] = 'C.UTF-8'
        if 'LANGUAGE' in env:
            del env['LANGUAGE']
        for name in list(env.keys()):
            if name.startswith("LC_"):
                del env[name]
    else:
        # Set the per-provider gettext domain and locale directory
        if job.provider.gettext_domain is not None:
            env['TEXTDOMAIN'] = env['PLAINBOX_PROVIDER_GETTEXT_DOMAIN'] = \
                job.provider.gettext_domain
        if job.provider.locale_dir is not None:
            env['TEXTDOMAINDIR'] = env['PLAINBOX_PROVIDER_LOCALE_DIR'] = \
                job.provider.locale_dir
        if (os.getenv("SNAP") or os.getenv("SNAP_APP_PATH")):
            copy_vars = ['PYTHONHOME', 'PYTHONUSERBASE', 'LD_LIBRARY_PATH',
                         'GI_TYPELIB_PATH']
            for key, value in env.items():
                if key in copy_vars or key.startswith('SNAP'):
                    env[key] = value
    # Use PATH that can lookup checkbox scripts
    if job.provider.extra_PYTHONPATH:
        env['PYTHONPATH'] = os.pathsep.join(
            [job.provider.extra_PYTHONPATH] + env.get(
                "PYTHONPATH", "").split(os.pathsep))
    # Inject nest_dir into PATH
    env['PATH'] = os.pathsep.join(
        [nest_dir] + env.get("PATH", "").split(os.pathsep))
    # Add per-session shared state directory
    env['PLAINBOX_SESSION_SHARE'] = WellKnownDirsHelper.session_share(
        session_id)

    def set_if_not_none(envvar, source):
        """Update env if the source variable is not None"""
        if source is not None:
            env[envvar] = source
    set_if_not_none('PLAINBOX_PROVIDER_DATA', job.provider.data_dir)
    set_if_not_none('PLAINBOX_PROVIDER_UNITS', job.provider.units_dir)
    set_if_not_none('CHECKBOX_SHARE', job.provider.CHECKBOX_SHARE)
    # Inject additional variables that are requested in the config
    if environ is not None:
        for env_var in environ:
            # Don't override anything that is already present in the
            # current environment. This will allow users to customize
            # variables without editing any config files.
            if env_var in env:
                continue
            # The environ dict is populated from the environment section of the
            # config file. If it has a particular variable then copy it over.
            env[env_var] = environ[env_var]
    return env
Пример #8
0
    def resume_by_id(self, session_id=None):
        _logger.info("resume_by_id: %r", session_id)
        self._launcher = load_configs()
        resume_candidates = list(self._sa.get_resumable_sessions())
        if not session_id:
            if not resume_candidates:
                print('No session to resume')
                return
            session_id = resume_candidates[0].id
        if session_id not in [s.id for s in resume_candidates]:
            print("Requested session not found")
            return
        _logger.warning("Resuming session: %r", session_id)
        runner_kwargs = {
            'normal_user_provider': lambda: self._normal_user,
            'stdin': self._pipe_to_subproc,
            'extra_env': self.prepare_extra_env(),
        }
        meta = self._sa.resume_session(session_id, runner_kwargs=runner_kwargs)
        app_blob = json.loads(meta.app_blob.decode("UTF-8"))
        launcher = app_blob['launcher']
        self._launcher.read_string(launcher, False)
        self._sa.use_alternate_configuration(self._launcher)

        self._normal_user = app_blob.get(
            'effective_normal_user', self._launcher.normal_user)
        _logger.info(
            "normal_user after loading metadata: %r", self._normal_user)
        test_plan_id = app_blob['testplan_id']
        self._sa.select_test_plan(test_plan_id)
        self._sa.bootstrap()
        self._last_job = meta.running_job_name

        result_dict = {
            'outcome': IJobResult.OUTCOME_PASS,
            'comments': _("Automatically passed after resuming execution"),
        }
        session_share = WellKnownDirsHelper.session_share(
            self._sa._manager.storage.id)
        result_path = os.path.join(session_share, '__result')
        if os.path.exists(result_path):
            try:
                with open(result_path, 'rt') as f:
                    result_dict = json.load(f)
                    # the only really important field in the result is
                    # 'outcome' so let's make sure it doesn't contain
                    # anything stupid
                    if result_dict.get('outcome') not in [
                            'pass', 'fail', 'skip']:
                        result_dict['outcome'] = IJobResult.OUTCOME_PASS
            except json.JSONDecodeError as e:
                pass
        result = MemoryJobResult(result_dict)
        if self._last_job:
            try:
                self._sa.use_job_result(self._last_job, result, True)
            except KeyError:
                raise SystemExit(self._last_job)

        # some jobs have already been run, so we need to update the attempts
        # count for future auto-rerunning
        if self._launcher.auto_retry:
            for job_id in [
                    job.id for job in self.get_rerun_candidates('auto')]:
                job_state = self._sa.get_job_state(job_id)
                job_state.attempts = self._launcher.max_attempts - len(
                    job_state.result_history)

        self._state = TestsSelected