def run(self, revision):
        '''
        Build analysis workflows and directly run them
        '''
        issues = []

        # Index ASAP Taskcluster task for this revision
        self.index(revision, state='started')

        # Set the Phabricator build as running
        revision.update_status(state=BuildState.Work)

        # Use remote when we are on try
        if settings.source == SOURCE_TRY:
            remote = RemoteWorkflow(self.queue_service)
            issues += remote.run(revision)

        # Always use local workflow
        # until we have all analyzers in-tree
        local = LocalWorkflow(self, self.analyzers, self.index_service)
        issues += local.run(revision)

        if not issues:
            logger.info('No issues, stopping there.')
            self.index(revision, state='done', issues=0)
            revision.update_status(BuildState.Pass)
            return

        # Publish all issues from both workflows at once
        self.publish(revision, issues)
def test_unsupported_analyzer(mock_try_config, mock_revision):
    '''
    Test a remote workflow with an unsupported analyzer (not mozlint)
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'deadbeef1234',
            }
        },
        'remoteTryTask': {
            'dependencies': ['analyzer-A', 'analyzer-B']
        },
        'analyzer-A': {},
        'analyzer-B': {
            'name': 'custom-analyzer-from-vendor',
            'state': 'failed',
            'artifacts': {
                'issue.log':
                'TEST-UNEXPECTED-ERROR | test.cpp:12:1 | clearly an issue (checker XXX)',
            }
        },
        'extra-task': {},
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    with pytest.raises(Exception) as e:
        workflow.run(mock_revision)
    assert str(e.value) == 'Unsupported task custom-analyzer-from-vendor'
def test_no_issues(mock_try_config, mock_revision):
    '''
    Test a remote workflow without any issues in its artifacts
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'deadbeef1234',
            }
        },
        'remoteTryTask': {
            'dependencies': ['analyzer-A', 'analyzer-B']
        },
        'analyzer-A': {},
        'analyzer-B': {
            'name': 'source-test-mozlint-flake8',
            'state': 'failed',
            'artifacts': {
                'nope.log': 'No issues here !',
                'still-nope.txt': 'xxxxx',
                'public/code-review/mozlint.json': {},
            }
        },
        'extra-task': {},
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    issues = workflow.run(mock_revision)
    assert len(issues) == 0
示例#4
0
def test_unsupported_analyzer(mock_try_config, mock_revision):
    '''
    Test a remote workflow with an unsupported analyzer (not mozlint)
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'deadbeef1234',
            }
        },
        'remoteTryTask': {
            'dependencies': ['analyzer-A', 'analyzer-B']
        },
        'analyzer-A': {},
        'analyzer-B': {
            'name': 'custom-analyzer-from-vendor',
            'state': 'failed',
            'artifacts': {
                'issue.log': 'TEST-UNEXPECTED-ERROR | test.cpp:12:1 | clearly an issue (checker XXX)',
            }
        },
        'extra-task': {},
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    with pytest.raises(Exception) as e:
        workflow.run(mock_revision)
    assert str(e.value) == 'Unsupported task custom-analyzer-from-vendor'
示例#5
0
def test_no_issues(mock_try_config, mock_revision):
    '''
    Test a remote workflow without any issues in its artifacts
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'deadbeef1234',
            }
        },
        'remoteTryTask': {
            'dependencies': ['analyzer-A', 'analyzer-B']
        },
        'analyzer-A': {},
        'analyzer-B': {
            'name': 'source-test-mozlint-flake8',
            'state': 'failed',
            'artifacts': {
                'nope.log': 'No issues here !',
                'still-nope.txt': 'xxxxx',
                'public/code-review/mozlint.json': {},
            }
        },
        'extra-task': {},
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    issues = workflow.run(mock_revision)
    assert len(issues) == 0
