コード例 #1
0
def test_phabricator_coverage(mock_config, mock_phabricator, mock_try_task):
    """
    Test Phabricator reporter publication on a mock coverage issue
    """
    from code_review_bot.report.phabricator import PhabricatorReporter
    from code_review_bot.revisions import Revision
    from code_review_bot.tasks.coverage import CoverageIssue

    def _check_comment(request):
        # Check the Phabricator main comment is well formed
        payload = urllib.parse.parse_qs(request.body)
        assert payload["output"] == ["json"]
        assert len(payload["params"]) == 1
        details = json.loads(payload["params"][0])
        assert details["message"] == VALID_COVERAGE_MESSAGE

        # Outputs dummy empty response
        resp = {"error_code": None, "result": None}
        return (
            201,
            {
                "Content-Type": "application/json",
                "unittest": "coverage"
            },
            json.dumps(resp),
        )

    responses.add_callback(
        responses.POST,
        "http://phabricator.test/api/differential.createcomment",
        callback=_check_comment,
    )

    with mock_phabricator as api:
        revision = Revision(api, mock_try_task)
        revision.lines = {
            # Add dummy lines diff
            "test.txt": [0],
            "path/to/test.cpp": [0],
            "dom/test.cpp": [42],
        }
        reporter = PhabricatorReporter({"analyzers": ["coverage"]}, api=api)

    issue = CoverageIssue("path/to/test.cpp", 0, "This file is uncovered",
                          revision)
    assert issue.is_publishable()

    issues, patches = reporter.publish([issue], revision, [])
    assert len(issues) == 1
    assert len(patches) == 0

    # Check the callback has been used
    assert len(responses.calls) > 0
    call = responses.calls[-1]
    assert call.request.url == "http://phabricator.test/api/differential.createcomment"
    assert call.response.headers.get("unittest") == "coverage"
コード例 #2
0
    def _test_reporter(api, analyzers):
        # Always use the same setup, only varies the analyzers
        revision = Revision(api, mock_try_task)
        revision.lines = {"test.cpp": [0, 41, 42, 43], "dom/test.cpp": [42]}
        reporter = PhabricatorReporter({"analyzers": analyzers}, api=api)

        issues = [
            ClangFormatIssue("dom/test.cpp", 42, 1, revision),
            ClangTidyIssue(
                revision,
                "test.cpp",
                "42",
                "51",
                "modernize-use-nullptr",
                "dummy message",
                "error",
            ),
            InferIssue(
                {
                    "file": "test.cpp",
                    "line": 42,
                    "column": 1,
                    "bug_type": "dummy",
                    "kind": "whatever",
                    "qualifier": "dummy message.",
                },
                revision,
            ),
            MozLintIssue("test.cpp", 1, "danger", 42, "flake8", "Python error",
                         "EXXX", revision),
            CoverageIssue("test.cpp", 0, "This file is uncovered", revision),
        ]

        assert all(i.is_publishable() for i in issues)

        revision.improvement_patches = [
            ImprovementPatch("dummy", repr(revision), "Whatever"),
            ImprovementPatch("clang-tidy", repr(revision), "Some C fixes"),
            ImprovementPatch("clang-format", repr(revision),
                             "Some lint fixes"),
            ImprovementPatch("infer", repr(revision), "Some java fixes"),
            ImprovementPatch("mozlint", repr(revision), "Some js fixes"),
        ]
        list(map(lambda p: p.write(),
                 revision.improvement_patches))  # trigger local write

        return reporter.publish(issues, revision)
