diff options
-rw-r--r-- | test/samples/github-push.test-case.json | 182 | ||||
-rw-r--r-- | test/samples/gitlab-push.test-case.json | 110 | ||||
-rw-r--r-- | test/stubs/__init__.py | 0 | ||||
-rw-r--r-- | test/stubs/git.py | 16 | ||||
-rw-r--r-- | test/stubs/process.py | 6 | ||||
-rw-r--r-- | test/test_parsers.py | 85 | ||||
-rw-r--r-- | test/utils.py | 108 |
7 files changed, 507 insertions, 0 deletions
diff --git a/test/samples/github-push.test-case.json b/test/samples/github-push.test-case.json new file mode 100644 index 0000000..dbc9ccf --- /dev/null +++ b/test/samples/github-push.test-case.json @@ -0,0 +1,182 @@ +{ + "config": { + "branch": "master", + "deploy": "echo test!", + "remote": "origin", + "url": "https://github.com/olipo186/Git-Auto-Deploy.git" + }, + "expected": { + "status": 200, + "data": [ + { + "deploy": 0 + } + ] + }, + "headers": { + "accept": "*/*", + "content-length": "6602", + "content-type": "application/json", + "host": "narpau.se:8001", + "user-agent": "GitHub-Hookshot/e4028f5", + "x-github-delivery": "xxx", + "x-github-event": "push", + "x-hub-signature": "xxx" + }, + "payload": { + "after": "b60ff44438d884b200d70de9c45fec5a15f2c0fa", + "base_ref": null, + "before": "6aa6dd514d5b80c9f36fec6c56d4094fd182de61", + "commits": [ + { + "added": [], + "author": { + "email": "oliver@poignant.se", + "name": "Oliver Poignant", + "username": "olipo186" + }, + "committer": { + "email": "oliver@poignant.se", + "name": "Oliver Poignant", + "username": "olipo186" + }, + "distinct": true, + "id": "b60ff44438d884b200d70de9c45fec5a15f2c0fa", + "message": "Updated docs", + "modified": [ + "gitautodeploy/httpserver.py" + ], + "removed": [], + "timestamp": "2016-05-08T00:08:09+02:00", + "tree_id": "af9230d6223d6f6849b0f86ff7b5bef8b777a85b", + "url": "https://github.com/olipo186/Git-Auto-Deploy/commit/b60ff44438d884b200d70de9c45fec5a15f2c0fa" + } + ], + "compare": "https://github.com/olipo186/Git-Auto-Deploy/compare/6aa6dd514d5b...b60ff44438d8", + "created": false, + "deleted": false, + "forced": false, + "head_commit": { + "added": [], + "author": { + "email": "oliver@poignant.se", + "name": "Oliver Poignant", + "username": "olipo186" + }, + "committer": { + "email": "oliver@poignant.se", + "name": "Oliver Poignant", + "username": "olipo186" + }, + "distinct": true, + "id": "b60ff44438d884b200d70de9c45fec5a15f2c0fa", + "message": "Updated docs", + "modified": [ + "gitautodeploy/httpserver.py" + ], + "removed": [], + "timestamp": "2016-05-08T00:08:09+02:00", + "tree_id": "af9230d6223d6f6849b0f86ff7b5bef8b777a85b", + "url": "https://github.com/olipo186/Git-Auto-Deploy/commit/b60ff44438d884b200d70de9c45fec5a15f2c0fa" + }, + "pusher": { + "email": "oliver@poignant.se", + "name": "olipo186" + }, + "ref": "refs/heads/master", + "repository": { + "archive_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/{archive_format}{/ref}", + "assignees_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/assignees{/user}", + "blobs_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/branches{/branch}", + "clone_url": "https://github.com/olipo186/Git-Auto-Deploy.git", + "collaborators_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/comments{/number}", + "commits_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/commits{/sha}", + "compare_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/contents/{+path}", + "contributors_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/contributors", + "created_at": 1370546738, + "default_branch": "master", + "deployments_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/deployments", + "description": "Deploy your GitHub, GitLab or Bitbucket projects automatically on Git push events or webhooks using this small HTTP server written in Python. Continuous deployment in it's most simple form.", + "downloads_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/downloads", + "events_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/events", + "fork": false, + "forks": 71, + "forks_count": 71, + "forks_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/forks", + "full_name": "olipo186/Git-Auto-Deploy", + "git_commits_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/git/tags{/sha}", + "git_url": "git://github.com/olipo186/Git-Auto-Deploy.git", + "has_downloads": true, + "has_issues": true, + "has_pages": true, + "has_wiki": true, + "homepage": "http://olipo186.github.io/Git-Auto-Deploy/", + "hooks_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/hooks", + "html_url": "https://github.com/olipo186/Git-Auto-Deploy", + "id": 10534595, + "issue_comment_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/issues/comments{/number}", + "issue_events_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/issues/events{/number}", + "issues_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/issues{/number}", + "keys_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/keys{/key_id}", + "labels_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/labels{/name}", + "language": "Python", + "languages_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/languages", + "master_branch": "master", + "merges_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/merges", + "milestones_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/milestones{/number}", + "mirror_url": null, + "name": "Git-Auto-Deploy", + "notifications_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/notifications{?since,all,participating}", + "open_issues": 9, + "open_issues_count": 9, + "owner": { + "email": "oliver@poignant.se", + "name": "olipo186" + }, + "private": false, + "pulls_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/pulls{/number}", + "pushed_at": 1462658898, + "releases_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/releases{/id}", + "size": 502, + "ssh_url": "git@github.com:olipo186/Git-Auto-Deploy.git", + "stargazers": 259, + "stargazers_count": 259, + "stargazers_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/stargazers", + "statuses_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/statuses/{sha}", + "subscribers_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/subscribers", + "subscription_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/subscription", + "svn_url": "https://github.com/olipo186/Git-Auto-Deploy", + "tags_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/tags", + "teams_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/teams", + "trees_url": "https://api.github.com/repos/olipo186/Git-Auto-Deploy/git/trees{/sha}", + "updated_at": "2016-05-07T11:10:07Z", + "url": "https://github.com/olipo186/Git-Auto-Deploy", + "watchers": 259, + "watchers_count": 259 + }, + "sender": { + "avatar_url": "https://avatars.githubusercontent.com/u/1056476?v=3", + "events_url": "https://api.github.com/users/olipo186/events{/privacy}", + "followers_url": "https://api.github.com/users/olipo186/followers", + "following_url": "https://api.github.com/users/olipo186/following{/other_user}", + "gists_url": "https://api.github.com/users/olipo186/gists{/gist_id}", + "gravatar_id": "", + "html_url": "https://github.com/olipo186", + "id": 1056476, + "login": "olipo186", + "organizations_url": "https://api.github.com/users/olipo186/orgs", + "received_events_url": "https://api.github.com/users/olipo186/received_events", + "repos_url": "https://api.github.com/users/olipo186/repos", + "site_admin": false, + "starred_url": "https://api.github.com/users/olipo186/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/olipo186/subscriptions", + "type": "User", + "url": "https://api.github.com/users/olipo186" + } + } +}
\ No newline at end of file diff --git a/test/samples/gitlab-push.test-case.json b/test/samples/gitlab-push.test-case.json new file mode 100644 index 0000000..3c8b0d9 --- /dev/null +++ b/test/samples/gitlab-push.test-case.json @@ -0,0 +1,110 @@ +{ + "config": { + "branch": "master", + "deploy": "echo test!", + "remote": "origin", + "url": "http://gitlab.example.com/oliver/poignant-se.git" + }, + "expected": { + "status": 200, + "data": [ + { + "deploy": 0 + } + ] + }, + "headers": { + "connection": "close", + "content-length": "2336", + "content-type": "application/json", + "host": "example.com:8001", + "x-gitlab-event": "Push Hook" + }, + "payload": { + "after": "bb26e21adb5a97d3f7b45d0c29506d52793c8f3b", + "before": "fdd525130a91991648783608f9d55c359ed41abf", + "checkout_sha": "bb26e21adb5a97d3f7b45d0c29506d52793c8f3b", + "commits": [ + { + "added": [], + "author": { + "email": "oliver@poignant.se", + "name": "Oliver Poignant" + }, + "id": "bb26e21adb5a97d3f7b45d0c29506d52793c8f3b", + "message": "aa", + "modified": [ + "README.md" + ], + "removed": [], + "timestamp": "2016-04-14T00:19:23+02:00", + "url": "http://gitlab.example.com/oliver/poignant-se/commit/bb26e21adb5a97d3f7b45d0c29506d52793c8f3b" + }, + { + "added": [], + "author": { + "email": "oliver@poignant.se", + "name": "Oliver Poignant" + }, + "id": "dcfccd6cb19ef50c6b7e27a657f9e37bd041a913", + "message": "ss", + "modified": [ + "README.md" + ], + "removed": [], + "timestamp": "2016-04-14T00:18:53+02:00", + "url": "http://gitlab.example.com/oliver/poignant-se/commit/dcfccd6cb19ef50c6b7e27a657f9e37bd041a913" + }, + { + "added": [], + "author": { + "email": "oliver@poignant.se", + "name": "Oliver Poignant" + }, + "id": "fdd525130a91991648783608f9d55c359ed41abf", + "message": "aa", + "modified": [ + "README.md" + ], + "removed": [], + "timestamp": "2016-04-14T00:08:43+02:00", + "url": "http://gitlab.example.com/oliver/poignant-se/commit/fdd525130a91991648783608f9d55c359ed41abf" + } + ], + "event_name": "push", + "message": null, + "object_kind": "push", + "project": { + "avatar_url": null, + "default_branch": "master", + "description": "", + "git_http_url": "http://gitlab.example.com/oliver/poignant-se.git", + "git_ssh_url": "ssh://git@example.com/oliver/poignant-se.git", + "homepage": "http://gitlab.example.com/oliver/poignant-se", + "http_url": "http://gitlab.example.com/oliver/poignant-se.git", + "name": "poignant-se", + "namespace": "oliver", + "path_with_namespace": "oliver/poignant-se", + "ssh_url": "ssh://git@example.com/oliver/poignant-se.git", + "url": "ssh://git@example.com/oliver/poignant-se.git", + "visibility_level": 0, + "web_url": "http://gitlab.example.com/oliver/poignant-se" + }, + "project_id": 28, + "ref": "refs/heads/master", + "repository": { + "description": "", + "git_http_url": "http://gitlab.example.com/oliver/poignant-se.git", + "git_ssh_url": "ssh://git@example.com/oliver/poignant-se.git", + "homepage": "http://gitlab.example.com/oliver/poignant-se", + "name": "poignant-se", + "url": "ssh://git@example.com/oliver/poignant-se.git", + "visibility_level": 0 + }, + "total_commits_count": 3, + "user_avatar": "http://www.gravatar.com/avatar/bdf723d6a6f847ec075a6809aa4808fb?s=80&d=identicon", + "user_email": "oliver@poignant.se", + "user_id": 7, + "user_name": "Oliver Poignant" + } +}
\ No newline at end of file diff --git a/test/stubs/__init__.py b/test/stubs/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/stubs/__init__.py diff --git a/test/stubs/git.py b/test/stubs/git.py new file mode 100644 index 0000000..d023a51 --- /dev/null +++ b/test/stubs/git.py @@ -0,0 +1,16 @@ +class GitWrapper(object): + + @staticmethod + def pull(*args, **kwargs): + """Fake git pull""" + return 0 + + @staticmethod + def clone(*args, **kwargs): + """Fake git clone""" + return 0 + + @staticmethod + def deploy(*args, **kwargs): + """Fake deploy""" + return 0 diff --git a/test/stubs/process.py b/test/stubs/process.py new file mode 100644 index 0000000..8695c96 --- /dev/null +++ b/test/stubs/process.py @@ -0,0 +1,6 @@ +class ProcessWrapper(): + + @staticmethod + def call(*args, **kwargs): + """Fake process call""" + return 0 diff --git a/test/test_parsers.py b/test/test_parsers.py new file mode 100644 index 0000000..a5ba65f --- /dev/null +++ b/test/test_parsers.py @@ -0,0 +1,85 @@ +import unittest +from utils import WebhookTestCaseBase + +class WebhookTestCase(WebhookTestCaseBase): + + test_case = None + test_name = None + + def set_test_case(self, test_case, test_name): + self.test_case = test_case + self.test_name = test_name + + def shortDescription(self): + return self.test_name + + def runTest(self): + import requests + import json + + # GAD configuration for this test case + config = { + 'port': 0, + 'intercept-stdout': False, + 'detailed-response': True, + 'log-level': 'WARNING', + 'log-test-case': True, + 'repositories': [] + } + + if 'url' in self.test_case['config']: + config['repositories'].append(self.test_case['config']) + + # Start GAD instance + self.start_gad(config) + + # Send webhook request + session = requests.session() + response = requests.post('http://localhost:%s/' % self.gad_port(), data=json.dumps(self.test_case['payload']), headers=self.test_case['headers']) + + # Verify response status + self.assertEqual(response.status_code, self.test_case['expected']['status']) + + # Compare results + if 'data' in self.test_case['expected'] and self.test_case['expected']['data']: + actual = json.dumps(response.json()) + expected = json.dumps(self.test_case['expected']['data']) + self.assertEqual(actual, expected) + + # Wait for GAD to handle the request + self.await_gad() + +def suite(): + import os + import json + + suite = unittest.TestSuite() + + # Look for test cases in samples dir + samples_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'samples') + for item in os.listdir(samples_dir): + + if not item[-15:] == '.test-case.json': + continue + + file = open(os.path.join(samples_dir, item), 'r') + test_case = json.loads(file.read()) + + t = WebhookTestCase() + t.set_test_case(test_case, item) + + suite.addTest(t) + + return suite + +if __name__ == '__main__': + from unittest import TestResult + #result = TestResult() + + #suite().run(result) + #unittest.main() + #print result + + suite = suite() + result = unittest.TextTestRunner(verbosity=2).run(suite) + diff --git a/test/utils.py b/test/utils.py new file mode 100644 index 0000000..a686485 --- /dev/null +++ b/test/utils.py @@ -0,0 +1,108 @@ +import unittest + +class WebhookTestCaseBase(unittest.TestCase): + + thread = None + + def setUp(self): + import sys + + # Use our custom importer to replace certain modules with stub modules to + # enable testing of other parts of GAD + sys.meta_path.append(StubImporter()) + + def start_gad(self, test_config): + import sys + import time + sys.path.insert(1, '..') + + from gitautodeploy.cli.config import get_config_defaults, init_config + + config = get_config_defaults() + config.update(test_config) + + init_config(config) + + # Create a GAD instance + self.thread = GADRunnerThread(config) + + # Run GAD in a thread + self.thread.start() + + def gad_port(self): + return self.thread.port + + def await_gad(self): + """Waits for GAD and all it's threads to complete.""" + import threading + + # Wait for GAD runner thread to finish + self.thread.join() + + # Wait for all request handler threads to finish + main_thread = threading.currentThread() + for current_thread in threading.enumerate(): + if current_thread == main_thread: + continue + #print "Waiting for thread %s to finish" % current_thread + current_thread.join() + + def tearDown(self): + pass + + +class StubImporter(object): + + overload_modules = ['gitautodeploy.wrappers.git', 'gitautodeploy.wrappers.process'] + + def find_module(self, full_name, package_path): + + # Intervene when any wrapper module is imported + if full_name in self.overload_modules: + + # Return a loader + return self + + return None + + def load_module(self, full_name): + """Load matching module from stubs package (test stub) instead of main gitautodeploy package.""" + import imp + import sys + + module_name = full_name.split('.')[-1] + module_info = imp.find_module(module_name, ['stubs']) + module = imp.load_module(module_name, *module_info) + sys.modules[module_name] = module + +# print "returning module %s" % module_name + +# module.history.append('WAH') + + # Return a module + return module + + +import threading + +class GADRunnerThread(threading.Thread): + def __init__(self, config): + super(GADRunnerThread, self).__init__() + import sys + import time + + from gitautodeploy import GitAutoDeploy + + self._app = GitAutoDeploy() + self._app.setup(config) + + # Store PID and port in thread instance + self.pid = self._app._pid + self.port = self._app._port + + def run(self): + self._app.handle_request() + + def exit(self): + self._app.stop() + self._app.close() |