Ejemplo n.º 1
0
    def __init__(self, pav_cfg, tests, _id=None):
        """Initialize the suite.
        :param pav_cfg: The pavilion configuration object.
        :param list tests: The list of test objects that belong to this suite.
        :param int _id: The test id number. If this is given, it implies that
            we're regenerating this suite from saved files.
        """

        self.pav_cfg = pav_cfg
        self.tests = {test.id: test for test in tests}

        if not tests:
            raise SuiteError("You cannot create a suite of zero tests.")

        suites_path = os.path.join(self.pav_cfg.working_dir, 'suites')

        # We're creating this suite from scratch.
        if _id is None:
            # Get the suite id and path.
            try:
                self.id, self.path = utils.create_id_dir(suites_path)
            except (OSError, TimeoutError) as err:
                raise SuiteError(
                    "Could not get id or suite directory in '{}': {}".format(
                        suites_path, err))

            # Create a soft link to the test directory of each test in the
            # suite.
            for test in tests:
                link_path = utils.make_id_path(self.path, test.id)

                try:
                    os.symlink(test.path, link_path)
                except OSError as err:
                    raise SuiteError(
                        "Could not link test '{}' in suite at '{}': {}".format(
                            test.path, link_path, err))

            # Save the last suite we created to the .pavilion directory
            # in the user's home dir. Pavilion commands can use this so the
            # user doesn't actually have to know the suite_id of tests.
            try:
                user_pav_dir = os.path.expanduser('~/.pavilion')
                if not os.path.exists(user_pav_dir):
                    os.mkdir(user_pav_dir)

                last_suite_fn = os.path.join(user_pav_dir, 'last_suite')
                with open(last_suite_fn, 'w') as last_suite_file:
                    last_suite_file.write(str(self.id))
            except (IOError, OSError):
                # It's ok if we can't write this file.
                pass
        else:
            self.id = _id
            self.path = utils.make_id_path(suites_path, self.id)

        self._logger = logging.getLogger(self.LOGGER_FMT.format(self.id))
Ejemplo n.º 2
0
    def create_id_dir(id_dir):
        """In the given directory, create the lowest numbered (positive integer)
directory that doesn't already exist.

:param Path id_dir: Path to the directory that contains these 'id'
    directories
:returns: The id and path to the created directory.
:rtype: list(int, Path)
:raises OSError: on directory creation failure.
:raises TimeoutError: If we couldn't get the lock in time.
"""

        lockfile_path = id_dir / '.lockfile'
        with lockfile.LockFile(lockfile_path, timeout=1):
            ids = list(os.listdir(str(id_dir)))
            # Only return the test directories that could be integers.
            ids = [id_ for id_ in ids if id_.isdigit()]
            ids = [id_ for id_ in ids if (id_dir / id_).is_dir()]
            ids = [int(id_) for id_ in ids]
            ids.sort()

            # Find the first unused id.
            id_ = 1
            while id_ in ids:
                id_ += 1

            path = utils.make_id_path(id_dir, id_)
            path.mkdir()

        return id_, path
Ejemplo n.º 3
0
    def run(self, pav_cfg, args):
        """List the run directory for the given run."""

        test_dir = pav_cfg.working_dir / 'test_runs'
        job_dir = utils.make_id_path(test_dir, args.job_id)

        if os.path.isdir(job_dir.as_posix()) is False:
            output.fprint("directory '{}' does not exist.".format(job_dir),
                          file=sys.stderr,
                          color=output.RED)
            return errno.EEXIST

        if args.path is True:
            output.fprint(job_dir)
            return 0

        output.fprint(str(job_dir) + ':', file=sys.stdout)

        if args.tree is True:
            level = 0
            self.tree_(level, job_dir)
            return 0

        if args.subdir:
            return self.ls_(job_dir / args.subdir[0])
        else:
            return self.ls_(job_dir)