コード例 #3
0
def test_full_file(mock_config, mock_phabricator, mock_try_task):
    """
    Test Phabricator reporter supports an issue on a full file
    """
    from code_review_bot.report.phabricator import PhabricatorReporter
    from code_review_bot.revisions import Revision
    from code_review_bot.tasks.default import DefaultIssue

    def _check_comment(request):
        # Check the Phabricator main comment is well formed
        payload = urllib.parse.parse_qs(request.body)
        assert payload["output"] == ["json"]
        assert len(payload["params"]) == 1
        details = json.loads(payload["params"][0])
        assert details["message"] == VALID_DEFAULT_MESSAGE.format(
            results=mock_config.taskcluster.results_dir)

        # Outputs dummy empty response
        resp = {"error_code": None, "result": None}
        return (
            201,
            {
                "Content-Type": "application/json",
                "unittest": "full-file-comment"
            },
            json.dumps(resp),
        )

    def _check_inline(request):
        # Check the inline does not have a null value for line
        payload = urllib.parse.parse_qs(request.body)
        assert payload["output"] == ["json"]
        assert len(payload["params"]) == 1
        details = json.loads(payload["params"][0])

        assert details == {
            "__conduit__": {
                "token": "deadbeef"
            },
            "content":
            "Error: Something bad happened on the whole file ! [a-huge-issue]",
            "diffID": 42,
            "filePath": "xx.cpp",
            "isNewFile": 1,
            "lineLength": -1,
            # Cannot be null for a full file as it's not supported by phabricator
            "lineNumber": 1,
        }

        # Outputs dummy empty response
        resp = {"error_code": None, "result": {"id": "PHID-XXXX-YYYYY"}}
        return (
            201,
            {
                "Content-Type": "application/json",
                "unittest": "full-file-inline"
            },
            json.dumps(resp),
        )

    responses.add_callback(
        responses.POST,
        "http://phabricator.test/api/differential.createinline",
        callback=_check_inline,
    )
    responses.add_callback(
        responses.POST,
        "http://phabricator.test/api/differential.createcomment",
        callback=_check_comment,
    )

    with mock_phabricator as api:
        revision = Revision(api, mock_try_task)
        revision.lines = {
            # Add dummy lines diff
            "xx.cpp": [123, 124, 125]
        }
        revision.files = list(revision.lines.keys())
        reporter = PhabricatorReporter(api=api)

    issue = DefaultIssue(
        analyzer="full-file-analyzer",
        revision=revision,
        path="xx.cpp",
        line=-1,
        nb_lines=0,
        check="a-huge-issue",
        message="Something bad happened on the whole file !",
    )
    assert issue.line is None  # check auto conversion
    assert str(
        issue
    ) == "full-file-analyzer issue a-huge-issue@error xx.cpp full file"
    assert issue.is_publishable()
    assert revision.has_file(issue.path)
    assert revision.contains(issue)

    issues, patches = reporter.publish([issue], revision, [])
    assert len(issues) == 1
    assert len(patches) == 0

    # Check the comment callback has been used
    assert len(responses.calls) > 0
    call = responses.calls[-1]
    assert call.request.url == "http://phabricator.test/api/differential.createcomment"
    assert call.response.headers.get("unittest") == "full-file-comment"

    # Check the inline callback has been used
    call = responses.calls[-2]
    assert call.request.url == "http://phabricator.test/api/differential.createinline"
    assert call.response.headers.get("unittest") == "full-file-inline"
コード例 #4
0
def test_phabricator_clang_tidy(mock_phabricator, mock_try_task):
    """
    Test Phabricator reporter publication on a mock clang-tidy issue
    """
    from code_review_bot.report.phabricator import PhabricatorReporter
    from code_review_bot.revisions import Revision
    from code_review_bot.tasks.clang_tidy import ClangTidyIssue

    def _check_comment(request):
        # Check the Phabricator main comment is well formed
        payload = urllib.parse.parse_qs(request.body)
        assert payload["output"] == ["json"]
        assert len(payload["params"]) == 1
        details = json.loads(payload["params"][0])
        assert details == {
            "revision_id": 51,
            "message": VALID_CLANG_TIDY_MESSAGE,
            "attach_inlines": 1,
            "__conduit__": {
                "token": "deadbeef"
            },
        }

        # Outputs dummy empty response
        resp = {"error_code": None, "result": None}
        return (
            201,
            {
                "Content-Type": "application/json",
                "unittest": "clang-tidy"
            },
            json.dumps(resp),
        )

    responses.add_callback(
        responses.POST,
        "http://phabricator.test/api/differential.createcomment",
        callback=_check_comment,
    )

    with mock_phabricator as api:
        revision = Revision(api, mock_try_task)
        revision.lines = {
            # Add dummy lines diff
            "another_test.cpp": [41, 42, 43]
        }
        revision.files = ["another_test.cpp"]
        reporter = PhabricatorReporter(
            {
                "analyzers": ["clang-tidy"],
                "modes": ("comment")
            }, api=api)

    issue = ClangTidyIssue(
        "mock-clang-tidy",
        revision,
        "another_test.cpp",
        "42",
        "51",
        "modernize-use-nullptr",
        "dummy message",
        "error",
    )
    assert issue.is_publishable()

    issues, patches = reporter.publish([issue], revision, [])
    assert len(issues) == 1
    assert len(patches) == 0

    # Check the callback has been used
    assert len(responses.calls) > 0
    call = responses.calls[-1]
    assert call.request.url == "http://phabricator.test/api/differential.createcomment"
    assert call.response.headers.get("unittest") == "clang-tidy"
