Пример #1
0
class TestBuildApiGetJobStatus(unittest.TestCase):
    """Test query_job_status with different types of jobs."""
    def setUp(self):
        self.query_api = BuildApi()

    def test_pending_job(self):
        """Test get_job_status with a pending job."""
        pending_job = json.loads(BASE_JSON %
                                 ('null', 'null', 0, 1433166609))[0]
        pending_job.pop("status")
        self.assertEquals(self.query_api.get_job_status(pending_job), PENDING)

    def test_running_job(self):
        """Test get_job_status with a running job."""
        running_job = json.loads(BASE_JSON % ('null', 'null', 0, 'null'))[0]
        self.assertEquals(self.query_api.get_job_status(running_job), RUNNING)

    def test_unknown_job(self):
        """Test get_job_status with an unknown job."""
        unknown_job = json.loads(BASE_JSON %
                                 ('null', 'null', 0, 1433166609))[0]
        self.assertEquals(self.query_api.get_job_status(unknown_job), UNKNOWN)

    @patch('mozci.query_jobs.BuildApi._is_coalesced', return_value=SUCCESS)
    def test_successful_job(self, _is_coalesced):
        """Test get_job_status with a successful job. We will mock _is_coalesced for that."""
        successful_job = json.loads(BASE_JSON %
                                    (SUCCESS, 1433166610, 1, 1433166609))[0]
        self.assertEquals(self.query_api.get_job_status(successful_job),
                          SUCCESS)

    @patch('mozci.query_jobs.BuildApi._is_coalesced', return_value=COALESCED)
    def test_coalesced_job(self, _is_coalesced):
        """Test get_job_status with a coalesced job. We will mock _is_coalesced for that."""
        coalesced_job = json.loads(BASE_JSON %
                                   (SUCCESS, 1433166610, 1, 1433166609))[0]
        self.assertEquals(self.query_api.get_job_status(coalesced_job),
                          COALESCED)

    def test_failed_job(self):
        """Test get_job_status with a failed job."""
        failed_job = json.loads(BASE_JSON %
                                (FAILURE, 1433166610, 1, 1433166609))[0]
        self.assertEquals(self.query_api.get_job_status(failed_job), FAILURE)

    def test_weird_job(self):
        """get_job_status should raise an Exception when it encounters an unexpected status."""
        weird_job = json.loads(BASE_JSON % (20, 1433166610, 1, 1433166609))[0]
        with self.assertRaises(Exception):
            self.query_api.get_job_status(weird_job)
Пример #2
0
class TestBuildApiGetJobStatus(unittest.TestCase):
    """Test query_job_status with different types of jobs."""

    def setUp(self):
        self.query_api = BuildApi()

    def test_pending_job(self):
        """Test get_job_status with a pending job."""
        pending_job = json.loads(BASE_JSON % ('null', 'null', 0, 1433166609))[0]
        pending_job.pop("status")
        self.assertEquals(self.query_api.get_job_status(pending_job), PENDING)

    def test_running_job(self):
        """Test get_job_status with a running job."""
        running_job = json.loads(BASE_JSON % ('null', 'null', 0, 'null'))[0]
        self.assertEquals(self.query_api.get_job_status(running_job), RUNNING)

    def test_unknown_job(self):
        """Test get_job_status with an unknown job."""
        unknown_job = json.loads(BASE_JSON % ('null', 'null', 0, 1433166609))[0]
        self.assertEquals(self.query_api.get_job_status(unknown_job), UNKNOWN)

    @patch('mozci.query_jobs.BuildApi._is_coalesced', return_value=SUCCESS)
    def test_successful_job(self, _is_coalesced):
        """Test get_job_status with a successful job. We will mock _is_coalesced for that."""
        successful_job = json.loads(BASE_JSON % (SUCCESS, 1433166610, 1, 1433166609))[0]
        self.assertEquals(self.query_api.get_job_status(successful_job), SUCCESS)

    @patch('mozci.query_jobs.BuildApi._is_coalesced', return_value=COALESCED)
    def test_coalesced_job(self, _is_coalesced):
        """Test get_job_status with a coalesced job. We will mock _is_coalesced for that."""
        coalesced_job = json.loads(BASE_JSON % (SUCCESS, 1433166610, 1, 1433166609))[0]
        self.assertEquals(self.query_api.get_job_status(coalesced_job), COALESCED)

    def test_failed_job(self):
        """Test get_job_status with a failed job."""
        failed_job = json.loads(BASE_JSON % (FAILURE, 1433166610, 1, 1433166609))[0]
        self.assertEquals(self.query_api.get_job_status(failed_job), FAILURE)

    def test_weird_job(self):
        """get_job_status should raise an Exception when it encounters an unexpected status."""
        weird_job = json.loads(BASE_JSON % (20, 1433166610, 1, 1433166609))[0]
        with self.assertRaises(Exception):
            self.query_api.get_job_status(weird_job)