Ejemplo n.º 4
0
    def from_id(cls, pav_cfg, id_):

        suites_path = os.path.join(pav_cfg.working_dir, 'suites')
        suite_path = utils.make_id_path(suites_path, id_)

        if not os.path.exists(suite_path):
            raise SuiteError("No such suite found: '{}' at '{}'".format(
                id_, suite_path))

        logger = logging.getLogger(cls.LOGGER_FMT.format(id_))

        tests = []
        for path in os.listdir(suite_path):
            link_path = os.path.join(suite_path, path)
            if os.path.islink(link_path) and os.path.isdir(link_path):
                try:
                    test_id = int(os.path.basename(link_path))
                except ValueError:
                    logger.info(
                        "Bad test id in suite from dir '{}'".format(link_path))
                    continue

                tests.append(PavTest.from_id(pav_cfg, test_id=test_id))
            else:
                logger.info("Polluted suite directory in suite '{}'".format(
                    suite_path))
                raise ValueError(link_path)

        return cls(pav_cfg, tests, _id=id_)
Ejemplo n.º 5
0
    def from_id(cls, pav_cfg, id_):

        series_path = pav_cfg.working_dir/'series'
        series_path = utils.make_id_path(series_path, id_)

        if not series_path.exists():
            raise TestSeriesError("No such series found: '{}' at '{}'"
                                  .format(id_, series_path))

        logger = logging.getLogger(cls.LOGGER_FMT.format(id_))

        tests = []
        for path in os.listdir(str(series_path)):
            link_path = series_path/path
            if link_path.is_symlink() and link_path.is_dir():
                try:
                    test_id = int(link_path.name)
                except ValueError:
                    logger.info(
                        "Bad test id in series from dir '%s'",
                        link_path)
                    continue

                tests.append(PavTest.load(pav_cfg, test_id=test_id))
            else:
                logger.info("Polluted series directory in series '%s'",
                            series_path)
                raise ValueError(link_path)

        return cls(pav_cfg, tests, _id=id_)
Ejemplo n.º 6
0
    def __init__(self, pav_cfg, tests, _id=None):
        """Initialize the series.
        :param pav_cfg: The pavilion configuration object.
        :param list tests: The list of test objects that belong to this series.
        :param int _id: The test id number. If this is given, it implies that
            we're regenerating this series from saved files.
        """

        self.pav_cfg = pav_cfg
        self.tests = {test.id: test for test in tests}

        if not tests:
            raise TestSeriesError("You cannot create a series of zero tests.")

        series_path = self.pav_cfg.working_dir/'series'

        # We're creating this series from scratch.
        if _id is None:
            # Get the series id and path.
            try:
                self._id, self.path = PavTest.create_id_dir(series_path)
            except (OSError, TimeoutError) as err:
                raise TestSeriesError(
                    "Could not get id or series directory in '{}': {}"
                    .format(series_path, err))

            # Create a soft link to the test directory of each test in the
            # series.
            for test in tests:
                link_path = utils.make_id_path(self.path, test.id)

                try:
                    link_path.symlink_to(test.path)
                except OSError as err:
                    raise TestSeriesError(
                        "Could not link test '{}' in series at '{}': {}"
                        .format(test.path, link_path, err))

            self._save_series_id()

        else:
            self._id = _id
            self.path = utils.make_id_path(series_path, self._id)

        self._logger = logging.getLogger(self.LOGGER_FMT.format(self._id))
Ejemplo n.º 7
0
    def run(self, pav_cfg, args):
        test_dir = pav_cfg.working_dir / 'test_runs'
        job_dir = utils.make_id_path(test_dir, args.job_id)

        if os.path.isdir(job_dir.as_posix()) is False:
            output.fprint("directory '{}' does not exist."
                          .format(job_dir.as_posix()),
                          file=sys.stderr, color=output.RED)
            return errno.EEXIST

        level = 0
        print_directory(level, job_dir)
        return 0
