Exemple #1
0
    def __init__(self, cache_root):
        # Create message bus shared amongst processes
        self.bus = MessageBus()

        self.workflow = CodeReview(
            api_key=taskcluster_config.secrets["PHABRICATOR"]["api_key"],
            url=taskcluster_config.secrets["PHABRICATOR"]["url"],
            publish=taskcluster_config.secrets["PHABRICATOR"].get(
                "publish", False),
            risk_analysis_reviewers=taskcluster_config.secrets.get(
                "risk_analysis_reviewers", []),
            community_config=taskcluster_config.secrets.get(
                "taskcluster_community"),
        )
        self.workflow.register(self.bus)

        # Build mercurial worker and queue
        self.mercurial = MercurialWorker(
            QUEUE_MERCURIAL,
            QUEUE_PHABRICATOR_RESULTS,
            repositories=self.workflow.get_repositories(
                taskcluster_config.secrets["repositories"], cache_root),
        )
        self.mercurial.register(self.bus)

        # Create web server
        self.webserver = WebServer(QUEUE_WEB_BUILDS)
        self.webserver.register(self.bus)

        # Setup monitoring for newly created tasks
        self.monitoring = Monitoring(QUEUE_MONITORING,
                                     taskcluster_config.secrets["admins"],
                                     MONITORING_PERIOD)
        self.monitoring.register(self.bus)
Exemple #2
0
async def test_start_test_selection(PhabricatorMock, mock_taskcluster):
    bus = MessageBus()
    bus.add_queue(QUEUE_MONITORING_COMMUNITY)

    build = PhabricatorBuild(
        MockRequest(
            diff="125397",
            repo="PHID-REPO-saax4qdxlbbhahhp2kg5",
            revision="36474",
            target="PHID-HMBT-icusvlfibcebizyd33op",
        ))

    taskcluster_config.secrets["test_selection_enabled"] = True
    taskcluster_config.secrets["test_selection_share"] = 1.0

    with PhabricatorMock as phab:
        phab.load_patches_stack(build)
        phab.update_state(build)
        phab.load_reviewers(build)

        bugbug_utils = BugbugUtils(phab.api)
        bugbug_utils.register(bus)

    with responses.RequestsMock(assert_all_requests_are_fired=True) as rsps:

        def trigger_hook_callback(request):
            payload = json.loads(request.body)
            assert payload == {
                "DIFF_ID":
                125397,
                "PHABRICATOR_DEPLOYMENT":
                "prod",
                "RUNNABLE_JOBS":
                "http://taskcluster.test/api/index/v1/task/gecko.v2.try.revision.MyRevision.firefox.decision/artifacts/public%2Frunnable-jobs.json",
            }
            return (
                200,
                {
                    "Content-Type": "application/json"
                },
                json.dumps({"status": {
                    "taskId": "xxx"
                }}),
            )

        rsps.add_callback(
            responses.POST,
            "http://community_taskcluster.test/api/hooks/v1/hooks/project-relman/bugbug-test-select/trigger",
            callback=trigger_hook_callback,
        )

        await bugbug_utils.start_test_selection(build, "MyRevision")

        group_id, hook_id, task_id = await bus.receive(
            QUEUE_MONITORING_COMMUNITY)
        assert group_id == "project-relman"
        assert hook_id == "bugbug-test-select"
        assert task_id == "xxx"
async def test_failure_general(PhabricatorMock, mock_mc):
    """
    Run mercurial worker on a single diff
    and check the treeherder link publication as an artifact
    Use a Python common exception to trigger a broken build
    """
    diff = {
        "phid": "PHID-DIFF-test123",
        "id": 1234,
        "baseRevision": None,
        "revisionPHID": "PHID-DREV-deadbeef",
    }
    build = MockBuild(1234, "PHID-REPO-mc", 5678, "PHID-somehash", diff)
    with PhabricatorMock as phab:
        phab.load_patches_stack(build)

    bus = MessageBus()
    bus.add_queue("phabricator")

    # Get initial tip commit in repo
    initial = mock_mc.repo.tip()

    # The patched and config files should not exist at first
    repo_dir = mock_mc.repo.root().decode("utf-8")
    config = os.path.join(repo_dir, "try_task_config.json")
    target = os.path.join(repo_dir, "test.txt")
    assert not os.path.exists(target)
    assert not os.path.exists(config)

    # Raise an exception during the workflow to trigger a broken build
    def boom(*args):
        raise Exception("Boom")

    mock_mc.apply_build = boom

    worker = MercurialWorker(
        "mercurial", "phabricator", repositories={"PHID-REPO-mc": mock_mc}
    )
    worker.register(bus)
    assert len(worker.repositories) == 1

    await bus.send("mercurial", build)
    assert bus.queues["mercurial"].qsize() == 1
    task = asyncio.create_task(worker.run())

    # Check the unit result was published
    mode, out_build, details = await bus.receive("phabricator")
    assert mode == "fail:general"
    assert out_build == build
    assert details["duration"] > 0
    assert details["message"] == "Boom"
    task.cancel()

    # Clone should not be modified
    tip = mock_mc.repo.tip()
    assert tip.node == initial.node
