import hashlib import hmac import json import unittest from unittest.mock import patch from deploy_webhook import create_app class WebhookTest(unittest.TestCase): def setUp(self): self.process = None self.app = create_app({ "TESTING": True, "WEBHOOK_SECRET": "webhook-secret", "REPOSITORY": "KingHWJ/WeReadBoard", "BRANCH": "master", "PROJECT_DIR": "/srv/weread", "DEPLOY_SCRIPT": "deploy.sh", }) self.client = self.app.test_client() @staticmethod def signed(payload): body = json.dumps(payload, separators=(",", ":")).encode() signature = hmac.new(b"webhook-secret", body, hashlib.sha256).hexdigest() return body, { "Content-Type": "application/json", "X-GitHub-Event": "push", "X-Hub-Signature-256": f"sha256={signature}", } def test_health_is_available(self): self.assertEqual(self.client.get("/health").status_code, 200) def test_invalid_signature_is_rejected(self): response = self.client.post( "/github/webhook", data=b"{}", headers={"X-GitHub-Event": "push", "X-Hub-Signature-256": "sha256=bad"}, ) self.assertEqual(response.status_code, 401) @patch("deploy_webhook.subprocess.Popen") def test_only_matching_master_push_starts_deployment(self, popen): payload = {"ref": "refs/heads/master", "repository": {"full_name": "KingHWJ/WeReadBoard"}} body, headers = self.signed(payload) response = self.client.post("/github/webhook", data=body, headers=headers) self.assertEqual(response.status_code, 202) self.assertEqual(response.json["status"], "accepted") popen.assert_called_once() self.assertEqual(popen.call_args.args[0], ["/srv/weread/deploy.sh"]) @patch("deploy_webhook.subprocess.Popen") def test_dev_push_does_not_start_deployment(self, popen): payload = {"ref": "refs/heads/dev", "repository": {"full_name": "KingHWJ/WeReadBoard"}} body, headers = self.signed(payload) response = self.client.post("/github/webhook", data=body, headers=headers) self.assertEqual(response.status_code, 202) popen.assert_not_called() @patch("deploy_webhook.subprocess.Popen") def test_duplicate_push_is_not_started_while_deploying(self, popen): popen.return_value.poll.return_value = None payload = {"ref": "refs/heads/master", "repository": {"full_name": "KingHWJ/WeReadBoard"}} body, headers = self.signed(payload) self.assertEqual(self.client.post("/github/webhook", data=body, headers=headers).json["status"], "accepted") response = self.client.post("/github/webhook", data=body, headers=headers) self.assertEqual(response.json["status"], "already_deploying") popen.assert_called_once() if __name__ == "__main__": unittest.main()