Пример #3
0
def determine_trigger_objective(revision,
                                buildername,
                                trigger_build_if_missing=True):
    """
    Determine if we need to trigger any jobs and which job.

    Returns:

    * The name of the builder we need to trigger
    * Files, if needed, to trigger such builder
    """
    builder_to_trigger = None
    files = None
    repo_name = query_repo_name_from_buildername(buildername)

    build_buildername = determine_upstream_builder(buildername)

    if VALIDATE and not valid_builder(build_buildername):
        raise MozciError("Our platforms mapping system has failed.")

    if build_buildername == buildername:
        # For a build job we know that we don't need files to
        # trigger it and it's the build job we want to trigger
        return build_buildername, None

    # Let's figure out which jobs are associated to such revision
    query_api = BuildApi()
    # Let's only look at jobs that match such build_buildername
    build_jobs = query_api.get_matching_jobs(repo_name, revision,
                                             build_buildername)

    # We need to determine if we need to trigger a build job
    # or the test job
    working_job = None
    running_job = None
    failed_job = None

    LOG.debug("List of matching jobs:")
    for job in build_jobs:
        try:
            status = query_api.get_job_status(job)
        except buildjson.BuildjsonException:
            LOG.debug(
                "We have hit bug 1159279 and have to work around it. We will "
                "pretend that we could not reach the files for it.")
            continue

        # Sometimes running jobs have status unknown in buildapi
        if status in (RUNNING, PENDING, UNKNOWN):
            LOG.debug(
                "We found a running/pending build job. We don't search anymore."
            )
            running_job = job
            # We cannot call _find_files for a running job
            continue

        # Having a coalesced build is the same as not having a build available
        if status == COALESCED:
            LOG.debug(
                "The build we found was a coalesced one; this is the same as "
                "non-existant.")
            continue

        # Successful or failed jobs may have the files we need
        files = _find_files(job)

        if files != [] and _all_urls_reachable(files.values()):
            working_job = job
            break
        else:
            LOG.debug("We can't determine the files for this build or "
                      "can't reach them.")
            files = None

        LOG.info("We found a job that finished but it did not "
                 "produced files. status: %d" % status)
        failed_job = job
    # End of for loop

    if working_job:
        # We found a build job with the necessary files. It could be a
        # successful job, a running job that already emitted files or a
        # testfailed job
        LOG.debug(str(working_job))
        LOG.info("We have the necessary files to trigger the downstream job.")
        # We have the files needed to trigger the test job
        builder_to_trigger = buildername

    elif running_job:
        LOG.info(
            "We found a running/pending build job. We will not trigger another one."
        )
        LOG.info(
            "You have to run the script again after the build job is finished to "
            "trigger %s." % buildername)
        builder_to_trigger = None

    elif failed_job:
        LOG.info(
            "The build job %s failed on revision %s without generating the "
            "necessary files. We will not trigger anything." %
            (build_buildername, revision))
        builder_to_trigger = None

    else:
        # We were trying to build a test job, however, we determined
        # that we need an upstream builder instead
        if not trigger_build_if_missing or not _unique_build_request(
                build_buildername, revision):
            # This is a safeguard to prevent triggering a build
            # job multiple times if it is not intentional
            builder_to_trigger = None
            if not trigger_build_if_missing:
                LOG.info(
                    "We would have to triggered build '%s' in order to trigger "
                    "job '%s'. On this mode we will not trigger either." %
                    (build_buildername, buildername))
        else:
            LOG.info("We will trigger 1) "
                     "'%s' instead of 2) '%s'" %
                     (build_buildername, buildername))
            LOG.info("We need to trigger the build job once (1) "
                     "in order to be able to run the test job (2).")
            if repo_name == 'try':
                LOG.info(
                    "You'll need to run the script again after (1) is done to "
                    "trigger (2).")
            else:
                LOG.info(
                    "After (1) is done and if no coalesccing happens the test "
                    "jobs associated with it will be triggered.")
            builder_to_trigger = build_buildername

    if files:
        return builder_to_trigger, files['packageUrl'], files[
            'testPackagesUrl']
    else:
        return builder_to_trigger, None, None