示例#6
0
def test_clang_format_task(mock_try_config, mock_revision):
    '''
    Test a remote workflow with a clang-format analyzer
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow
    from static_analysis_bot.clang.format import ClangFormatIssue

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'deadbeef1234',
            }
        },
        'remoteTryTask': {
            'dependencies': ['clang-format']
        },
        'clang-format': {
            'name': 'source-test-clang-format',
            'state': 'completed',
            'artifacts': {
                'public/code-review/clang-format.json': {
                    'test.cpp': [
                        {
                            'line_offset': 11,
                            'char_offset': 44616,
                            'char_length': 7,
                            'lines_modified': 2,
                            'line': 1386,
                            'replacement': 'Multi\nlines',
                        }
                    ]
                }
            }
        }
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    issues = workflow.run(mock_revision)
    assert len(issues) == 1
    issue = issues[0]
    assert isinstance(issue, ClangFormatIssue)
    assert issue.path == 'test.cpp'
    assert issue.line == 1386
    assert issue.nb_lines == 2
    assert issue.patch == 'Multi\nlines'
    assert issue.column == 11
    assert issue.as_dict() == {
        'analyzer': 'clang-format',
        'column': 11,
        'in_patch': False,
        'is_new': True,
        'line': 1386,
        'nb_lines': 2,
        'patch': 'Multi\nlines',
        'path': 'test.cpp',
        'publishable': False,
        'validates': False,
        'validation': {}
    }
示例#7
0
    def run(self, revision):
        '''
        Build analysis workflows and directly run them
        '''
        issues = []

        # Index ASAP Taskcluster task for this revision
        self.index(revision, state='started')

        # Set the Phabricator build as running
        revision.update_status(state=BuildState.Work)

        # Use remote when we are on try
        if settings.source == SOURCE_TRY:
            remote = RemoteWorkflow(self.queue_service)
            issues += remote.run(revision)

        # Always use local workflow
        # until we have all analyzers in-tree
        local = LocalWorkflow(self, self.analyzers, self.index_service)
        issues += local.run(revision)

        if not issues:
            logger.info('No issues, stopping there.')
            self.index(revision, state='done', issues=0)
            revision.update_status(BuildState.Pass)
            return

        # Publish all issues from both workflows at once
        self.publish(revision, issues)
def test_clang_format_task(mock_try_config, mock_revision):
    '''
    Test a remote workflow with a clang-format analyzer
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow
    from static_analysis_bot.clang.format import ClangFormatIssue

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'deadbeef1234',
            }
        },
        'remoteTryTask': {
            'dependencies': ['clang-format']
        },
        'clang-format': {
            'name': 'source-test-clang-format',
            'state': 'completed',
            'artifacts': {
                'public/code-review/clang-format.json': {
                    'test.cpp': [{
                        'line_offset': 11,
                        'char_offset': 44616,
                        'char_length': 7,
                        'lines_modified': 2,
                        'line': 1386,
                        'replacement': 'Multi\nlines',
                    }]
                }
            }
        }
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    issues = workflow.run(mock_revision)
    assert len(issues) == 1
    issue = issues[0]
    assert isinstance(issue, ClangFormatIssue)
    assert issue.path == 'test.cpp'
    assert issue.line == 1386
    assert issue.nb_lines == 2
    assert issue.patch == 'Multi\nlines'
    assert issue.column == 11
    assert issue.as_dict() == {
        'analyzer': 'clang-format',
        'column': 11,
        'in_patch': False,
        'is_new': True,
        'line': 1386,
        'nb_lines': 2,
        'patch': 'Multi\nlines',
        'path': 'test.cpp',
        'publishable': False,
        'validates': False,
        'validation': {}
    }