async def test_treeherder_link(PhabricatorMock, mock_mc):
    """
    Run mercurial worker on a single diff
    and check the treeherder link publication as an artifact
    """
    # Preload the build
    diff = {
        "phid": "PHID-DIFF-test123",
        "revisionPHID": "PHID-DREV-deadbeef",
        "id": 1234,
        "baseRevision": "abcdef12345",
    }
    build = MockBuild(1234, "PHID-REPO-mc", 5678, "PHID-HMBT-somehash", diff)
    with PhabricatorMock as phab:
        phab.load_patches_stack(build)

    bus = MessageBus()
    bus.add_queue("phabricator")

    # Get initial tip commit in repo
    initial = mock_mc.repo.tip()

    # The patched and config files should not exist at first
    repo_dir = mock_mc.repo.root().decode("utf-8")
    config = os.path.join(repo_dir, "try_task_config.json")
    target = os.path.join(repo_dir, "test.txt")
    assert not os.path.exists(target)
    assert not os.path.exists(config)

    worker = MercurialWorker(
        "mercurial", "phabricator", repositories={"PHID-REPO-mc": mock_mc}
    )
    worker.register(bus)
    assert len(worker.repositories) == 1

    await bus.send("mercurial", build)
    assert bus.queues["mercurial"].qsize() == 1
    task = asyncio.create_task(worker.run())

    # Check the treeherder link was queued
    mode, out_build, details = await bus.receive("phabricator")
    tip = mock_mc.repo.tip()
    assert mode == "success"
    assert out_build == build
    assert details[
        "treeherder_url"
    ] == "https://treeherder.mozilla.org/#/jobs?repo=try&revision={}".format(
        tip.node.decode("utf-8")
    )
    assert details["revision"] == tip.node.decode("utf-8")
    task.cancel()

    # Tip should be updated
    assert tip.node != initial.node
async def test_failure_mercurial(PhabricatorMock, mock_mc):
    """
    Run mercurial worker on a single diff
    and check the treeherder link publication as an artifact
    Apply a bad mercurial patch to trigger a mercurial fail
    """
    diff = {
        "revisionPHID": "PHID-DREV-666",
        "baseRevision": "missing",
        "phid": "PHID-DIFF-666",
        "id": 666,
    }
    build = MockBuild(1234, "PHID-REPO-mc", 5678, "PHID-build-666", diff)
    with PhabricatorMock as phab:
        phab.load_patches_stack(build)

    bus = MessageBus()
    bus.add_queue("phabricator")

    # Get initial tip commit in repo
    initial = mock_mc.repo.tip()

    # The patched and config files should not exist at first
    repo_dir = mock_mc.repo.root().decode("utf-8")
    config = os.path.join(repo_dir, "try_task_config.json")
    target = os.path.join(repo_dir, "test.txt")
    assert not os.path.exists(target)
    assert not os.path.exists(config)

    worker = MercurialWorker(
        "mercurial", "phabricator", repositories={"PHID-REPO-mc": mock_mc}
    )
    worker.register(bus)
    assert len(worker.repositories) == 1

    await bus.send("mercurial", build)
    assert bus.queues["mercurial"].qsize() == 1
    task = asyncio.create_task(worker.run())

    # Check the treeherder link was queued
    mode, out_build, details = await bus.receive("phabricator")
    assert mode == "fail:mercurial"
    assert out_build == build
    assert details["duration"] > 0
    assert details["message"] == MERCURIAL_FAILURE
    task.cancel()

    # Clone should not be modified
    tip = mock_mc.repo.tip()
    assert tip.node == initial.node
Exemple #6
0
async def test_publish_results_success_mode(PhabricatorMock, mock_taskcluster):
    bus = MessageBus()
    build = PhabricatorBuild(
        MockRequest(
            diff="125397",
            repo="PHID-REPO-saax4qdxlbbhahhp2kg5",
            revision="36474",
            target="PHID-HMBT-icusvlfibcebizyd33op",
        )
    )

    with PhabricatorMock as phab:
        client = CodeReview(
            publish=True, url="http://phabricator.test/api/", api_key="fakekey"
        )
        client.register(bus)

        phab.update_state(build)

        await client.publish_results(
            (
                "success",
                build,
                {"treeherder_url": "https://treeherder.org/", "revision": "123"},
            )
        )
Exemple #7
0
    def __init__(self):
        # Create message bus shared amongst process
        self.bus = MessageBus()

        # Build code coverage workflow
        self.workflow = CodeCoverage(
            taskcluster_config.secrets["hook_id"],
            taskcluster_config.secrets["hook_group_id"],
            self.bus,
        )

        # Setup monitoring for newly created tasks
        self.monitoring = Monitoring(
            taskcluster_config,
            QUEUE_MONITORING,
            taskcluster_config.secrets["admins"],
            7 * 3600,
        )
        self.monitoring.register(self.bus)

        # Create pulse listener for code coverage
        self.pulse = PulseListener(
            {
                QUEUE_PULSE: [
                    ("exchange/taskcluster-queue/v1/task-group-resolved", ["#"])
                ]
            },
            taskcluster_config.secrets["pulse_user"],
            taskcluster_config.secrets["pulse_password"],
        )
        self.pulse.register(self.bus)