コード例 #5
0
def test_phabricator_unitresult(mock_phabricator, mock_try_task):
    """
    Test Phabricator UnitResult for a CoverityIssue
    """
    from code_review_bot.tasks.coverity import CoverityIssue
    from code_review_bot.report.phabricator import PhabricatorReporter
    from code_review_bot.revisions import Revision

    def _check_message(request):
        # Check the Phabricator main comment is well formed
        payload = urllib.parse.parse_qs(request.body)
        assert payload["output"] == ["json"]
        assert len(payload["params"]) == 1
        details = json.loads(payload["params"][0])
        assert details == {
            "buildTargetPHID": "PHID-HMBD-deadbeef12456",
            "lint": [],
            "unit": [],
            "type": "work",
            "__conduit__": {
                "token": "deadbeef"
            },
        }

        # Outputs dummy empty response
        resp = {"error_code": None, "result": None}
        return (
            201,
            {
                "Content-Type": "application/json",
                "unittest": "coverity"
            },
            json.dumps(resp),
        )

    def _check_unitresult(request):
        # Check the Phabricator main comment is well formed
        payload = urllib.parse.parse_qs(request.body)
        assert payload["output"] == ["json"]
        assert len(payload["params"]) == 1
        details = json.loads(payload["params"][0])
        assert details == {
            "buildTargetPHID":
            "PHID-HMBD-deadbeef12456",
            "lint": [],
            "unit": [{
                "details":
                'Code review bot found a **build error**: \nDereferencing a pointer that might be "nullptr" "env" when calling "lookupImport".',
                "format": "remarkup",
                "name": "general",
                "namespace": "code-review",
                "result": "fail",
            }],
            "type":
            "fail",
            "__conduit__": {
                "token": "deadbeef"
            },
        }

        # Outputs dummy empty response
        resp = {"error_code": None, "result": None}
        return (
            201,
            {
                "Content-Type": "application/json",
                "unittest": "coverity"
            },
            json.dumps(resp),
        )

    # First callback is to catch the publicatio of a lint
    responses.add_callback(
        responses.POST,
        "http://phabricator.test/api/harbormaster.sendmessage",
        callback=_check_message,
    )

    # Catch the publication of a UnitResult failure
    responses.add_callback(
        responses.POST,
        "http://phabricator.test/api/harbormaster.sendmessage",
        callback=_check_unitresult,
    )

    with mock_phabricator as api:
        revision = Revision(api, mock_try_task)
        revision.lines = {
            # Add dummy lines diff
            "test.cpp": [41, 42, 43]
        }
        revision.build_target_phid = "PHID-HMBD-deadbeef12456"
        reporter = PhabricatorReporter(
            {
                "analyzers": ["coverity"],
                "mode": "harbormaster",
                "publish_build_errors": True,
            },
            api=api,
        )

        issue_dict = {
            "line": 41,
            "reliability": "medium",
            "message":
            'Dereferencing a pointer that might be "nullptr" "env" when calling "lookupImport".',
            "flag": "NULL_RETURNS",
            "build_error": True,
            "extra": {
                "category": "Null pointer dereferences",
                "stateOnServer": {
                    "ownerLdapServerName": "local",
                    "stream": "Firefox",
                    "cid": 95687,
                    "cached": False,
                    "retrievalDateTime": "2019-05-13T10:20:22+00:00",
                    "firstDetectedDateTime": "2019-04-08T12:57:07+00:00",
                    "presentInReferenceSnapshot": False,
                    "components": ["js"],
                    "customTriage": {},
                    "triage": {
                        "fixTarget": "Untargeted",
                        "severity": "Unspecified",
                        "classification": "Unclassified",
                        "owner": "try",
                        "legacy": "False",
                        "action": "Undecided",
                        "externalReference": "",
                    },
                },
            },
        }

        issue = CoverityIssue("mock-coverity", revision, issue_dict,
                              "test.cpp")
        assert issue.is_publishable()

        issues, patches = reporter.publish([issue], revision, [])
        assert len(issues) == 1
        assert len(patches) == 0

        # Check the callback has been used
        assert len(responses.calls) > 0

        # Only check the last call
        print(responses.calls[-1].request.url)
        assert responses.calls[-1].response.headers.get(
            "unittest") == "coverity"