Ejemplo n.º 8
0
    def run(self, pav_cfg, args):
        """Run this command."""

        test_dir = pav_cfg.working_dir / 'test_runs'
        job_dir = utils.make_id_path(test_dir, args.job_id)

        if os.path.isdir(job_dir.as_posix()) is False:
            output.fprint("directory '{}' does not exist.".format(
                job_dir.as_posix()),
                          file=sys.stderr,
                          color=output.RED)
            return errno.EEXIST

        return print_file(job_dir / args.file)
Ejemplo n.º 9
0
    def from_id(cls, pav_cfg, test_id):
        """Load a new PavTest object based on id."""

        path = utils.make_id_path(os.path.join(pav_cfg.working_dir, 'tests'),
                                  test_id)

        if not os.path.isdir(path):
            raise PavTestError("Test directory for test id {} does not exist "
                               "at '{}' as expected."
                               .format(test_id, path))

        config = cls._load_config(path)

        return PavTest(pav_cfg, config, test_id)
Ejemplo n.º 10
0
    def load(cls, pav_cfg, test_id):
        """Load an old PavTest object given a test id.
        :param pav_cfg: The pavilion config
        :param int test_id: The test's id number.
        """

        path = utils.make_id_path(pav_cfg.working_dir / 'tests', test_id)

        if not path.is_dir():
            raise PavTestError("Test directory for test id {} does not exist "
                               "at '{}' as expected.".format(test_id, path))

        config = cls._load_config(path)

        return PavTest(pav_cfg, config, None, _id=test_id)
Ejemplo n.º 11
0
    def from_id(cls, pav_cfg, id_):
        """Load a series object from the given id, along with all of its
associated tests."""

        try:
            id_ = int(id_[1:])
        except TypeError as err:
            pass

        series_path = pav_cfg.working_dir/'series'
        series_path = utils.make_id_path(series_path, id_)

        if not series_path.exists():
            raise TestSeriesError("No such series found: '{}' at '{}'"
                                  .format(id_, series_path))

        logger = logging.getLogger(cls.LOGGER_FMT.format(id_))

        tests = []
        for path in os.listdir(str(series_path)):
            link_path = series_path/path
            if link_path.is_symlink() and link_path.is_dir():
                try:
                    test_id = int(link_path.name)
                except ValueError:
                    logger.info(
                        "Bad test id in series from dir '%s'",
                        link_path)
                    continue

                try:
                    tests.append(TestRun.load(pav_cfg, test_id=test_id))
                except TestRunError as err:
                    logger.info(
                        "Error loading test %s: %s",
                        test_id, err
                    )

            else:
                logger.info("Polluted series directory in series '%s'",
                            series_path)
                raise ValueError(link_path)

        return cls(pav_cfg, tests, _id=id_)