def test_is_coverage_task(mock_taskcluster):
    bus = MessageBus()
    hook = CodeCoverage("services-staging-codecoverage/bot", "project-test",
                        bus)

    cov_task = {"task": {"metadata": {"name": "build-linux64-ccov"}}}
    assert hook.is_coverage_task(cov_task)

    cov_task = {"task": {"metadata": {"name": "build-linux1804-64-ccov"}}}
    assert hook.is_coverage_task(cov_task)

    cov_task = {"task": {"metadata": {"name": "build-linux64-ccov/opt"}}}
    assert hook.is_coverage_task(cov_task)

    cov_task = {"task": {"metadata": {"name": "build-win64-ccov/debug"}}}
    assert hook.is_coverage_task(cov_task)

    nocov_task = {
        "task": {
            "metadata": {
                "name": "test-linux64-ccov/opt-mochitest-1"
            }
        }
    }
    assert hook.is_coverage_task(nocov_task)

    nocov_task = {
        "task": {
            "metadata": {
                "name": "test-linux64/opt-mochitest-1"
            }
        }
    }
    assert not hook.is_coverage_task(nocov_task)
Exemple #9
0
async def test_risk_analysis_shouldnt_trigger(PhabricatorMock,
                                              mock_taskcluster):
    bus = MessageBus()
    build = PhabricatorBuild(
        MockRequest(
            diff="125397",
            repo="PHID-REPO-saax4qdxlbbhahhp2kg5",
            revision="36474",
            target="PHID-HMBT-icusvlfibcebizyd33op",
        ))

    with PhabricatorMock as phab:
        client = CodeReview(
            risk_analysis_reviewers=["ehsan"],
            url="http://phabricator.test/api/",
            api_key="fakekey",
            community_config={
                "client_id": "xxx",
                "access_token": "yyy"
            },
        )
        client.register(bus)

        phab.update_state(build)
        phab.load_reviewers(build)

    assert not client.should_run_risk_analysis(build)
Exemple #10
0
async def test_blacklist(PhabricatorMock, mock_taskcluster):
    bus = MessageBus()
    build = PhabricatorBuild(
        MockRequest(
            diff="123456",
            repo="PHID-REPO-saax4qdxlbbhahhp2kg5",
            revision="98765",
            target="PHID-HMBT-icusvlfibcebizyd33op",
        )
    )

    with PhabricatorMock as phab:
        client = CodeReview(
            user_blacklist=["baduser123"],
            url="http://phabricator.test/api/",
            api_key="fakekey",
        )
        client.register(bus)

        assert client.user_blacklist == {"PHID-USER-baduser123": "baduser123"}

        phab.update_state(build)

        assert build.revision["fields"]["authorPHID"] == "PHID-USER-baduser123"

    assert client.is_blacklisted(build.revision)
def test_wrong_branch(mock_taskcluster):
    bus = MessageBus()
    hook = CodeCoverage("services-staging-codecoverage/bot", "project-test",
                        bus)

    assert run_async_parser(hook, "bNq-VIT-Q12o6nXcaUmYNQ",
                            "gecko-level-1") is None
Exemple #12
0
async def test_risk_analysis_should_trigger(PhabricatorMock, mock_taskcluster):
    bus = MessageBus()
    build = PhabricatorBuild(
        MockRequest(
            diff="125397",
            repo="PHID-REPO-saax4qdxlbbhahhp2kg5",
            revision="36474",
            target="PHID-HMBT-icusvlfibcebizyd33op",
        ))

    with PhabricatorMock as phab:
        phab.load_patches_stack(build)
        phab.update_state(build)

        # Reviewer of the patch is in the list of risk analysis users.
        taskcluster_config.secrets["risk_analysis_users"] = ["ehsan", "heycam"]

        bugbug_utils = BugbugUtils(phab.api)
        bugbug_utils.register(bus)

        assert bugbug_utils.should_run_risk_analysis(build)

        # Author of the patch is in the list of risk analysis users.
        taskcluster_config.secrets["risk_analysis_users"] = [
            "ehsan", "tnguyen"
        ]

        bugbug_utils = BugbugUtils(phab.api)

        assert bugbug_utils.should_run_risk_analysis(build)
Exemple #13
0
async def test_monitoring_retry_exceptions(QueueMock, NotifyMock,
                                           mock_taskcluster):
    bus = MessageBus()
    monitoring = Monitoring(mock_taskcluster, "testqueue", ["pinco@pallino"],
                            1)
    monitoring.register(bus)
    await bus.send("testqueue", ("Group1", "Hook1", "Task-exception-retry:2"))
    await bus.send("testqueue", ("Group1", "Hook2", "Task-exception-retry:0"))
    assert bus.queues["testqueue"].qsize() == 2

    monitoring.queue = QueueMock
    assert len(monitoring.queue.created_tasks) == 0
    monitoring.notify = NotifyMock

    # Task exception with 2 retries
    await monitoring.check_task()
    assert monitoring.stats["Hook1"]["exception"] == ["Task-exception-retry:2"]
    assert len(monitoring.queue.created_tasks) == 1
    assert bus.queues["testqueue"].qsize() == 2

    # The retried task should maintain the original taskGroupId
    old_task = await monitoring.queue.task("Task-exception-retry:2")
    new_task_id, new_task = monitoring.queue.created_tasks[0]
    assert new_task_id != "Task-exception-retry:2"
    assert new_task != old_task
    assert new_task["taskGroupId"] == old_task["taskGroupId"]
    assert new_task["payload"] == old_task["payload"]
    assert new_task["created"] != old_task["created"]

    # Task exception with 0 retries
    # No new task should be created
    await monitoring.check_task()
    assert monitoring.stats["Hook2"]["exception"] == ["Task-exception-retry:0"]
    assert len(monitoring.queue.created_tasks) == 1
    assert bus.queues["testqueue"].qsize() == 1
