From 497c90e7ea90e21870af67d8e28c7e49eaacf230 Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Mon, 13 Feb 2017 15:01:09 -0500 Subject: [PATCH] Add unit testing of bitbucket trigger handler --- buildtrigger/bitbuckethandler.py | 9 +- buildtrigger/githubhandler.py | 1 + buildtrigger/test/bitbucketmock.py | 161 +++++++++++++++++++++ buildtrigger/test/githubmock.py | 6 +- buildtrigger/test/test_bitbuckethandler.py | 32 ++-- buildtrigger/test/test_githosthandler.py | 48 +++--- buildtrigger/test/test_githubhandler.py | 11 ++ 7 files changed, 217 insertions(+), 51 deletions(-) create mode 100644 buildtrigger/test/bitbucketmock.py diff --git a/buildtrigger/bitbuckethandler.py b/buildtrigger/bitbuckethandler.py index f96a38cee..33c890083 100644 --- a/buildtrigger/bitbuckethandler.py +++ b/buildtrigger/bitbuckethandler.py @@ -412,7 +412,8 @@ class BitbucketBuildTrigger(BuildTriggerHandler): 'id': owner, 'title': owner, 'avatar_url': repo['logo'], - 'score': 0, + 'url': 'https://bitbucket.org/%s' % (owner), + 'score': 1, } return list(namespaces.values()) @@ -464,7 +465,7 @@ class BitbucketBuildTrigger(BuildTriggerHandler): (result, data, err_msg) = repository.get_raw_path_contents(path, revision='master') if not result: - raise RepositoryReadException(err_msg) + return None return data @@ -541,7 +542,7 @@ class BitbucketBuildTrigger(BuildTriggerHandler): # Lookup the commit SHA for the branch. (result, data, _) = repository.get_branch(branch_name) if not result: - raise TriggerStartException('Could not find branch commit SHA') + raise TriggerStartException('Could not find branch in repository') return data['target']['hash'] @@ -549,7 +550,7 @@ class BitbucketBuildTrigger(BuildTriggerHandler): # Lookup the commit SHA for the tag. (result, data, _) = repository.get_tag(tag_name) if not result: - raise TriggerStartException('Could not find tag commit SHA') + raise TriggerStartException('Could not find tag in repository') return data['target']['hash'] diff --git a/buildtrigger/githubhandler.py b/buildtrigger/githubhandler.py index a51526507..3233f5f5d 100644 --- a/buildtrigger/githubhandler.py +++ b/buildtrigger/githubhandler.py @@ -286,6 +286,7 @@ class GithubBuildTrigger(BuildTriggerHandler): 'id': usr.login, 'title': usr.name or usr.login, 'avatar_url': usr.avatar_url, + 'url': usr.html_url, 'score': usr.plan.private_repos if usr.plan else 0, } diff --git a/buildtrigger/test/bitbucketmock.py b/buildtrigger/test/bitbucketmock.py new file mode 100644 index 000000000..c442f20dd --- /dev/null +++ b/buildtrigger/test/bitbucketmock.py @@ -0,0 +1,161 @@ +from datetime import datetime +from mock import Mock + +from buildtrigger.bitbuckethandler import BitbucketBuildTrigger +from util.morecollections import AttrDict + +def get_bitbucket_trigger(subdir=''): + trigger_obj = AttrDict(dict(auth_token='foobar', id='sometrigger')) + trigger = BitbucketBuildTrigger(trigger_obj, { + 'build_source': 'foo/bar', + 'subdir': subdir, + 'username': 'knownuser' + }) + + trigger._get_client = get_mock_bitbucket + return trigger + +def get_repo_path_contents(path, revision): + if revision != 'master': + return (False, None, None) + + data = { + 'files': [{'path': 'Dockerfile'}], + } + + return (True, data, None) + +def get_raw_path_contents(path, revision): + if path == '/Dockerfile': + return (True, 'hello world', None) + + if path == 'somesubdir/Dockerfile': + return (True, 'hi universe', None) + + return (False, None, None) + +def get_branches_and_tags(): + data = { + 'branches': [{'name': 'master'}, {'name': 'otherbranch'}], + 'tags': [{'name': 'sometag'}, {'name': 'someothertag'}], + } + return (True, data, None) + +def get_branches(): + return (True, {'master': {}, 'otherbranch': {}}, None) + +def get_tags(): + return (True, {'sometag': {}, 'someothertag': {}}, None) + +def get_branch(branch_name): + if branch_name != 'master': + return (False, None, None) + + data = { + 'target': { + 'hash': 'aaaaaaa', + }, + } + + return (True, data, None) + +def get_tag(tag_name): + if tag_name != 'sometag': + return (False, None, None) + + data = { + 'target': { + 'hash': 'aaaaaaa', + }, + } + + return (True, data, None) + +def get_changeset_mock(commit_sha): + if commit_sha != 'aaaaaaa': + return (False, None, 'Not found') + + data = { + 'node': 'aaaaaaa', + 'message': 'some message', + 'timestamp': 'now', + 'raw_author': 'foo@bar.com', + } + + return (True, data, None) + +def get_changesets(): + changesets_mock = Mock() + changesets_mock.get = Mock(side_effect=get_changeset_mock) + return changesets_mock + +def get_deploykeys(): + deploykeys_mock = Mock() + deploykeys_mock.create = Mock(return_value=(True, {'pk': 'someprivatekey'}, None)) + deploykeys_mock.delete = Mock(return_value=(True, {}, None)) + return deploykeys_mock + +def get_webhooks(): + webhooks_mock = Mock() + webhooks_mock.create = Mock(return_value=(True, {'uuid': 'someuuid'}, None)) + webhooks_mock.delete = Mock(return_value=(True, {}, None)) + return webhooks_mock + +def get_repo_mock(name): + if name != 'bar': + return None + + repo_mock = Mock() + repo_mock.get_main_branch = Mock(return_value=(True, {'name': 'master'}, None)) + repo_mock.get_path_contents = Mock(side_effect=get_repo_path_contents) + repo_mock.get_raw_path_contents = Mock(side_effect=get_raw_path_contents) + repo_mock.get_branches_and_tags = Mock(side_effect=get_branches_and_tags) + repo_mock.get_branches = Mock(side_effect=get_branches) + repo_mock.get_tags = Mock(side_effect=get_tags) + repo_mock.get_branch = Mock(side_effect=get_branch) + repo_mock.get_tag = Mock(side_effect=get_tag) + + repo_mock.changesets = Mock(side_effect=get_changesets) + repo_mock.deploykeys = Mock(side_effect=get_deploykeys) + repo_mock.webhooks = Mock(side_effect=get_webhooks) + return repo_mock + +def get_repositories_mock(): + repos_mock = Mock() + repos_mock.get = Mock(side_effect=get_repo_mock) + return repos_mock + +def get_namespace_mock(namespace): + namespace_mock = Mock() + namespace_mock.repositories = Mock(side_effect=get_repositories_mock) + return namespace_mock + +def get_repo(namespace, name): + return { + 'owner': namespace, + 'logo': 'avatarurl', + 'slug': name, + 'description': 'some %s repo' % (name), + 'utc_last_updated': str(datetime.utcfromtimestamp(0)), + 'read_only': namespace != 'knownuser', + 'is_private': name == 'somerepo', + } + +def get_visible_repos(): + repos = [ + get_repo('knownuser', 'somerepo'), + get_repo('someorg', 'somerepo'), + get_repo('someorg', 'anotherrepo'), + ] + return (True, repos, None) + +def get_authed_mock(token, secret): + authed_mock = Mock() + authed_mock.for_namespace = Mock(side_effect=get_namespace_mock) + authed_mock.get_visible_repositories = Mock(side_effect=get_visible_repos) + return authed_mock + +def get_mock_bitbucket(): + bitbucket_mock = Mock() + bitbucket_mock.get_authorized_client = Mock(side_effect=get_authed_mock) + return bitbucket_mock diff --git a/buildtrigger/test/githubmock.py b/buildtrigger/test/githubmock.py index a5b22bf87..77c8a7a1f 100644 --- a/buildtrigger/test/githubmock.py +++ b/buildtrigger/test/githubmock.py @@ -54,7 +54,7 @@ def get_mock_github(): repo_mock.name = name repo_mock.description = 'some %s repo' % (name) repo_mock.pushed_at = datetime.utcfromtimestamp(0) - repo_mock.html_url = 'http://some/url' + repo_mock.html_url = 'https://bitbucket.org/%s/%s' % (namespace, name) repo_mock.private = name == 'somerepo' repo_mock.permissions = Mock() repo_mock.permissions.admin = namespace == 'knownuser' @@ -76,7 +76,7 @@ def get_mock_github(): user_mock.plan = Mock() user_mock.plan.private_repos = 1 user_mock.login = username - user_mock.html_url = 'htmlurl' + user_mock.html_url = 'https://bitbucket.org/%s' % (username) user_mock.avatar_url = 'avatarurl' user_mock.get_repos = Mock(side_effect=get_user_repos_mock) user_mock.get_orgs = Mock(side_effect=get_orgs_mock) @@ -89,7 +89,7 @@ def get_mock_github(): org_mock = Mock() org_mock.get_repos = Mock(side_effect=get_org_repos_mock) org_mock.login = namespace - org_mock.html_url = 'htmlurl' + org_mock.html_url = 'https://bitbucket.org/%s' % (namespace) org_mock.avatar_url = 'avatarurl' org_mock.name = namespace org_mock.plan = Mock() diff --git a/buildtrigger/test/test_bitbuckethandler.py b/buildtrigger/test/test_bitbuckethandler.py index b95619bf6..991d90af1 100644 --- a/buildtrigger/test/test_bitbuckethandler.py +++ b/buildtrigger/test/test_bitbuckethandler.py @@ -1,24 +1,22 @@ import pytest -from mock import Mock -from datetime import datetime - -from buildtrigger.bitbuckethandler import BitbucketBuildTrigger -from buildtrigger.triggerutil import (InvalidPayloadException, SkipRequestException, - TriggerStartException, ValidationRequestException) -from endpoints.building import PreparedBuild -from util.morecollections import AttrDict +from buildtrigger.test.bitbucketmock import get_bitbucket_trigger @pytest.fixture def bitbucket_trigger(): - return _get_bitbucket_trigger() + return get_bitbucket_trigger() -def get_mock_bitbucket(): - client_mock = Mock() - return client_mock -def _get_bitbucket_trigger(subdir=''): - trigger_obj = AttrDict(dict(auth_token='foobar', id='sometrigger')) - trigger = BitbucketBuildTrigger(trigger_obj, {'build_source': 'foo/bar', 'subdir': subdir}) - trigger._get_client = get_mock_bitbucket - return trigger +def test_list_build_subdirs(bitbucket_trigger): + assert bitbucket_trigger.list_build_subdirs() == [''] + + +@pytest.mark.parametrize('subdir, contents', [ + ('', 'hello world'), + ('somesubdir', 'hi universe'), + ('unknownpath', None), +]) +def test_load_dockerfile_contents(subdir, contents): + trigger = get_bitbucket_trigger(subdir) + assert trigger.load_dockerfile_contents() == contents + diff --git a/buildtrigger/test/test_githosthandler.py b/buildtrigger/test/test_githosthandler.py index 6ed25bf4f..04b87fa3c 100644 --- a/buildtrigger/test/test_githosthandler.py +++ b/buildtrigger/test/test_githosthandler.py @@ -1,13 +1,11 @@ import pytest from buildtrigger.triggerutil import TriggerStartException +from buildtrigger.test.bitbucketmock import get_bitbucket_trigger from buildtrigger.test.githubmock import get_github_trigger from endpoints.building import PreparedBuild -def github_trigger(): - return get_github_trigger() - -@pytest.fixture(params=[github_trigger()]) +@pytest.fixture(params=[get_github_trigger(), get_bitbucket_trigger()]) def githost_trigger(request): return request.param @@ -38,14 +36,6 @@ def test_manual_start(run_parameters, expected_error, expected_message, githost_ assert isinstance(githost_trigger.manual_start(run_parameters), PreparedBuild) -@pytest.mark.parametrize('username, expected_response', [ - ('unknownuser', None), - ('knownuser', {'html_url': 'htmlurl', 'avatar_url': 'avatarurl'}), -]) -def test_lookup_user(username, expected_response, githost_trigger): - assert githost_trigger.lookup_user(username) == expected_response - - @pytest.mark.parametrize('name, expected', [ ('refs', [ {'kind': 'branch', 'name': 'master'}, @@ -53,16 +43,17 @@ def test_lookup_user(username, expected_response, githost_trigger): {'kind': 'tag', 'name': 'sometag'}, {'kind': 'tag', 'name': 'someothertag'}, ]), - ('tag_name', ['sometag', 'someothertag']), - ('branch_name', ['master', 'otherbranch']), + ('tag_name', set(['sometag', 'someothertag'])), + ('branch_name', set(['master', 'otherbranch'])), ('invalid', None) ]) def test_list_field_values(name, expected, githost_trigger): - assert githost_trigger.list_field_values(name) == expected - - -def test_list_build_subdirs(githost_trigger): - assert githost_trigger.list_build_subdirs() == ['', 'somesubdir'] + if expected is None: + assert githost_trigger.list_field_values(name) is None + elif isinstance(expected, set): + assert set(githost_trigger.list_field_values(name)) == set(expected) + else: + assert githost_trigger.list_field_values(name) == expected def test_list_build_source_namespaces(githost_trigger): @@ -72,13 +63,14 @@ def test_list_build_source_namespaces(githost_trigger): 'score': 1, 'avatar_url': 'avatarurl', 'id': 'knownuser', - 'title': 'knownuser' + 'title': 'knownuser', + 'url': 'https://bitbucket.org/knownuser', }, { 'score': 2, 'title': 'someorg', 'personal': False, - 'url': 'htmlurl', + 'url': 'https://bitbucket.org/someorg', 'avatar_url': 'avatarurl', 'id': 'someorg' } @@ -92,20 +84,23 @@ def test_list_build_source_namespaces(githost_trigger): ('knownuser', [ { - 'last_updated': 0, 'name': 'somerepo', 'url': 'http://some/url', 'private': True, + 'last_updated': 0, 'name': 'somerepo', + 'url': 'https://bitbucket.org/knownuser/somerepo', 'private': True, 'full_name': 'knownuser/somerepo', 'has_admin_permissions': True, 'description': 'some somerepo repo' }]), ('someorg', [ { - 'last_updated': 0, 'name': 'somerepo', 'url': 'http://some/url', - 'private': True, 'full_name': 'someorg/somerepo', 'has_admin_permissions': False, + 'last_updated': 0, 'name': 'somerepo', + 'url': 'https://bitbucket.org/someorg/somerepo', 'private': True, + 'full_name': 'someorg/somerepo', 'has_admin_permissions': False, 'description': 'some somerepo repo' }, { - 'last_updated': 0, 'name': 'anotherrepo', 'url': 'http://some/url', - 'private': False, 'full_name': 'someorg/anotherrepo', 'has_admin_permissions': False, + 'last_updated': 0, 'name': 'anotherrepo', + 'url': 'https://bitbucket.org/someorg/anotherrepo', 'private': False, + 'full_name': 'someorg/anotherrepo', 'has_admin_permissions': False, 'description': 'some anotherrepo repo' }]), ]) @@ -117,7 +112,6 @@ def test_list_build_sources_for_namespace(namespace, expected, githost_trigger): def test_activate(githost_trigger): config, private_key = githost_trigger.activate('http://some/url') assert 'deploy_key_id' in config - assert 'hook_id' in config assert 'private_key' in private_key diff --git a/buildtrigger/test/test_githubhandler.py b/buildtrigger/test/test_githubhandler.py index aa2fdd244..5f9a1d786 100644 --- a/buildtrigger/test/test_githubhandler.py +++ b/buildtrigger/test/test_githubhandler.py @@ -76,3 +76,14 @@ def test_load_dockerfile_contents(subdir, contents): trigger = get_github_trigger(subdir) assert trigger.load_dockerfile_contents() == contents + +@pytest.mark.parametrize('username, expected_response', [ + ('unknownuser', None), + ('knownuser', {'html_url': 'https://bitbucket.org/knownuser', 'avatar_url': 'avatarurl'}), +]) +def test_lookup_user(username, expected_response, github_trigger): + assert github_trigger.lookup_user(username) == expected_response + + +def test_list_build_subdirs(github_trigger): + assert github_trigger.list_build_subdirs() == ['', 'somesubdir']