def determine_trigger_objective(revision, buildername, trigger_build_if_missing=True,
                                will_use_buildapi=False):
    """
    Determine if we need to trigger any jobs and which job.

    Returns:

    * The name of the builder we need to trigger
    * Files, if needed, to trigger such builder
    """
    builder_to_trigger = None
    files = None
    repo_name = query_repo_name_from_buildername(buildername)

    build_buildername = determine_upstream_builder(buildername)

    if VALIDATE and not valid_builder(build_buildername):
        raise MozciError("Our platforms mapping system has failed.")

    if build_buildername == buildername:
        # For a build job we know that we don't need files to
        # trigger it and it's the build job we want to trigger
        return build_buildername, None, None

    # Let's figure out which jobs are associated to such revision
    query_api = BuildApi()
    # Let's only look at jobs that match such build_buildername
    build_jobs = query_api.get_matching_jobs(repo_name, revision, build_buildername)

    # We need to determine if we need to trigger a build job
    # or the test job
    working_job = None
    running_job = None
    failed_job = None

    LOG.debug("List of matching jobs:")
    for job in build_jobs:
        try:
            status = query_api.get_job_status(job)
        except buildjson.BuildjsonException:
            LOG.debug("We have hit bug 1159279 and have to work around it. We will "
                      "pretend that we could not reach the files for it.")
            continue

        # Sometimes running jobs have status unknown in buildapi
        if status in (RUNNING, PENDING, UNKNOWN):
            LOG.debug("We found a running/pending build job. We don't search anymore.")
            running_job = job
            # We cannot call _find_files for a running job
            continue

        # Having a coalesced build is the same as not having a build available
        if status == COALESCED:
            LOG.debug("The build we found was a coalesced one; this is the same as "
                      "non-existant.")
            continue

        # Successful or failed jobs may have the files we need
        files = _find_files(job)

        if files != [] and _all_urls_reachable(files.values()):
            working_job = job
            break
        else:
            LOG.debug("We can't determine the files for this build or "
                      "can't reach them.")
            files = None

        LOG.info("We found a job that finished but it did not "
                 "produced files. status: %d" % status)
        failed_job = job
    # End of for loop

    if working_job:
        # We found a build job with the necessary files. It could be a
        # successful job, a running job that already emitted files or a
        # testfailed job
        LOG.debug(str(working_job))
        LOG.info("We have the necessary files to trigger the downstream job.")
        # We have the files needed to trigger the test job
        builder_to_trigger = buildername

    elif running_job:
        LOG.info("We found a running/pending build job. We will not trigger another one.")
        LOG.info("You have to run the script again after the build job is finished to "
                 "trigger %s." % buildername)
        builder_to_trigger = None

    elif failed_job:
        LOG.info("The build job %s failed on revision %s without generating the "
                 "necessary files. We will not trigger anything." %
                 (build_buildername, revision))
        builder_to_trigger = None

    else:
        # We were trying to build a test job, however, we determined
        # that we need an upstream builder instead
        if not trigger_build_if_missing or not _unique_build_request(build_buildername, revision):
            # This is a safeguard to prevent triggering a build
            # job multiple times if it is not intentional
            builder_to_trigger = None
            if not trigger_build_if_missing:
                LOG.info("We would have to triggered build '%s' in order to trigger "
                         "job '%s'. On this mode we will not trigger either." %
                         (build_buildername, buildername))
        else:
            if will_use_buildapi:
                LOG.info("We will trigger 1) '%s'" % build_buildername)
                LOG.info("instead of 2) '%s'" % buildername)
                LOG.info("We need to trigger the build job once (1) "
                         "in order to be able to run the test job (2).")
                if repo_name == 'try':
                    LOG.info("You'll need to run the script again after (1) is done to "
                             "trigger (2).")
                else:
                    LOG.info("After (1) is done and if no coalesccing happens the test "
                             "jobs associated with it will be triggered.")
            builder_to_trigger = build_buildername

    if files:
        return builder_to_trigger, files['packageUrl'], files['testsUrl']
    else:
        return builder_to_trigger, None, None