Exemple #14
0
    def __init__(self, cache_root):
        # Create message bus shared amongst processes
        self.bus = MessageBus()

        self.workflow = CodeReview(
            api_key=taskcluster_config.secrets["PHABRICATOR"]["api_key"],
            url=taskcluster_config.secrets["PHABRICATOR"]["url"],
            publish=taskcluster_config.secrets["PHABRICATOR"].get(
                "publish", False),
            risk_analysis_reviewers=taskcluster_config.secrets.get(
                "risk_analysis_reviewers", []),
            community_config=taskcluster_config.secrets.get(
                "taskcluster_community"),
            user_blacklist=taskcluster_config.secrets["user_blacklist"],
        )
        self.workflow.register(self.bus)

        # Build mercurial worker and queue
        self.mercurial = MercurialWorker(
            QUEUE_MERCURIAL,
            QUEUE_PHABRICATOR_RESULTS,
            repositories=self.workflow.get_repositories(
                taskcluster_config.secrets["repositories"], cache_root),
        )
        self.mercurial.register(self.bus)

        # Create web server
        self.webserver = WebServer(QUEUE_WEB_BUILDS)
        self.webserver.register(self.bus)

        # Setup monitoring for newly created tasks
        self.monitoring = Monitoring(QUEUE_MONITORING,
                                     taskcluster_config.secrets["admins"],
                                     MONITORING_PERIOD)
        self.monitoring.register(self.bus)

        # Create pulse listener for unit test failures
        if self.workflow.publish:
            self.pulse = PulseListener(
                QUEUE_PULSE,
                "exchange/taskcluster-queue/v1/task-completed",
                "*.*.gecko-level-3._",
                taskcluster_config.secrets["pulse_user"],
                taskcluster_config.secrets["pulse_password"],
            )
            self.pulse.register(self.bus)
Exemple #15
0
async def test_conversion():
    """
    Test message conversion between 2 queues
    """
    bus = MessageBus()
    bus.add_queue("input")
    bus.add_queue(
        "output",
        maxsize=3)  # limit size to immediately stop execution for unit test
    assert isinstance(bus.queues["input"], asyncio.Queue)
    assert isinstance(bus.queues["output"], asyncio.Queue)
    assert bus.queues["input"].qsize() == 0
    assert bus.queues["output"].qsize() == 0

    await bus.send("input", "test x")
    await bus.send("input", "hello world.")
    await bus.send("output", "lowercase")

    # Convert all strings from input in uppercase
    assert bus.queues["input"].qsize() == 2
    task = asyncio.create_task(
        bus.run(lambda x: x.upper(), "input", ["output"]))

    await bus.receive("output") == "lowercase"
    await bus.receive("output") == "TEST X"
    await bus.receive("output") == "HELLO WORLD."
    task.cancel()
    assert bus.queues["input"].qsize() == 0
    assert bus.queues["output"].qsize() == 0
Exemple #16
0
async def test_dispatch():
    """
    Test message dispatch from a queue to 2 queues
    """
    bus = MessageBus()
    bus.add_queue("input")
    # limit size to immediately stop execution for unit test
    bus.add_queue("output1", maxsize=3)
    bus.add_queue("output2", maxsize=3)
    assert isinstance(bus.queues["input"], asyncio.Queue)
    assert isinstance(bus.queues["output1"], asyncio.Queue)
    assert isinstance(bus.queues["output2"], asyncio.Queue)
    assert bus.queues["input"].qsize() == 0
    assert bus.queues["output1"].qsize() == 0
    assert bus.queues["output2"].qsize() == 0

    await bus.send("input", 1)
    await bus.send("input", 2)

    # Convert all strings from input in uppercase
    assert bus.queues["input"].qsize() == 2
    task = asyncio.create_task(bus.dispatch("input", ["output1", "output2"]))

    await bus.receive("output1") == 1
    await bus.receive("output2") == 1
    await bus.receive("output1") == 2
    await bus.receive("output2") == 2
    task.cancel()
    assert bus.queues["input"].qsize() == 0
    assert bus.queues["output1"].qsize() == 0
    assert bus.queues["output2"].qsize() == 0
async def test_get_coverage_task_in_group(mock_taskcluster):
    bus = MessageBus()
    hook = CodeCoverage("services-staging-codecoverage/bot", "project-test",
                        bus)

    hook.triggered_groups.add("already-triggered-group")

    assert await hook.get_coverage_task_in_group("already-triggered-group"
                                                 ) is None
def test_hook_group(mock_taskcluster):
    bus = MessageBus()
    hook = CodeCoverage("services-staging-codecoverage/bot", "project-test",
                        bus)
    assert hook.group_id == "project-test"
    assert hook.hook_id == "services-staging-codecoverage/bot"

    hook = CodeCoverage("anotherHook", "anotherProject", bus)
    assert hook.group_id == "anotherProject"
    assert hook.hook_id == "anotherHook"