示例#9
0
def test_baseline(mock_try_config, mock_revision):
    '''
    Test a normal remote workflow (aka Try mode)
    - current task with analyzer deps
    - an analyzer in failed status
    - with some issues in its log
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow
    from static_analysis_bot.lint import MozLintIssue

    # We run on a mock TC, with a try source
    assert mock_try_config.taskcluster.task_id == 'local instance'
    assert mock_try_config.source == 'try'
    assert mock_try_config.try_task_id == 'remoteTryTask'

    # We do not want to check local files with this worfklow
    mock_try_config.has_local_clone = False

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'deadbeef1234',
            }
        },
        'remoteTryTask': {
            'dependencies': ['analyzer-A', 'analyzer-B']
        },
        'analyzer-A': {
            'name': 'source-test-mozlint-flake8',
            'state': 'failed',
            'artifacts': {
                'failures.log':
                '\n'.join([
                    'something else',
                    'xx123 TEST-UNEXPECTED-ERROR | test.cpp:12:1 | strange issue (checker XXX)',
                ])
            }
        },
        'analyzer-B': {},
        'extra-task': {},
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    issues = workflow.run(mock_revision)

    assert len(issues) == 1
    issue = issues[0]
    assert isinstance(issue, MozLintIssue)
    assert issue.path == 'test.cpp'
    assert issue.line == 12
    assert issue.column == 1
    assert issue.message == 'strange issue'
    assert issue.rule == 'checker XXX'
    assert issue.revision is mock_revision
    assert issue.validates()
示例#10
0
def test_clang_tidy_task(mock_try_config, mock_revision):
    '''
    Test a remote workflow with a clang-tidy analyzer
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow
    from static_analysis_bot.clang.tidy import ClangTidyIssue

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'deadbeef1234',
            }
        },
        'remoteTryTask': {
            'dependencies': ['clang-tidy']
        },
        'clang-tidy': {
            'name': 'source-test-clang-tidy',
            'state': 'completed',
            'artifacts': {
                'public/code-review/clang-tidy.json': {
                    'files': {
                        'test.cpp': {
                            'hash': 'e409f05a10574adb8d47dcb631f8e3bb',
                            'warnings': [
                                {
                                    'column': 12,
                                    'line': 123,
                                    'flag': 'checker.XXX',
                                    'message': 'some hard issue with c++',
                                    'filename': 'test.cpp',
                                }
                            ]
                        }
                    }
                },
            }
        }
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    issues = workflow.run(mock_revision)
    assert len(issues) == 1
    issue = issues[0]
    assert isinstance(issue, ClangTidyIssue)
    assert issue.path == 'test.cpp'
    assert issue.line == 123
    assert issue.char == 12
    assert issue.check == 'checker.XXX'
    assert issue.message == 'some hard issue with c++'
def test_clang_tidy_task(mock_try_config, mock_revision):
    '''
    Test a remote workflow with a clang-tidy analyzer
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow
    from static_analysis_bot.clang.tidy import ClangTidyIssue

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'deadbeef1234',
            }
        },
        'remoteTryTask': {
            'dependencies': ['clang-tidy']
        },
        'clang-tidy': {
            'name': 'source-test-clang-tidy',
            'state': 'completed',
            'artifacts': {
                'public/code-review/clang-tidy.json': {
                    'files': {
                        'test.cpp': {
                            'hash':
                            'e409f05a10574adb8d47dcb631f8e3bb',
                            'warnings': [{
                                'column': 12,
                                'line': 123,
                                'flag': 'checker.XXX',
                                'message': 'some hard issue with c++',
                                'filename': 'test.cpp',
                            }]
                        }
                    }
                },
            }
        }
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    issues = workflow.run(mock_revision)
    assert len(issues) == 1
    issue = issues[0]
    assert isinstance(issue, ClangTidyIssue)
    assert issue.path == 'test.cpp'
    assert issue.line == 123
    assert issue.char == 12
    assert issue.check == 'checker.XXX'
    assert issue.message == 'some hard issue with c++'
示例#12
0
def test_mozlint_task(mock_try_config, mock_revision):
    '''
    Test a remote workflow with a mozlint analyzer
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow
    from static_analysis_bot.lint import MozLintIssue

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'deadbeef1234',
            }
        },
        'remoteTryTask': {
            'dependencies': ['mozlint']
        },
        'mozlint': {
            'name': 'source-test-mozlint-dummy',
            'state': 'failed',
            'artifacts': {
                'public/code-review/mozlint.json': {
                    'test.cpp': [
                        {
                            'path': 'test.cpp',
                            'lineno': 42,
                            'column': 51,
                            'level': 'error',
                            'linter': 'flake8',
                            'rule': 'E001',
                            'message': 'dummy issue',
                        }
                    ]
                },
            }
        }
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    issues = workflow.run(mock_revision)
    assert len(issues) == 1
    issue = issues[0]
    assert isinstance(issue, MozLintIssue)
    assert issue.path == 'test.cpp'
    assert issue.line == 42
    assert issue.column == 51
    assert issue.linter == 'flake8'
    assert issue.message == 'dummy issue'