Ejemplo n.º 12
0
    def __init__(self, pav_cfg, config, var_man=None, _id=None):
        """Create an new TestRun object. If loading an existing test
    instance, use the ``TestRun.from_id()`` method.

:param pav_cfg: The pavilion configuration.
:param dict config: The test configuration dictionary.
:param variables.VariableSetManager var_man: The variable set manager for this
    test.
:param int _id: The test id of an existing test. (You should be using
            TestRun.load).
"""

        # Just about every method needs this
        self._pav_cfg = pav_cfg

        self.load_ok = True

        # Compute the actual name of test, using the subtitle config parameter.
        self.name = '.'.join([
            config.get('suite', '<unknown>'),
            config.get('name', '<unnamed>')
        ])
        if 'subtitle' in config and config['subtitle']:
            self.name = self.name + '.' + config['subtitle']

        self.scheduler = config['scheduler']

        # Create the tests directory if it doesn't already exist.
        tests_path = pav_cfg.working_dir / 'test_runs'

        self.config = config

        self.id = None  # pylint: disable=invalid-name

        # Get an id for the test, if we weren't given one.
        if _id is None:
            self.id, self.path = self.create_id_dir(tests_path)
            self._save_config()
            self.var_man = var_man
            self.var_man.save(self.path / 'variables')
        else:
            self.id = _id
            self.path = utils.make_id_path(tests_path, self.id)
            if not self.path.is_dir():
                raise TestRunNotFoundError(
                    "No test with id '{}' could be found.".format(self.id))
            try:
                self.var_man = variables.VariableSetManager.load(self.path /
                                                                 'variables')
            except RuntimeError as err:
                raise TestRunError(*err.args)

        # Set a logger more specific to this test.
        self.logger = logging.getLogger('pav.TestRun.{}'.format(self.id))

        # This will be set by the scheduler
        self._job_id = None

        # Setup the initial status file.
        self.status = StatusFile(self.path / 'status')
        if _id is None:
            self.status.set(STATES.CREATED,
                            "Test directory and status file created.")

        self._started = None
        self._finished = None

        self.build_path = None  # type: Path
        self.build_name = None
        self.build_hash = None  # type: str
        self.build_origin = None  # type: Path
        self.run_log = self.path / 'run.log'
        self.results_path = self.path / 'results.json'

        build_config = self.config.get('build', {})

        # make sure build source_download_name is not set without
        # source_location
        try:
            if build_config['source_download_name'] is not None:
                if build_config['source_location'] is None:
                    msg = "Test could not be build. Need 'source_location'."
                    fprint(msg)
                    self.status.set(
                        STATES.BUILD_ERROR,
                        "'source_download_name is set without a "
                        "'source_location'")
                    raise TestConfigError(msg)
        except KeyError:
            # this is mostly for unit tests that create test configs without a
            # build section at all
            pass

        self.build_script_path = self.path / 'build.sh'  # type: Path
        self.build_path = self.path / 'build'
        if _id is None:
            self._write_script(path=self.build_script_path,
                               config=build_config)

        if _id is None:
            self.build_hash = self._create_build_hash(build_config)
            with (self.path / 'build_hash').open('w') as build_hash_file:
                build_hash_file.write(self.build_hash)
        else:
            build_hash_fn = self.path / 'build_hash'
            if build_hash_fn.exists():
                with build_hash_fn.open() as build_hash_file:
                    self.build_hash = build_hash_file.read()

        if self.build_hash is not None:
            short_hash = self.build_hash[:self.BUILD_HASH_BYTES * 2]
            self.build_name = '{hash}'.format(hash=short_hash)
            self.build_origin = pav_cfg.working_dir / 'builds' / self.build_name

        run_config = self.config.get('run', {})
        self.run_tmpl_path = self.path / 'run.tmpl'
        self.run_script_path = self.path / 'run.sh'

        if _id is None:
            self._write_script(path=self.run_tmpl_path, config=run_config)

        if _id is None:
            self.status.set(STATES.CREATED, "Test directory setup complete.")

        # Checking validity of timeout values.
        for loc in ['build', 'run']:
            if loc in config and 'timeout' in config[loc]:
                try:
                    if config[loc]['timeout'] is None:
                        test_timeout = None
                    else:
                        test_timeout = int(config[loc]['timeout'])
                        if test_timeout < 0:
                            raise ValueError()
                except ValueError:
                    raise TestRunError(
                        "{} timeout must be a non-negative "
                        "integer or empty.  Received {}.".format(
                            loc, config[loc]['timeout']))
                else:
                    if loc == 'build':
                        self._build_timeout = test_timeout
                    else:
                        self._run_timeout = test_timeout