Exemple #19
0
async def test_message_passing_mp():
    """
    Test sending & receiving messages on a multiprocessing queueu
    """
    bus = MessageBus()
    bus.add_queue("test", mp=True)
    assert isinstance(bus.queues["test"], multiprocessing.queues.Queue)

    await bus.send("test", {"payload": 1234})
    await bus.send("test", {"another": "deadbeef"})
    await bus.send("test", "covfefe")
    assert bus.queues["test"].qsize() == 3

    msg = await bus.receive("test")
    assert msg == {"payload": 1234}
    msg = await bus.receive("test")
    assert msg == {"another": "deadbeef"}
    msg = await bus.receive("test")
    assert msg == "covfefe"
    assert bus.queues["test"].qsize() == 0
async def test_parse(mock_taskcluster):
    bus = MessageBus()
    hook = CodeCoverage("services-staging-codecoverage/bot", "project-test",
                        bus)

    hook.triggered_groups.add("already-triggered-group")

    assert (await hook.parse({
        "schedulerId": "gecko-level-1",
        "taskGroupId": "already-triggered-group"
    }) is None)
def test_success_windows(mock_taskcluster):
    bus = MessageBus()
    hook = CodeCoverage("services-staging-codecoverage/bot", "project-test",
                        bus)

    assert run_async_parser(hook, "MibGDsa4Q7uFNzDf7EV6nw",
                            "gecko-level-2") == [{
                                "REPOSITORY":
                                "https://hg.mozilla.org/mozilla-central",
                                "REVISION":
                                "63519bfd42ee379f597c0357af2e712ec3cd9f50",
                            }]
def test_success_try(mock_taskcluster):
    bus = MessageBus()
    hook = CodeCoverage("services-staging-codecoverage/bot", "project-test",
                        bus)

    assert run_async_parser(hook, "FG3goVnCQfif8ZEOaM_4IA",
                            "gecko-level-1") == [{
                                "REPOSITORY":
                                "https://hg.mozilla.org/try",
                                "REVISION":
                                "066cb18ba95a7efe144e729713c429e422d9f95b",
                            }]
def test_success(mock_taskcluster):
    bus = MessageBus()
    hook = CodeCoverage("services-staging-codecoverage/bot", "project-test",
                        bus)

    assert run_async_parser(hook, "RS0UwZahQ_qAcdZzEb_Y9g",
                            "gecko-level-1") == [{
                                "REPOSITORY":
                                "https://hg.mozilla.org/mozilla-central",
                                "REVISION":
                                "ec3dd3ee2ae4b3a63529a912816a110e925eb2d0",
                            }]
Exemple #24
0
def test_queue_creation():
    """
    Test queues creation with different types
    """
    bus = MessageBus()
    assert len(bus.queues) == 0

    bus.add_queue("test")
    assert len(bus.queues) == 1

    with pytest.raises(AssertionError) as e:
        bus.add_queue("test")
    assert str(e.value) == "Queue test already setup"
    assert len(bus.queues) == 1

    bus.add_queue("another")
    assert len(bus.queues) == 2

    bus.add_queue("different", mp=True)
    assert len(bus.queues) == 3

    assert isinstance(bus.queues["test"], asyncio.Queue)
    assert isinstance(bus.queues["another"], asyncio.Queue)
    assert isinstance(bus.queues["different"], multiprocessing.queues.Queue)
Exemple #25
0
async def test_report_all_completed(QueueMock, NotifyMock, mock_taskcluster):
    bus = MessageBus()
    monitoring = Monitoring(mock_taskcluster, "testqueue", ["pinco@pallino"],
                            1)
    monitoring.register(bus)
    await bus.send("testqueue", ("Group1", "Hook1", "Task1-completed"))
    await bus.send("testqueue", ("Group1", "Hook1", "Task2-completed"))
    assert bus.queues["testqueue"].qsize() == 2

    monitoring.queue = QueueMock
    monitoring.notify = NotifyMock

    await monitoring.check_task()
    await monitoring.check_task()

    # No email sent, since all tasks were successful.
    await monitoring.send_report()
    assert NotifyMock.email_obj == {}
    assert monitoring.stats == {}
Exemple #26
0
async def test_run_async_parallel():
    """
    Test using run to get messages from a queue using an async function executed in parallel
    """
    bus = MessageBus()
    bus.add_queue("input")
    bus.add_queue("end", maxsize=1)
    assert isinstance(bus.queues["input"], asyncio.Queue)
    assert bus.queues["input"].qsize() == 0

    await bus.send("input", 0)
    await bus.send("input", 1)
    await bus.send("input", 2)

    assert bus.queues["input"].qsize() == 3

    done = {0: False, 1: False, 2: False}

    async def torun(count):
        await asyncio.sleep(0)

        if count == 0:
            # Wait for 7 seconds, in the meantime other tasks will be scheduled
            # and executed.
            await asyncio.sleep(7)
        elif count == 1:
            pass
        elif count == 2:
            await bus.send("end", count)
        else:
            assert False

        done[count] = True

    task = asyncio.create_task(bus.run(torun, "input", sequential=False))

    await bus.receive("end") == 1
    task.cancel()
    assert bus.queues["input"].qsize() == 0
    assert bus.queues["end"].qsize() == 0
    assert done == {0: False, 1: True, 2: True}
Exemple #27
0
async def test_maxsize():
    """
    Test a queue maxsize behaves as expected
    Maxsize=-1 is enabled by default
    """
    bus = MessageBus()
    bus.add_queue("async")
    bus.add_queue("mp", mp=True)
    assert bus.queues["async"].maxsize == -1
    # No maxsize getter on mp queues

    assert bus.queues["async"].empty()
    assert bus.queues["mp"].empty()

    for i in range(1000):
        await bus.send("async", i)
        await bus.send("mp", i)

    assert not bus.queues["async"].full()
    assert not bus.queues["mp"].full()