def test_mozlint_task(mock_try_config, mock_revision):
    '''
    Test a remote workflow with a mozlint analyzer
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow
    from static_analysis_bot.lint import MozLintIssue

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'deadbeef1234',
            }
        },
        'remoteTryTask': {
            'dependencies': ['mozlint']
        },
        'mozlint': {
            'name': 'source-test-mozlint-dummy',
            'state': 'failed',
            'artifacts': {
                'public/code-review/mozlint.json': {
                    'test.cpp': [{
                        'path': 'test.cpp',
                        'lineno': 42,
                        'column': 51,
                        'level': 'error',
                        'linter': 'flake8',
                        'rule': 'E001',
                        'message': 'dummy issue',
                    }]
                },
            }
        }
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    issues = workflow.run(mock_revision)
    assert len(issues) == 1
    issue = issues[0]
    assert isinstance(issue, MozLintIssue)
    assert issue.path == 'test.cpp'
    assert issue.line == 42
    assert issue.column == 51
    assert issue.linter == 'flake8'
    assert issue.message == 'dummy issue'
def test_no_deps(mock_try_config, mock_revision):
    '''
    Test an error occurs when no dependencies are found on root task
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'deadbeef1234',
            }
        },
        'remoteTryTask': {},
        'extra-task': {},
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    with pytest.raises(AssertionError) as e:
        workflow.run(mock_revision)
    assert str(e.value) == 'No task dependencies to analyze'
示例#15
0
def test_no_deps(mock_try_config, mock_revision):
    '''
    Test an error occurs when no dependencies are found on root task
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'deadbeef1234',
            }
        },
        'remoteTryTask': {},
        'extra-task': {},
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    with pytest.raises(AssertionError) as e:
        workflow.run(mock_revision)
    assert str(e.value) == 'No task dependencies to analyze'
示例#16
0
def test_no_failed(mock_try_config, mock_revision):
    '''
    Test a remote workflow without any failed tasks
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'deadbeef1234',
            }
        },
        'remoteTryTask': {
            'dependencies': ['analyzer-A', 'analyzer-B']
        },
        'analyzer-A': {},
        'analyzer-B': {},
        'extra-task': {},
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    issues = workflow.run(mock_revision)
    assert len(issues) == 0
def test_no_failed(mock_try_config, mock_revision):
    '''
    Test a remote workflow without any failed tasks
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'deadbeef1234',
            }
        },
        'remoteTryTask': {
            'dependencies': ['analyzer-A', 'analyzer-B']
        },
        'analyzer-A': {},
        'analyzer-B': {},
        'extra-task': {},
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    issues = workflow.run(mock_revision)
    assert len(issues) == 0
def test_decision_task(mock_try_config, mock_revision):
    '''
    Test a remote workflow with different decision task setup
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow

    tasks = {
        'decision': {},
        'remoteTryTask': {},
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    with pytest.raises(AssertionError) as e:
        workflow.run(mock_revision)
    assert str(e.value) == 'Missing decision task'

    tasks = {
        'decision': {
            'image': 'anotherImage',
        },
        'remoteTryTask': {},
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    with pytest.raises(AssertionError) as e:
        workflow.run(mock_revision)
    assert str(e.value) == 'Missing decision task'

    tasks = {
        'decision': {
            'image': {
                'from': 'taskcluster/decision',
                'tag': 'unsupported',
            }
        },
        'remoteTryTask': {},
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    with pytest.raises(AssertionError) as e:
        workflow.run(mock_revision)
    assert str(e.value) == 'Missing decision task'

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
        },
        'remoteTryTask': {},
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    with pytest.raises(AssertionError) as e:
        workflow.run(mock_revision)
    assert str(e.value) == 'Not the try repo in GECKO_HEAD_REPOSITORY'

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
            }
        },
        'remoteTryTask': {},
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    with pytest.raises(AssertionError) as e:
        workflow.run(mock_revision)
    assert str(e.value) == 'Missing try revision'
    assert mock_revision.mercurial_revision is None

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'someRevision'
            }
        },
        'remoteTryTask': {},
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    with pytest.raises(AssertionError) as e:
        workflow.run(mock_revision)
    assert str(e.value) == 'No task dependencies to analyze'
    assert mock_revision.mercurial_revision is not None
    assert mock_revision.mercurial_revision == 'someRevision'