Ejemplo n.º 13
0
    def __init__(self, pav_cfg, config, sys_vars, _id=None):
        """Create an new PavTest object. If loading an existing test instance,
        use the PavTest.from_id method.
        :param pav_cfg: The pavilion configuration.
        :param config: The test configuration dictionary.
        :param Union(dict, None) sys_vars: System variables.
        :param _id: The test id of an existing test. (You should be using
            PavTest.load).
        """

        if _id is None and sys_vars is None:
            raise RuntimeError("New PavTest objects require a sys_vars dict. ")

        # Just about every method needs this
        self._pav_cfg = pav_cfg

        # Compute the actual name of test, using the subtest config parameter.
        self.name = config['name']
        if 'subtest' in config and config['subtest']:
            self.name = self.name + '.' + config['subtest']

        self.scheduler = config['scheduler']

        # Create the tests directory if it doesn't already exist.
        tests_path = pav_cfg.working_dir / 'tests'

        self.config = config

        self.id = None  # pylint: disable=invalid-name

        # Get an id for the test, if we weren't given one.
        if _id is None:
            self.id, self.path = self.create_id_dir(tests_path)
            self._save_config()
        else:
            self.id = _id
            self.path = utils.make_id_path(tests_path, self.id)
            if not self.path.is_dir():
                raise PavTestNotFoundError(
                    "No test with id '{}' could be found.".format(self.id))

        # Set a logger more specific to this test.
        self.logger = logging.getLogger('pav.PavTest.{}'.format(self.id))

        # This will be set by the scheduler
        self._job_id = None

        # Setup the initial status file.
        self.status = StatusFile(self.path / 'status')
        if _id is None:
            self.status.set(STATES.CREATED,
                            "Test directory and status file created.")

        self._started = None
        self._finished = None

        self.build_path = None  # type: Path
        self.build_name = None
        self.build_hash = None  # type: str
        self.build_script_path = None  # type: Path
        self.build_origin = None  # type: Path
        self.run_log = self.path / 'run.log'
        self.results_path = self.path / 'results.json'

        build_config = self.config.get('build', {})

        self.build_script_path = self.path / 'build.sh'
        if not self.build_script_path.exists():
            self._write_script(self.build_script_path, build_config, sys_vars)

        self.build_path = self.path / 'build'
        if self.build_path.is_symlink():
            build_rp = self.build_path.resolve()
            self.build_hash = build_rp.name
        else:
            self.build_hash = self._create_build_hash(build_config)

        short_hash = self.build_hash[:self.BUILD_HASH_BYTES * 2]
        self.build_name = '{hash}'.format(hash=short_hash)
        self.build_origin = pav_cfg.working_dir / 'builds' / self.build_name

        run_config = self.config.get('run', {})
        if run_config:
            self.run_tmpl_path = self.path / 'run.tmpl'
            self.run_script_path = self.path / 'run.sh'
            if not self.run_tmpl_path.exists():
                self._write_script(self.run_tmpl_path, run_config, sys_vars)
        else:
            self.run_tmpl_path = None
            self.run_script_path = None

        if _id is None:
            self.status.set(STATES.CREATED, "Test directory setup complete.")