Exemple #28
0
async def test_run_async_without_output_queue():
    """
    Test using run to get messages from a queue using an async function and without an output queue
    """
    bus = MessageBus()
    bus.add_queue("input")
    bus.add_queue("end", maxsize=1)
    assert isinstance(bus.queues["input"], asyncio.Queue)
    assert bus.queues["input"].qsize() == 0

    await bus.send("input", "test x")
    await bus.send("input", "hello world.")

    assert bus.queues["input"].qsize() == 2

    count = 0

    async def torun(payload):
        nonlocal count

        if count == 0:
            assert payload == "test x"
        elif count == 1:
            assert payload == "hello world."
            await bus.send("end", count)
        else:
            assert False

        count += 1

    task = asyncio.create_task(bus.run(torun, "input"))

    await bus.receive("end") == 1
    task.cancel()
    assert bus.queues["input"].qsize() == 0
    assert bus.queues["end"].qsize() == 0
Exemple #29
0
async def test_got_try_task_end(PhabricatorMock, mock_taskcluster):
    bus = MessageBus()
    build = PhabricatorBuild(
        MockRequest(
            diff="125397",
            repo="PHID-REPO-saax4qdxlbbhahhp2kg5",
            revision="36474",
            target="PHID-HMBT-icusvlfibcebizyd33op",
        ))

    payload = {
        "routing": {
            "exchange":
            "exchange/taskcluster-queue/v1/task-completed",
            "key":
            "primary.fUAKaIdkSF6K1NlOgx7-LA.0.aws.i-0a45c84b1709af6a7.gecko-t.t-win10-64.gecko-level-1.RHY-YSgBQ7KlTAaQ5ZWP5g._",
            "other_routes": [
                b"route.tc-treeherder.v2.try.028980a035fb3e214f7645675a01a52234aad0fe.455891"
            ],
        },
        "body": {
            "status": {
                "taskId":
                "W2SMZ3bYTeanBq-WNpUeHA",
                "provisionerId":
                "gecko-t",
                "workerType":
                "t-linux-xlarge",
                "schedulerId":
                "gecko-level-1",
                "taskGroupId":
                "HDnvYOibTMS8h_5Qzv6fWg",
                "deadline":
                "2019-11-23T14:04:41.581Z",
                "expires":
                "2019-12-06T14:04:41.581Z",
                "retriesLeft":
                5,
                "state":
                "completed",
                "runs": [{
                    "runId": 0,
                    "state": "completed",
                    "reasonCreated": "scheduled",
                    "reasonResolved": "completed",
                    "workerGroup": "aws",
                    "workerId": "i-01a6b2a05e2211f7c",
                    "takenUntil": "2019-11-22T15:51:57.083Z",
                    "scheduled": "2019-11-22T15:31:56.661Z",
                    "started": "2019-11-22T15:31:57.162Z",
                    "resolved": "2019-11-22T15:42:46.684Z",
                }],
            },
            "runId": 0,
            "task": {
                "tags": {
                    "kind": "test",
                    "worker-implementation": "docker-worker",
                    "createdForUser": "******",
                    "retrigger": "true",
                    "label": "test-linux64-shippable/opt-awsy-tp6-e10s",
                    "os": "linux",
                }
            },
            "workerGroup": "aws",
            "workerId": "i-01a6b2a05e2211f7c",
            "version": 1,
        },
    }

    taskGroupId = payload["body"]["status"]["taskGroupId"]

    taskcluster_config.secrets["test_selection_enabled"] = True
    taskcluster_config.secrets["test_selection_share"] = 0.1

    with PhabricatorMock as phab:
        bus.add_queue(QUEUE_PHABRICATOR_RESULTS)

        phab.load_patches_stack(build)
        phab.update_state(build)
        phab.load_reviewers(build)

        bugbug_utils = BugbugUtils(phab.api)
        bugbug_utils.register(bus)

    try:
        await bugbug_utils.task_group_to_push.rem(taskGroupId)
    except KeyError:
        pass

    # Nothing happens for tasks that are not test tasks.
    payload["body"]["task"]["tags"]["kind"] = "source-test"
    await bugbug_utils.got_try_task_end(payload)
    assert bus.queues[QUEUE_PHABRICATOR_RESULTS].empty()

    # Nothing happens for tasks that are not registered.
    payload["body"]["task"]["tags"]["kind"] = "test"
    await bugbug_utils.got_try_task_end(payload)
    assert bus.queues[QUEUE_PHABRICATOR_RESULTS].empty()

    push = {
        "build": build,
        "revision": "028980a035fb3e214f7645675a01a52234aad0fe",
    }
    await bugbug_utils.task_group_to_push.set(taskGroupId, push)

    payload["body"]["status"]["state"] = "completed"
    await bugbug_utils.got_try_task_end(payload)
    mode, build_, extras = await bus.receive(QUEUE_PHABRICATOR_RESULTS)
    assert mode == "test_result"
    assert build_ == build
    assert extras == {
        "name": "test-linux64-shippable/opt-awsy-tp6-e10s",
        "result": UnitResultState.Pass,
        "details": None,
    }

    payload["body"]["status"]["state"] = "failed"
    await bugbug_utils.got_try_task_end(payload)
    mode, build_, extras = await bus.receive(QUEUE_PHABRICATOR_RESULTS)
    assert mode == "test_result"
    assert build_ == build
    assert extras == {
        "name":
        "test-linux64-shippable/opt-awsy-tp6-e10s",
        "result":
        UnitResultState.Fail,
        "details":
        "https://treeherder.mozilla.org/#/jobs?repo=try&revision=028980a035fb3e214f7645675a01a52234aad0fe&selectedTaskRun=W2SMZ3bYTeanBq-WNpUeHA-0",
    }