示例#19
0
def test_decision_task(mock_try_config, mock_revision):
    '''
    Test a remote workflow with different decision task setup
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow

    tasks = {
        'decision': {
        },
        'remoteTryTask': {
        },
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    with pytest.raises(AssertionError) as e:
        workflow.run(mock_revision)
    assert str(e.value) == 'Missing decision task'

    tasks = {
        'decision': {
            'image': 'anotherImage',
        },
        'remoteTryTask': {
        },
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    with pytest.raises(AssertionError) as e:
        workflow.run(mock_revision)
    assert str(e.value) == 'Missing decision task'

    tasks = {
        'decision': {
            'image': {
                'from': 'taskcluster/decision',
                'tag': 'unsupported',
            }
        },
        'remoteTryTask': {
        },
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    with pytest.raises(AssertionError) as e:
        workflow.run(mock_revision)
    assert str(e.value) == 'Missing decision task'

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
        },
        'remoteTryTask': {
        },
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    with pytest.raises(AssertionError) as e:
        workflow.run(mock_revision)
    assert str(e.value) == 'Not the try repo in GECKO_HEAD_REPOSITORY'

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
            }
        },
        'remoteTryTask': {
        },
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    with pytest.raises(AssertionError) as e:
        workflow.run(mock_revision)
    assert str(e.value) == 'Missing try revision'
    assert mock_revision.mercurial_revision is None

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'someRevision'
            }
        },
        'remoteTryTask': {
        },
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    with pytest.raises(AssertionError) as e:
        workflow.run(mock_revision)
    assert str(e.value) == 'No task dependencies to analyze'
    assert mock_revision.mercurial_revision is not None
    assert mock_revision.mercurial_revision == 'someRevision'
示例#20
0
def test_baseline(mock_try_config, mock_revision):
    '''
    Test a normal remote workflow (aka Try mode)
    - current task with analyzer deps
    - an analyzer in failed status
    - with some issues in its log
    '''
    from static_analysis_bot.workflows.remote import RemoteWorkflow
    from static_analysis_bot.lint import MozLintIssue

    # We run on a mock TC, with a try source
    assert mock_try_config.taskcluster.task_id == 'local instance'
    assert mock_try_config.source == 'try'
    assert mock_try_config.try_task_id == 'remoteTryTask'

    # We do not want to check local files with this worfklow
    mock_try_config.has_local_clone = False

    tasks = {
        'decision': {
            'image': 'taskcluster/decision:XXX',
            'env': {
                'GECKO_HEAD_REPOSITORY': 'https://hg.mozilla.org/try',
                'GECKO_HEAD_REV': 'deadbeef1234',
            }
        },
        'remoteTryTask': {
            'dependencies': ['analyzer-A', 'analyzer-B']
        },
        'analyzer-A': {
            'name': 'source-test-mozlint-flake8',
            'state': 'failed',
            'artifacts': {
                'public/code-review/mozlint.json': {
                    'test.cpp': [
                        {
                            'path': 'test.cpp',
                            'lineno': 12,
                            'column': 1,
                            'level': 'error',
                            'linter': 'flake8',
                            'rule': 'checker XXX',
                            'message': 'strange issue',
                        }
                    ]
                },
            }
        },
        'analyzer-B': {},
        'extra-task': {},
    }
    workflow = RemoteWorkflow(MockQueue(tasks))
    issues = workflow.run(mock_revision)

    assert len(issues) == 1
    issue = issues[0]
    assert isinstance(issue, MozLintIssue)
    assert issue.path == 'test.cpp'
    assert issue.line == 12
    assert issue.column == 1
    assert issue.message == 'strange issue'
    assert issue.rule == 'checker XXX'
    assert issue.revision is mock_revision
    assert issue.validates()