Ejemplo n.º 14
0
    def __init__(self, pav_cfg, config, test_id=None):
        """Create an new PavTest object. If loading an existing test instance,
        use the PavTest.from_id method.
        :param pav_cfg: The pavilion configuration.
        :param config: The test configuration dictionary.
        :param test_id: The test id (for an existing test).
        """

        # Just about every method needs this
        self._pav_cfg = pav_cfg

        # Compute the actual name of test, using the subtest config parameter.
        self.name = config['name']
        if 'subtest' in config and config['subtest']:
            self.name = self.name + '.' + config['subtest']

        # Create the tests directory if it doesn't already exist.
        tests_path = os.path.join(pav_cfg.working_dir, 'tests')

        self.config = config

        # Get an id for the test, if we weren't given one.
        if test_id is None:
            self.id, self.path = utils.create_id_dir(tests_path)
            self._save_config()
        else:
            self.id = test_id
            self.path = utils.make_id_path(tests_path, self.id)
            if not os.path.isdir(self.path):
                raise PavTestNotFoundError(
                    "No test with id '{}' could be found.".format(self.id))

        # Set a logger more specific to this test.
        self.LOGGER = logging.getLogger('pav.PavTest.{}'.format(self.id))

        # This will be set by the scheduler
        self._job_id = None

        # Setup the initial status file.
        self.status = StatusFile(os.path.join(self.path, 'status'))
        self.status.set(STATES.CREATED,
                        "Test directory and status file created.")

        self.build_path = None
        self.build_name = None
        self.build_hash = None
        self.build_script_path = None

        build_config = self.config.get('build', {})
        if build_config:
            self.build_path = os.path.join(self.path, 'build')
            if os.path.islink(self.build_path):
                build_rp = os.path.realpath(self.build_path)
                build_fn = os.path.basename(build_rp)
                self.build_hash = build_fn.split('-')[-1]
            else:
                self.build_hash = self._create_build_hash(build_config)

            short_hash = self.build_hash[:self.BUILD_HASH_BYTES*2]
            self.build_name = '{hash}'.format(hash=short_hash)
            self.build_origin = os.path.join(pav_cfg.working_dir,
                                             'builds', self.build_name)

            self.build_script_path = os.path.join(self.path, 'build.sh')
            self._write_script(self.build_script_path, build_config)

        run_config = self.config.get('run', {})
        if run_config:
            self.run_tmpl_path = os.path.join(self.path, 'run.tmpl')
            self.run_script_path = os.path.join(self.path, 'run.sh')
            self._write_script(self.run_tmpl_path, run_config)
        else:
            self.run_tmpl_path = None
            self.run_script_path = None

        self.status.set(STATES.CREATED, "Test directory setup complete.")