Exemple #30
0
async def test_got_bugbug_test_select_end(PhabricatorMock, mock_taskcluster):
    bus = MessageBus()
    build = PhabricatorBuild(
        MockRequest(
            diff="125397",
            repo="PHID-REPO-saax4qdxlbbhahhp2kg5",
            revision="36474",
            target="PHID-HMBT-icusvlfibcebizyd33op",
        ))

    diffId = str(build.diff_id)

    payload = {
        "routing": {
            "exchange":
            "exchange/taskcluster-queue/v1/task-completed",
            "key":
            "primary.OhtlizLqT9ah2jVkUL-yvg.0.community-tc-workers-google.8155538221748661937.proj-relman.compute-large.-.OhtlizLqT9ah2jVkUL-yvg._",
            "other_routes": [
                b"[email protected]",
                b"route.notify.irc-channel.#bugbug.on-failed",
                b"route.index.project.relman.bugbug.test_select.latest",
                f"route.index.project.relman.bugbug.test_select.diff.{diffId}".
                encode(),
                b"route.project.relman.bugbug.test_select",
            ],
        },
        "body": {
            "status": {
                "taskId":
                "bugbug-test-select",
                "provisionerId":
                "proj-relman",
                "workerType":
                "compute-large",
                "schedulerId":
                "-",
                "taskGroupId":
                "HDnvYOibTMS8h_5Qzv6fWg",
                "deadline":
                "2019-11-27T17:03:07.100Z",
                "expires":
                "2019-12-27T15:03:07.100Z",
                "retriesLeft":
                5,
                "state":
                "completed",
                "runs": [{
                    "runId": 0,
                    "state": "completed",
                    "reasonCreated": "scheduled",
                    "reasonResolved": "completed",
                    "workerGroup": "community-tc-workers-google",
                    "workerId": "8155538221748661937",
                    "takenUntil": "2019-11-27T15:25:02.767Z",
                    "scheduled": "2019-11-27T15:03:07.606Z",
                    "started": "2019-11-27T15:05:02.786Z",
                    "resolved": "2019-11-27T15:19:24.809Z",
                }],
            },
            "runId": 0,
            "task": {
                "tags": {}
            },
            "workerGroup": "community-tc-workers-google",
            "workerId": "8155538221748661937",
            "version": 1,
        },
    }

    taskGroupId = payload["body"]["status"]["taskGroupId"]

    taskcluster_config.secrets["test_selection_enabled"] = True
    taskcluster_config.secrets["test_selection_share"] = 0.1

    with PhabricatorMock as phab:
        phab.load_patches_stack(build)
        phab.update_state(build)

        bugbug_utils = BugbugUtils(phab.api)
        bugbug_utils.register(bus)

    try:
        await bugbug_utils.diff_to_push.rem(diffId)
    except KeyError:
        pass

    try:
        await bugbug_utils.task_group_to_push.rem(taskGroupId)
    except KeyError:
        pass

    # Nothing happens when diff_to_push is empty.
    with responses.RequestsMock(assert_all_requests_are_fired=True) as rsps:
        rsps.add(
            responses.GET,
            "http://community_taskcluster.test/api/queue/v1/task/bugbug-test-select",
            body=mock_taskcluster("task-bugbug-test-select.json"),
            content_type="application/json",
        )

        rsps.add(
            responses.GET,
            "http://community_taskcluster.test/api/queue/v1/task/bugbug-test-select/artifacts/public%2Ffailure_risk",
            body=mock_taskcluster("artifact-bugbug-test-select-failure-risk"),
        )

        rsps.add(
            responses.GET,
            "http://community_taskcluster.test/api/queue/v1/task/bugbug-test-select/artifacts/public%2Fselected_tasks",
            body=mock_taskcluster(
                "artifact-bugbug-test-select-selected-tasks"),
        )

        with pytest.raises(KeyError):
            await bugbug_utils.diff_to_push.get(diffId)
        await bugbug_utils.got_bugbug_test_select_end(payload)
        with pytest.raises(KeyError):
            await bugbug_utils.task_group_to_push.get(taskGroupId)

    # Nothing happens when we are on the wrong Phabricator deployment.
    with responses.RequestsMock(assert_all_requests_are_fired=True) as rsps:
        rsps.add(
            responses.GET,
            "http://community_taskcluster.test/api/queue/v1/task/bugbug-test-select",
            body=mock_taskcluster("task-bugbug-test-select.json"),
            content_type="application/json",
        )

        bugbug_utils.phabricator_deployment = "dev"

        await bugbug_utils.diff_to_push.set(diffId, {
            "revision": "123",
            "build": build
        })
        await bugbug_utils.got_bugbug_test_select_end(payload)
        with pytest.raises(KeyError):
            await bugbug_utils.task_group_to_push.get(taskGroupId)
        await bugbug_utils.diff_to_push.rem(diffId)

        bugbug_utils.phabricator_deployment = "prod"

    # Nothing happens when the failure risk is low.
    with responses.RequestsMock(assert_all_requests_are_fired=True) as rsps:
        rsps.add(
            responses.GET,
            "http://community_taskcluster.test/api/queue/v1/task/bugbug-test-select",
            body=mock_taskcluster("task-bugbug-test-select.json"),
            content_type="application/json",
        )

        rsps.add(
            responses.GET,
            "http://community_taskcluster.test/api/queue/v1/task/bugbug-test-select/artifacts/public%2Ffailure_risk",
            body=mock_taskcluster(
                "artifact-bugbug-test-select-failure-risk-0"),
        )

        await bugbug_utils.diff_to_push.set(diffId, {
            "revision": "123",
            "build": build
        })
        await bugbug_utils.got_bugbug_test_select_end(payload)
        with pytest.raises(KeyError):
            await bugbug_utils.task_group_to_push.get(taskGroupId)
        # Wait removal of object from diff_to_push to be done.
        tasks = set(asyncio.all_tasks())
        tasks.remove(asyncio.current_task())
        await asyncio.gather(*tasks)
        with pytest.raises(KeyError):
            await bugbug_utils.diff_to_push.get(diffId)

    # Nothing happens when the failure risk is high but there are no selected tasks.
    with responses.RequestsMock(assert_all_requests_are_fired=True) as rsps:
        rsps.add(
            responses.GET,
            "http://community_taskcluster.test/api/queue/v1/task/bugbug-test-select",
            body=mock_taskcluster("task-bugbug-test-select.json"),
            content_type="application/json",
        )

        rsps.add(
            responses.GET,
            "http://community_taskcluster.test/api/queue/v1/task/bugbug-test-select/artifacts/public%2Ffailure_risk",
            body=mock_taskcluster("artifact-bugbug-test-select-failure-risk"),
        )

        rsps.add(
            responses.GET,
            "http://community_taskcluster.test/api/queue/v1/task/bugbug-test-select/artifacts/public%2Fselected_tasks",
            body=mock_taskcluster(
                "artifact-bugbug-test-select-selected-tasks-none"),
        )

        await bugbug_utils.diff_to_push.set(diffId, {
            "revision": "123",
            "build": build
        })
        await bugbug_utils.got_bugbug_test_select_end(payload)
        with pytest.raises(KeyError):
            await bugbug_utils.task_group_to_push.get(taskGroupId)
        # Wait removal of object from diff_to_push to be done.
        tasks = set(asyncio.all_tasks())
        tasks.remove(asyncio.current_task())
        await asyncio.gather(*tasks)
        with pytest.raises(KeyError):
            await bugbug_utils.diff_to_push.get(diffId)

    # Stuff happens.
    with responses.RequestsMock(assert_all_requests_are_fired=True) as rsps:
        rsps.add(
            responses.GET,
            "http://community_taskcluster.test/api/queue/v1/task/bugbug-test-select",
            body=mock_taskcluster("task-bugbug-test-select.json"),
            content_type="application/json",
        )

        rsps.add(
            responses.GET,
            "http://community_taskcluster.test/api/queue/v1/task/bugbug-test-select/artifacts/public%2Ffailure_risk",
            body=mock_taskcluster("artifact-bugbug-test-select-failure-risk"),
        )

        rsps.add(
            responses.GET,
            "http://community_taskcluster.test/api/queue/v1/task/bugbug-test-select/artifacts/public%2Fselected_tasks",
            body=mock_taskcluster(
                "artifact-bugbug-test-select-selected-tasks"),
        )

        rsps.add(
            responses.GET,
            "http://taskcluster.test/api/index/v1/task/gecko.v2.try.revision.123.taskgraph.decision",
            body=mock_taskcluster("index-gecko-decision.json"),
            content_type="application/json",
        )

        rsps.add(
            responses.GET,
            f"http://taskcluster.test/api/queue/v1/task/{taskGroupId}/artifacts/public%2Factions.json",
            body=mock_taskcluster("artifact-gecko-decision-actions.json"),
            content_type="application/json",
        )

        def trigger_hook_callback(request):
            payload = json.loads(request.body)
            assert payload == json.loads(
                mock_taskcluster("trigger-hook-add-new-jobs-post-body.json"))
            return (
                200,
                {
                    "Content-Type": "application/json"
                },
                mock_taskcluster("trigger-hook-add-new-jobs.json"),
            )

        rsps.add_callback(
            responses.POST,
            "http://taskcluster.test/api/hooks/v1/hooks/project-gecko/in-tree-action-1-generic%2Fea5d85cbef/trigger",
            callback=trigger_hook_callback,
        )

        push = {"revision": "123", "build": build}
        await bugbug_utils.diff_to_push.set(diffId, push)
        await bugbug_utils.got_bugbug_test_select_end(payload)
        assert await bugbug_utils.task_group_to_push.get(taskGroupId) == push
        # Wait removal of object from diff_to_push to be done.
        tasks = set(asyncio.all_tasks())
        tasks.remove(asyncio.current_task())
        await asyncio.gather(*tasks)
        with pytest.raises(KeyError):
            await bugbug_utils.diff_to_push.get(diffId)