コード例 #6
0
def test_phabricator_harbormaster(mock_phabricator, mock_try_task):
    """
    Test Phabricator reporter publication on a mock clang-tidy issue
    using harbormaster
    """
    from code_review_bot.report.phabricator import PhabricatorReporter
    from code_review_bot.revisions import Revision
    from code_review_bot.tasks.clang_tidy import ClangTidyIssue

    def _check_message(request):
        # Check the Phabricator main comment is well formed
        payload = urllib.parse.parse_qs(request.body)
        assert payload["output"] == ["json"]
        assert len(payload["params"]) == 1
        details = json.loads(payload["params"][0])
        assert details == {
            "buildTargetPHID":
            "PHID-HMBD-deadbeef12456",
            "lint": [{
                "char": 51,
                "code": "clang-tidy.modernize-use-nullptr",
                "name": "Clang-Tidy - modernize-use-nullptr",
                "line": 42,
                "path": "test.cpp",
                "severity": "warning",
                "description": "dummy message",
            }],
            "unit": [],
            "type":
            "work",
            "__conduit__": {
                "token": "deadbeef"
            },
        }

        # Outputs dummy empty response
        resp = {"error_code": None, "result": None}
        return (
            201,
            {
                "Content-Type": "application/json",
                "unittest": "clang-tidy"
            },
            json.dumps(resp),
        )

    responses.add_callback(
        responses.POST,
        "http://phabricator.test/api/harbormaster.sendmessage",
        callback=_check_message,
    )

    with mock_phabricator as api:
        revision = Revision(api, mock_try_task)
        revision.lines = {
            # Add dummy lines diff
            "test.cpp": [41, 42, 43]
        }
        revision.build_target_phid = "PHID-HMBD-deadbeef12456"
        reporter = PhabricatorReporter(
            {
                "analyzers": ["clang-tidy"],
                "mode": "harbormaster"
            }, api=api)

    issue = ClangTidyIssue(
        "mock-clang-tidy",
        revision,
        "test.cpp",
        "42",
        "51",
        "modernize-use-nullptr",
        "dummy message",
        "error",
    )
    assert issue.is_publishable()

    issues, patches = reporter.publish([issue], revision, [])
    assert len(issues) == 1
    assert len(patches) == 0

    # Check the callback has been used
    assert len(responses.calls) > 0
    call = responses.calls[-1]
    assert call.request.url == "http://phabricator.test/api/harbormaster.sendmessage"
    assert call.response.headers.get("unittest") == "clang-tidy"
コード例 #7
0
def test_phabricator_clang_format(mock_config, mock_phabricator,
                                  mock_try_task):
    """
    Test Phabricator reporter publication on a mock clang-format issue
    """
    from code_review_bot.report.phabricator import PhabricatorReporter
    from code_review_bot.revisions import Revision, ImprovementPatch
    from code_review_bot.tasks.clang_format import ClangFormatIssue

    def _check_comment(request):
        # Check the Phabricator main comment is well formed
        payload = urllib.parse.parse_qs(request.body)
        assert payload["output"] == ["json"]
        assert len(payload["params"]) == 1
        details = json.loads(payload["params"][0])
        assert details["message"] == VALID_CLANG_FORMAT_MESSAGE.format(
            results=mock_config.taskcluster.results_dir)

        # Outputs dummy empty response
        resp = {"error_code": None, "result": None}
        return (
            201,
            {
                "Content-Type": "application/json",
                "unittest": "clang-format"
            },
            json.dumps(resp),
        )

    responses.add_callback(
        responses.POST,
        "http://phabricator.test/api/differential.createcomment",
        callback=_check_comment,
    )

    with mock_phabricator as api:
        revision = Revision(api, mock_try_task)
        revision.lines = {
            # Add dummy lines diff
            "test.cpp": [41, 42, 43],
            "dom/test.cpp": [42],
        }
        reporter = PhabricatorReporter({"analyzers": ["clang-format"]},
                                       api=api)

    issue = ClangFormatIssue("mock-clang-format", "dom/test.cpp", 42, 1,
                             revision)
    assert issue.is_publishable()

    revision.improvement_patches = [
        ImprovementPatch("clang-format", repr(revision), "Some lint fixes")
    ]
    list(map(lambda p: p.write(),
             revision.improvement_patches))  # trigger local write

    issues, patches = reporter.publish([issue], revision, [])
    assert len(issues) == 1
    assert len(patches) == 1

    # Check the callback has been used
    assert len(responses.calls) > 0
    call = responses.calls[-1]
    assert call.request.url == "http://phabricator.test/api/differential.createcomment"
    assert call.response.headers.get("unittest") == "clang-format"