Ejemplo n.º 15
0
    def __init__(self, pav_cfg, config,
                 build_tracker=None, var_man=None, _id=None,
                 rebuild=False, build_only=False):
        """Create an new TestRun object. If loading an existing test
    instance, use the ``TestRun.from_id()`` method.

:param pav_cfg: The pavilion configuration.
:param dict config: The test configuration dictionary.
:param builder.MultiBuildTracker build_tracker: Tracker for watching
    and managing the status of multiple builds.
:param variables.VariableSetManager var_man: The variable set manager for this
    test.
:param bool build_only: Only build this test run, do not run it.
:param bool rebuild: After determining the build name, deprecate it and select
    a new, non-deprecated build.
:param int _id: The test id of an existing test. (You should be using
    TestRun.load).
"""

        # Just about every method needs this
        self._pav_cfg = pav_cfg

        self.load_ok = True

        self.scheduler = config['scheduler']

        # Create the tests directory if it doesn't already exist.
        tests_path = pav_cfg.working_dir/'test_runs'

        self.config = config

        self.id = None  # pylint: disable=invalid-name

        self._attrs = {}

        # Mark the run to build locally.
        self.build_local = config.get('build', {}) \
                                 .get('on_nodes', 'false').lower() != 'true'

        # If a test access group was given, make sure it exists and the
        # current user is a member.
        self.group = config.get('group')
        if self.group is not None:
            try:
                group_data = grp.getgrnam(self.group)
                user = utils.get_login()
                if self.group != user and user not in group_data.gr_mem:
                    raise TestConfigError(
                        "Test specified group '{}', but the current user '{}' "
                        "is not a member of that group."
                        .format(self.group, user))
            except KeyError as err:
                raise TestConfigError(
                    "Test specified group '{}', but that group does not "
                    "exist on this system. {}"
                    .format(self.group, err))

        self.umask = config.get('umask')
        if self.umask is not None:
            try:
                self.umask = int(self.umask, 8)
            except ValueError:
                raise RuntimeError(
                    "Invalid umask. This should have been enforced by the "
                    "by the config format.")

        self.build_only = build_only
        self.rebuild = rebuild

        self.suite_path = None
        if self.config.get('suite_path') is not None:
            try:
                self.suite_path = Path(self.config['suite_path'])
            except ValueError:
                pass

        # Get an id for the test, if we weren't given one.
        if _id is None:
            self.id, self.path = self.create_id_dir(tests_path)
            with PermissionsManager(self.path, self.group, self.umask):
                self._save_config()
                if var_man is None:
                    var_man = variables.VariableSetManager()
                self.var_man = var_man
                self._variables_path = self.path / 'variables'
                self.var_man.save(self._variables_path)

            self.save_attributes()
        else:
            self.id = _id
            self.path = utils.make_id_path(tests_path, self.id)
            self._variables_path = self.path / 'variables'
            if not self.path.is_dir():
                raise TestRunNotFoundError(
                    "No test with id '{}' could be found.".format(self.id))
            try:
                self.var_man = variables.VariableSetManager.load(
                    self._variables_path
                )
            except RuntimeError as err:
                raise TestRunError(*err.args)

            self.load_attributes()

        name_parts = [
            self.config.get('suite', '<unknown>'),
            self.config.get('name', '<unnamed>'),
        ]
        subtitle = self.config.get('subtitle')
        # Don't add undefined or empty subtitles.
        if subtitle:
            name_parts.append(subtitle)

        self.name = '.'.join(name_parts)

        # Set a logger more specific to this test.
        self.logger = logging.getLogger('pav.TestRun.{}'.format(self.id))

        # This will be set by the scheduler
        self._job_id = None

        with PermissionsManager(self.path/'status', self.group, self.umask):
            # Setup the initial status file.
            self.status = StatusFile(self.path/'status')
            if _id is None:
                self.status.set(STATES.CREATED,
                                "Test directory and status file created.")

        self.run_timeout = self.parse_timeout(
            'run', config.get('run', {}).get('timeout'))
        self.build_timeout = self.parse_timeout(
            'build', config.get('build', {}).get('timeout'))

        self._attributes = {}

        self.build_name = None
        self.run_log = self.path/'run.log'
        self.results_path = self.path/'results.json'
        self.build_origin_path = self.path/'build_origin'

        build_config = self.config.get('build', {})

        if (build_config.get('source_path') is None and
                build_config.get('source_url') is not None):
            raise TestConfigError(
                "Build source_url specified, but not a source_path.")

        self.build_script_path = self.path/'build.sh'  # type: Path
        self.build_path = self.path/'build'
        if _id is None:
            self._write_script(
                'build',
                path=self.build_script_path,
                config=build_config)

        build_name = None
        self._build_name_fn = self.path / 'build_name'
        if _id is not None:
            build_name = self._load_build_name()

        try:
            self.builder = builder.TestBuilder(
                pav_cfg=pav_cfg,
                test=self,
                mb_tracker=build_tracker,
                build_name=build_name
            )
        except builder.TestBuilderError as err:
            raise TestRunError(
                "Could not create builder for test {s.name} (run {s.id}): {err}"
                .format(s=self, err=err)
            )

        self.save_build_name()

        run_config = self.config.get('run', {})
        self.run_tmpl_path = self.path/'run.tmpl'
        self.run_script_path = self.path/'run.sh'

        if _id is None:
            self._write_script(
                'run',
                path=self.run_tmpl_path,
                config=run_config)

        if _id is None:
            self.status.set(STATES.CREATED, "Test directory setup complete.")

        self._results = None
        self._created = None

        self.skipped = self._get_skipped()
