def test_publication(monkeypatch, mock_taskcluster_config): """ Check a patch publication through Taskcluster services """ # Setup local config as running in a real Taskcluster task with proxy monkeypatch.setenv("TASK_ID", "fakeTaskId") monkeypatch.setenv("RUN_ID", "0") monkeypatch.setenv("TASKCLUSTER_PROXY_URL", "http://proxy") settings.setup("test", []) # Mock the storage response responses.add( responses.PUT, "http://storage.test/public/patch/mock-analyzer-test-improvement.diff", json={}, headers={"ETag": "test123"}, ) patch = ImprovementPatch("mock-analyzer", "test-improvement", "This is good code") assert patch.url is None patch.publish() assert ( patch.url == "https://firefox-ci-tc.services.mozilla.com/api/queue/v1/task/fakeTaskId/runs/0/artifacts/public/patch/mock-analyzer-test-improvement.diff" ) # Check the mock has been called assert [c.request.url for c in responses.calls] == [ "http://storage.test/public/patch/mock-analyzer-test-improvement.diff" ]
def _test_reporter(api, analyzers_skipped): # Always use the same setup, only varies the analyzers revision = Revision.from_try(mock_try_task, api) revision.lines = {"test.cpp": [0, 41, 42, 43], "dom/test.cpp": [42]} reporter = PhabricatorReporter( {"analyzers_skipped": analyzers_skipped}, api=api ) issues = [ ClangFormatIssue("mock-clang-format", "dom/test.cpp", 42, 1, revision), ClangTidyIssue( "mock-clang-tidy", revision, "test.cpp", "42", "51", "modernize-use-nullptr", "dummy message", ), InferIssue( "mock-infer", { "file": "test.cpp", "line": 42, "column": 1, "bug_type": "dummy", "kind": "WARNING", "qualifier": "dummy message.", }, revision, ), MozLintIssue( "mock-lint-flake8", "test.cpp", 1, "error", 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("mock-clang-tidy", repr(revision), "Some C fixes"), ImprovementPatch("mock-clang-format", repr(revision), "Some lint fixes"), ImprovementPatch("mock-infer", repr(revision), "Some java fixes"), ImprovementPatch("mock-lint-flake8", repr(revision), "Some js fixes"), ] list( map(lambda p: p.write(), revision.improvement_patches) ) # trigger local write return reporter.publish(issues, revision, [])
def test_mail(mock_config, mock_issues, mock_revision, mock_taskcluster_config, mock_task): """ Test mail sending through Taskcluster """ from code_review_bot.report.mail import MailReporter from code_review_bot.revisions import ImprovementPatch def _check_email(request): payload = json.loads(request.body) assert payload["subject"] in ( "[test] New Static Analysis Phabricator #42 - PHID-DIFF-test", ) assert payload["address"] == "*****@*****.**" assert payload["template"] == "fullscreen" assert payload["content"] == MAIL_CONTENT.format( results=mock_config.taskcluster.results_dir) return (200, {}, "") # ack # Add mock taskcluster email to check output responses.add_callback( responses.POST, "http://taskcluster.test/api/notify/v1/email", callback=_check_email, ) # Publish email conf = {"emails": ["*****@*****.**"]} r = MailReporter(conf) mock_revision.improvement_patches = [ ImprovementPatch( mock_task(ClangTidyTask, "clang-tidy"), repr(mock_revision), "Some code fixes", ), ImprovementPatch( mock_task(ClangFormatTask, "clang-format"), repr(mock_revision), "Some lint fixes", ), ] list(map(lambda p: p.write(), mock_revision.improvement_patches)) # trigger local write r.publish(mock_issues, mock_revision, []) # Check stats assert r.calc_stats(mock_issues) == [{ "analyzer": "mock-analyzer", "help": None, "total": 5, "publishable": 3, "publishable_paths": ["/path/to/file"], }]
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.from_try(mock_try_task, api) revision.lines = { # Add dummy lines diff "test.cpp": [41, 42, 43], "dom/test.cpp": [42], } reporter = PhabricatorReporter({"analyzers": ["clang-format"]}, api=api) issue = ClangFormatIssue( "source-test-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"
def test_phabricator_clang_format(mock_config, mock_phabricator, phab, mock_try_task, mock_task): """ Test Phabricator reporter publication on a mock clang-format issue """ with mock_phabricator as api: revision = Revision.from_try(mock_try_task, api) revision.mercurial_revision = "deadbeef1234" revision.repository = "https://hg.mozilla.org/try" revision.repository_try_name = "try" revision.lines = { # Add dummy lines diff "test.cpp": [41, 42, 43], "dom/test.cpp": [42], } reporter = PhabricatorReporter({"analyzers": ["clang-format"]}, api=api) task = mock_task(ClangFormatTask, "source-test-clang-format") lines = [ (41, 41, b"no change"), (42, None, b"deletion"), (None, 42, b"change here"), ] issue = ClangFormatIssue(task, "dom/test.cpp", lines, revision) assert issue.is_publishable() revision.improvement_patches = [ ImprovementPatch(task, 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 comment has been posted assert phab.comments[51] == [ VALID_CLANG_FORMAT_MESSAGE.format( results=mock_config.taskcluster.results_dir) ]
def test_phabricator_analyzers( analyzers_skipped, valid_issues, valid_patches, mock_config, mock_phabricator, mock_try_task, mock_task, ): """ Test analyzers filtering on phabricator reporter """ with mock_phabricator as api: # Skip commenting on phabricator # we only care about filtering issues api.comment = unittest.mock.Mock(return_value=True) # Always use the same setup, only varies the analyzers revision = Revision.from_try(mock_try_task, api) revision.mercurial_revision = "deadbeef1234" revision.repository = "https://hg.mozilla.org/try" revision.repository_try_name = "try" revision.lines = {"test.cpp": [0, 41, 42, 43], "dom/test.cpp": [42]} reporter = PhabricatorReporter( {"analyzers_skipped": analyzers_skipped}, api=api ) issues = [ ClangFormatIssue( mock_task(ClangFormatTask, "mock-clang-format"), "dom/test.cpp", [ (41, 41, b"no change"), (42, None, b"deletion"), (None, 42, b"change here"), ], revision, ), ClangTidyIssue( mock_task(ClangTidyTask, "mock-clang-tidy"), revision, "test.cpp", "42", "51", "modernize-use-nullptr", "dummy message", ), InferIssue( mock_task(InferTask, "mock-infer"), { "file": "test.cpp", "line": 42, "column": 1, "bug_type": "dummy", "kind": "WARNING", "qualifier": "dummy message.", }, revision, ), MozLintIssue( mock_task(MozLintTask, "mock-lint-flake8"), "test.cpp", 1, "error", 42, "flake8", "Python error", "EXXX", revision, ), CoverageIssue( mock_task(ZeroCoverageTask, "coverage"), "test.cpp", 0, "This file is uncovered", revision, ), ] assert all(i.is_publishable() for i in issues) revision.improvement_patches = [ ImprovementPatch(mock_task(DefaultTask, "dummy"), repr(revision), "Whatever"), ImprovementPatch( mock_task(ClangTidyTask, "mock-clang-tidy"), repr(revision), "Some C fixes" ), ImprovementPatch( mock_task(ClangFormatTask, "mock-clang-format"), repr(revision), "Some lint fixes", ), ImprovementPatch( mock_task(InferTask, "mock-infer"), repr(revision), "Some java fixes" ), ImprovementPatch( mock_task(MozLintTask, "mock-lint-flake8"), repr(revision), "Some js fixes" ), ] list(map(lambda p: p.write(), revision.improvement_patches)) # trigger local write issues, patches = reporter.publish(issues, revision, []) # Check issues & patches analyzers assert len(issues) == len(valid_issues) assert len(patches) == len(valid_patches) assert [i.analyzer.name for i in issues] == valid_issues assert [p.analyzer.name for p in patches] == valid_patches