Ejemplo n.º 16
0
    def __init__(self,
                 pav_cfg,
                 config,
                 build_tracker=None,
                 var_man=None,
                 _id=None,
                 **options):
        """Create an new TestRun object. If loading an existing test
    instance, use the ``TestRun.from_id()`` method.

:param pav_cfg: The pavilion configuration.
:param dict config: The test configuration dictionary.
:param builder.MultiBuildTracker build_tracker: Tracker for watching
    and managing the status of multiple builds.
:param variables.VariableSetManager var_man: The variable set manager for this
    test.
:param bool build_only: Only build this test run, do not run it.
:param bool rebuild: After determining the build name, deprecate it and select
    a new, non-deprecated build.
:param int _id: The test id of an existing test. (You should be using
    TestRun.load).
"""

        # Just about every method needs this
        self._pav_cfg = pav_cfg

        self.load_ok = True

        # Compute the actual name of test, using the subtitle config parameter.
        self.name = '.'.join([
            config.get('suite', '<unknown>'),
            config.get('name', '<unnamed>')
        ])
        if 'subtitle' in config and config['subtitle']:
            self.name = self.name + '.' + config['subtitle']

        self.scheduler = config['scheduler']

        # Create the tests directory if it doesn't already exist.
        tests_path = pav_cfg.working_dir / 'test_runs'

        self.config = config

        self.id = None  # pylint: disable=invalid-name

        # Mark the run to build locally.
        self.build_local = config.get('build', {}) \
                                 .get('on_nodes', 'false').lower() != 'true'

        # Get an id for the test, if we weren't given one.
        if _id is None:
            self.id, self.path = self.create_id_dir(tests_path)
            self._save_config()
            if var_man is None:
                var_man = variables.VariableSetManager()
            self.var_man = var_man
            self._variables_path = self.path / 'variables'
            self.var_man.save(self._variables_path)
            self.opts = TestRunOptions(**options)
            self.opts.save(self)
        else:
            self.id = _id
            self.path = utils.make_id_path(tests_path, self.id)
            self._variables_path = self.path / 'variables'
            if not self.path.is_dir():
                raise TestRunNotFoundError(
                    "No test with id '{}' could be found.".format(self.id))
            try:
                self.var_man = variables.VariableSetManager.load(
                    self._variables_path)
            except RuntimeError as err:
                raise TestRunError(*err.args)

            self.opts = TestRunOptions.load(self)

        # Set a logger more specific to this test.
        self.logger = logging.getLogger('pav.TestRun.{}'.format(self.id))

        # This will be set by the scheduler
        self._job_id = None

        # Setup the initial status file.
        self.status = StatusFile(self.path / 'status')
        if _id is None:
            self.status.set(STATES.CREATED,
                            "Test directory and status file created.")

        self.run_timeout = self.parse_timeout(
            'run',
            config.get('run', {}).get('timeout'))
        self.build_timeout = self.parse_timeout(
            'build',
            config.get('build', {}).get('timeout'))

        self._started = None
        self._finished = None

        self.build_name = None
        self.run_log = self.path / 'run.log'
        self.results_path = self.path / 'results.json'
        self.build_origin_path = self.path / 'build_origin'

        build_config = self.config.get('build', {})

        # make sure build source_download_name is not set without
        # source_location
        try:
            if build_config['source_download_name'] is not None:
                if build_config['source_location'] is None:
                    msg = "Test could not be built. Need 'source_location'."
                    self.status.set(
                        STATES.BUILD_ERROR,
                        "'source_download_name is set without a "
                        "'source_location'")
                    raise TestConfigError(msg)
        except KeyError:
            # this is mostly for unit tests that create test configs without a
            # build section at all
            pass

        self.build_script_path = self.path / 'build.sh'  # type: Path
        self.build_path = self.path / 'build'
        if _id is None:
            self._write_script('build',
                               path=self.build_script_path,
                               config=build_config)

        build_name = None
        self._build_name_fn = self.path / 'build_name'
        if _id is not None:
            build_name = self._load_build_name()

        try:
            self.builder = builder.TestBuilder(pav_cfg=pav_cfg,
                                               test=self,
                                               mb_tracker=build_tracker,
                                               build_name=build_name)
        except builder.TestBuilderError as err:
            raise TestRunError(
                "Could not create builder for test {s.name} (run {s.id}): {err}"
                .format(s=self, err=err))

        self.save_build_name()

        run_config = self.config.get('run', {})
        self.run_tmpl_path = self.path / 'run.tmpl'
        self.run_script_path = self.path / 'run.sh'

        if _id is None:
            self._write_script('run',
                               path=self.run_tmpl_path,
                               config=run_config)

        if _id is None:
            self.status.set(STATES.CREATED, "Test directory setup complete.")

        self._results = None
        self._created = None