def test_app_event_testing(): with open( os.path.join(os.path.dirname(__file__), "events", "push_event.json"), "rb" ) as f: data = f.read() headers = { "X-GitHub-Delivery": str(uuid.uuid4()), "X-GitHub-Event": "push", "X-Hub-Signature": "sha1=%s" % utils.compute_hmac(data), "User-Agent": "GitHub-Hookshot/044aadd", "Content-Type": "application/json", } with testclient.TestClient(web.app) as client: client.delete("/events-testing", data=data, headers=headers) client.post("/events-testing", data=data, headers=headers) client.post("/events-testing", data=data, headers=headers) client.post("/events-testing", data=data, headers=headers) client.post("/events-testing", data=data, headers=headers) client.post("/events-testing", data=data, headers=headers) events = client.get( "/events-testing?number=3", data=data, headers=headers ).json() assert 3 == len(events) events = client.get("/events-testing", data=data, headers=headers).json() assert 2 == len(events) events = client.get("/events-testing", data=data, headers=headers).json() assert 0 == len(events) client.post("/events-testing", data=data, headers=headers) client.delete("/events-testing", data=data, headers=headers) events = client.get("/events-testing", data=data, headers=headers).json() assert 0 == len(events)
def test_tokens_cache_delete() -> None: owner_id = 123 headers = {"Authorization": f"Bearer {config.DASHBOARD_TO_ENGINE_API_KEY}"} with testclient.TestClient(root.app) as client: reply = client.delete(f"/tokens-cache/{owner_id}", headers=headers) assert reply.status_code == 200 assert reply.content == b"Cache cleaned"
def test_market_event_forward(_, __, httpserver): with open( os.path.join(os.path.dirname(__file__), "events", "market_event.json")) as f: data = f.read() headers = { "X-GitHub-Delivery": str(uuid.uuid4()), "X-GitHub-Event": "purchased", "X-Hub-Signature": "sha1=%s" % utils.compute_hmac(data.encode()), "User-Agent": "GitHub-Hookshot/044aadd", "Content-Type": "application/json", } httpserver.expect_request("/", method="POST", data=data, headers=headers).respond_with_data("") with mock.patch( "mergify_engine.config.WEBHOOK_MARKETPLACE_FORWARD_URL", httpserver.url_for("/"), ): with testclient.TestClient(web.app) as client: client.post("/marketplace", data=data, headers=headers) httpserver.check_assertions()
def test_app_event_forward(_: mock.Mock, __: mock.PropertyMock, httpserver: httpserver.HTTPServer) -> None: with open(os.path.join(os.path.dirname(__file__), "events", "push.json")) as f: data = f.read() headers = { "X-GitHub-Delivery": str(uuid.uuid4()), "X-GitHub-Event": "push", "X-Hub-Signature": f"sha1={utils.compute_hmac(data.encode(), config.WEBHOOK_SECRET)}", "User-Agent": "GitHub-Hookshot/044aadd", "Content-Type": "application/json", } httpserver.expect_request("/", method="POST", data=data, headers=headers).respond_with_data("") with mock.patch( "mergify_engine.config.WEBHOOK_APP_FORWARD_URL", httpserver.url_for("/"), ): with testclient.TestClient(root.app) as client: client.post("/event", data=data, headers=headers) httpserver.check_assertions() # type: ignore[no-untyped-call]
def test_badge_redirect(): with testclient.TestClient(web.app) as client: reply = client.get("/badges/mergifyio/mergify-engine.png", allow_redirects=False) assert reply.status_code == 302 assert reply.headers["Location"] == ( "https://img.shields.io/endpoint.png" "?url=https://dashboard.mergify.io/badges/mergifyio/mergify-engine&style=flat" ) with testclient.TestClient(web.app) as client: reply = client.get("/badges/mergifyio/mergify-engine.svg", allow_redirects=False) assert reply.status_code == 302 assert reply.headers["Location"] == ( "https://img.shields.io/endpoint.svg" "?url=https://dashboard.mergify.io/badges/mergifyio/mergify-engine&style=flat" )
def test_simulator_with_invalid_json() -> None: with testclient.TestClient(web.app) as client: charset = "utf-8" data = "invalid:json".encode(charset) headers = { "X-Hub-Signature": f"sha1={utils.compute_hmac(data)}", "Content-Type": f"application/json; charset={charset}", } reply = client.post("/simulator/", data=data, headers=headers) assert reply.status_code == 400, reply.content
def client(app): """client. Args: app: """ cwd = pathlib.Path(__file__).parent.parent subprocess.check_call(["alembic", "upgrade", "head"], cwd=cwd) with testclient.TestClient(app) as client: yield client
def test_subscription_cache_delete(): owner_id = 123 data = None headers = { "X-Hub-Signature": "sha1=%s" % utils.compute_hmac(data), } with testclient.TestClient(web.app) as client: reply = client.delete(f"/subscription-cache/{owner_id}", data=data, headers=headers) assert reply.status_code == 200 assert reply.content == b"Cache cleaned"
def test_legacy_authentication() -> None: owner_id = 123 data = b"azerty" headers = { "X-Hub-Signature": f"sha1={utils.compute_hmac(data, config.WEBHOOK_SECRET)}", } with testclient.TestClient(root.app) as client: reply = client.delete(f"/tokens-cache/{owner_id}", data=data, headers=headers) assert reply.status_code == 200 assert reply.content == b"Cache cleaned"
def client(app): # noqa: WPS442 """Get test client. Args: app: The zucced_api app. Yields: app: Yields an instance of the app after running migrations """ cwd = pathlib.Path(__file__).parent.parent command = ["alembic", "upgrade", "head"] subprocess.check_call(command, cwd=cwd) # noqa: S603, S607 with testclient.TestClient(app) as test_client: yield test_client
def test_subscription_cache_update(): installation_id = 123 charset = "utf-8" data = json.dumps({}).encode( charset) # for this test the content does not matter headers = { "X-Hub-Signature": "sha1=%s" % utils.compute_hmac(data), "Content-Type": f"application/json; charset={charset}", } with testclient.TestClient(web.app) as client: reply = client.put(f"/subscription-cache/{installation_id}", data=data, headers=headers) assert reply.status_code == 200 assert reply.content == b"Cache updated"
def test_push_event(event, event_type, status_code, reason): with testclient.TestClient(web.app) as client: charset = "utf-8" data = json.dumps(event).encode(charset) headers = { "X-Hub-Signature": "sha1=%s" % utils.compute_hmac(data), "X-GitHub-Event": event_type, "Content-Type": f"application/json; charset={charset}", } reply = client.post( "/event", data=data, headers=headers, ) assert reply.content == reason assert reply.status_code == status_code
def test_simulator_without_pull_request() -> None: with testclient.TestClient(web.app) as client: yaml_config = yaml.dump({ "pull_request_rules": [{ "name": "Automerge", "conditions": [ "base=master", "#files>100", "-#files<=100", ], "actions": { "merge": {} }, }] }) charset = "utf-8" data = json.dumps({ "mergify.yml": yaml_config, "pull_request": None }).encode(charset) headers = { "X-Hub-Signature": f"sha1={utils.compute_hmac(data)}", "Content-Type": f"application/json; charset={charset}", } reply = client.post("/simulator/", data=data, headers=headers) assert reply.status_code == 200, reply.content assert json.loads(reply.content) == { "title": "The configuration is valid", "summary": None, "conditions": { "pull_request_rules": [[ { "=": ["base", "master"] }, { ">": ["#files", 100] }, { "-": { "<=": ["#files", 100] } }, ]] }, }
def test_push_event(event: github_types.GitHubEvent, event_type: str, status_code: int, reason: bytes) -> None: with testclient.TestClient(root.app) as client: charset = "utf-8" data = json.dumps(event).encode(charset) headers = { "X-Hub-Signature": f"sha1={utils.compute_hmac(data)}", "X-GitHub-Event": event_type, "Content-Type": f"application/json; charset={charset}", } reply = client.post( "/event", data=data, headers=headers, ) assert reply.content == reason assert reply.status_code == status_code
def test_market_event_forward(mocked_http_client, _, __, ___): with open(os.path.dirname(__file__) + "/market_event.json", "rb") as f: data = f.read() headers = { "X-GitHub-Delivery": str(uuid.uuid4()), "X-GitHub-Event": "purchased", "X-Hub-Signature": "sha1=%s" % utils.compute_hmac(data), "User-Agent": "GitHub-Hookshot/044aadd", "Content-Type": "application/json", } with testclient.TestClient(web.app) as client: client.post("/marketplace", data=data, headers=headers) mocked_http_client.return_value.__enter__.return_value.post.assert_called_with( "https://foobar/engine/market", data=data, headers=headers)
def test_config_validator() -> None: with testclient.TestClient(web.app) as client: data = yaml.dump({ "pull_request_rules": [{ "name": "Automerge", "conditions": [ "base=master", "#files>100", ], "actions": { "merge": {} }, }] }).encode() reply = client.post("/validate/", files={"data": (".mergify.yml", data)}) assert reply.status_code == 200, reply.content assert reply.content == b"The configuration is valid"
def test_subscription_cache_update() -> None: owner_id = 123 charset = "utf-8" data = json.dumps( subscription.SubscriptionDict({ "subscription_reason": "Customer", "features": [], })).encode(charset) headers = { "Authorization": f"Bearer {config.DASHBOARD_TO_ENGINE_API_KEY}", "Content-Type": f"application/json; charset={charset}", } with testclient.TestClient(root.app) as client: reply = client.put(f"/subscription-cache/{owner_id}", data=data, headers=headers) assert reply.status_code == 200 assert reply.content == b"Cache updated"
def test_subscription_cache_update(): owner_id = 123 charset = "utf-8" data = json.dumps({ "subscription_active": True, "subscription_reason": "Customer", "tokens": {}, "features": [], }).encode(charset) headers = { "X-Hub-Signature": "sha1=%s" % utils.compute_hmac(data), "Content-Type": f"application/json; charset={charset}", } with testclient.TestClient(web.app) as client: reply = client.put(f"/subscription-cache/{owner_id}", data=data, headers=headers) assert reply.status_code == 200 assert reply.content == b"Cache updated"
def test_push_event( _: mock.PropertyMock, event: github_types.GitHubEvent, event_type: str, status_code: int, reason: bytes, ) -> None: with testclient.TestClient(root.app) as client: charset = "utf-8" data = json.dumps(event).encode(charset) headers = { "X-Hub-Signature": f"sha1={utils.compute_hmac(data, config.WEBHOOK_SECRET)}", "X-GitHub-Event": event_type, "Content-Type": f"application/json; charset={charset}", } reply = client.post( "/event", data=data, headers=headers, ) assert reply.content == reason assert reply.status_code == status_code # Same with WEBHOOK_SECRET_PRE_ROTATION for key rotation assert config.WEBHOOK_SECRET_PRE_ROTATION is not None charset = "utf-8" data = json.dumps(event).encode(charset) headers = { "X-Hub-Signature": f"sha1={utils.compute_hmac(data, config.WEBHOOK_SECRET_PRE_ROTATION)}", "X-GitHub-Event": event_type, "Content-Type": f"application/json; charset={charset}", } reply = client.post( "/event", data=data, headers=headers, ) assert reply.content == reason assert reply.status_code == status_code
def setUp(self): super(FunctionalTestBase, self).setUp() self.existing_labels = [] self.pr_counter = 0 self.git_counter = 0 self.cassette_library_dir = os.path.join(CASSETTE_LIBRARY_DIR_BASE, self.__class__.__name__, self._testMethodName) # Recording stuffs if RECORD: if os.path.exists(self.cassette_library_dir): shutil.rmtree(self.cassette_library_dir) os.makedirs(self.cassette_library_dir) self.recorder = vcr.VCR( cassette_library_dir=self.cassette_library_dir, record_mode="all" if RECORD else "none", match_on=["method", "uri"], filter_headers=[ ("Authorization", "<TOKEN>"), ("X-Hub-Signature", "<SIGNATURE>"), ("User-Agent", None), ("Accept-Encoding", None), ("Connection", None), ], before_record_response=self.response_filter, custom_patches=((pygithub.MainClass, "HTTPSConnection", vcr.stubs.VCRHTTPSConnection), ), ) if RECORD: github.CachedToken.STORAGE = {} else: # Never expire token during replay mock.patch.object(github_app, "get_or_create_jwt", return_value="<TOKEN>").start() mock.patch.object( github.GithubAppInstallationAuth, "get_access_token", return_value="<TOKEN>", ).start() # NOTE(sileht): httpx pyvcr stubs does not replay auth_flow as it directly patch client.send() # So anything occurring during auth_flow have to be mocked during replay def get_auth(owner=None, auth=None): if auth is None: auth = github.get_auth(owner) auth.installation = { "id": config.INSTALLATION_ID, } auth.permissions_need_to_be_updated = False auth.owner_id = config.TESTING_ORGANIZATION_ID return auth async def github_aclient(owner=None, auth=None): return github.AsyncGithubInstallationClient( get_auth(owner, auth)) def github_client(owner=None, auth=None): return github.GithubInstallationClient(get_auth(owner, auth)) mock.patch.object(github, "get_client", github_client).start() mock.patch.object(github, "aget_client", github_aclient).start() with open(engine.mergify_rule_path, "r") as f: engine.MERGIFY_RULE = yaml.safe_load(f.read().replace( "mergify[bot]", "mergify-test[bot]")) mock.patch.object(branch_updater.utils, "Gitter", self.get_gitter).start() mock.patch.object(duplicate_pull.utils, "Gitter", self.get_gitter).start() if not RECORD: # NOTE(sileht): Don't wait exponentialy during replay mock.patch.object(context.Context._ensure_complete.retry, "wait", None).start() # Web authentification always pass mock.patch("hmac.compare_digest", return_value=True).start() branch_prefix_path = os.path.join(self.cassette_library_dir, "branch_prefix") if RECORD: self.BRANCH_PREFIX = datetime.datetime.utcnow().strftime( "%Y%m%d%H%M%S") with open(branch_prefix_path, "w") as f: f.write(self.BRANCH_PREFIX) else: with open(branch_prefix_path, "r") as f: self.BRANCH_PREFIX = f.read() self.master_branch_name = self.get_full_branch_name("master") self.git = self.get_gitter(LOG) self.addCleanup(self.git.cleanup) self.loop = asyncio.get_event_loop() self.loop.run_until_complete(web.startup()) self.app = testclient.TestClient(web.app) # NOTE(sileht): Prepare a fresh redis self.redis_stream = redis.StrictRedis.from_url(config.STREAM_URL, decode_responses=False) self.redis_stream.flushall() self.redis_cache = utils.get_redis_for_cache() self.redis_cache.flushall() self.subscription = subscription.Subscription( config.INSTALLATION_ID, self.SUBSCRIPTION_ACTIVE, "You're not nice", { "mergify-test1": config.ORG_ADMIN_GITHUB_APP_OAUTH_TOKEN, "mergify-test3": config.ORG_USER_PERSONAL_TOKEN, }, frozenset( getattr(subscription.Features, f) for f in subscription.Features.__members__) if self.SUBSCRIPTION_ACTIVE else frozenset(), ) self.loop.run_until_complete( self.subscription.save_subscription_to_cache()) # Let's start recording cassette = self.recorder.use_cassette("http.json") cassette.__enter__() self.addCleanup(cassette.__exit__) integration = pygithub.GithubIntegration(config.INTEGRATION_ID, config.PRIVATE_KEY) self.installation_token = integration.get_access_token( config.INSTALLATION_ID).token base_url = config.GITHUB_API_URL self.g_integration = pygithub.Github(self.installation_token, base_url=base_url) self.g_admin = pygithub.Github(config.ORG_ADMIN_PERSONAL_TOKEN, base_url=base_url) self.g_fork = pygithub.Github(self.FORK_PERSONAL_TOKEN, base_url=base_url) self.o_admin = self.g_admin.get_organization( config.TESTING_ORGANIZATION) self.o_integration = self.g_integration.get_organization( config.TESTING_ORGANIZATION) self.u_fork = self.g_fork.get_user() assert self.o_admin.login == "mergifyio-testing" assert self.o_integration.login == "mergifyio-testing" assert self.u_fork.login in ["mergify-test2", "mergify-test3"] self.r_o_admin = self.o_admin.get_repo(self.REPO_NAME) self.r_o_integration = self.o_integration.get_repo(self.REPO_NAME) self.r_fork = self.u_fork.get_repo(self.REPO_NAME) self.url_main = f"{config.GITHUB_URL}/{self.r_o_integration.full_name}" self.url_fork = ( f"{config.GITHUB_URL}/{self.u_fork.login}/{self.r_o_integration.name}" ) self.cli_integration = github.get_client(config.TESTING_ORGANIZATION, ) real_get_subscription = subscription.Subscription.get_subscription async def fake_retrieve_subscription_from_db(owner_id): if owner_id == config.TESTING_ORGANIZATION_ID: return self.subscription return subscription.Subscription( owner_id, False, "We're just testing", {}, set(), ) async def fake_subscription(owner_id): if owner_id == config.TESTING_ORGANIZATION_ID: return await real_get_subscription(owner_id) return subscription.Subscription( owner_id, False, "We're just testing", {}, set(), ) mock.patch( "mergify_engine.subscription.Subscription._retrieve_subscription_from_db", side_effect=fake_retrieve_subscription_from_db, ).start() mock.patch( "mergify_engine.subscription.Subscription.get_subscription", side_effect=fake_subscription, ).start() mock.patch( "github.MainClass.Installation.Installation.get_repos", return_value=[self.r_o_integration], ).start() self._event_reader = EventReader(self.app) self._event_reader.drain() self.redis_stream.flushall()
def setUp(self): super(FunctionalTestBase, self).setUp() self.pr_counter = 0 self.git_counter = 0 self.cassette_library_dir = os.path.join( CASSETTE_LIBRARY_DIR_BASE, self.__class__.__name__, self._testMethodName ) # Recording stuffs if RECORD: if os.path.exists(self.cassette_library_dir): shutil.rmtree(self.cassette_library_dir) os.makedirs(self.cassette_library_dir) self.recorder = vcr.VCR( cassette_library_dir=self.cassette_library_dir, record_mode="all" if RECORD else "none", match_on=["method", "uri"], filter_headers=[ ("Authorization", "<TOKEN>"), ("X-Hub-Signature", "<SIGNATURE>"), ("User-Agent", None), ("Accept-Encoding", None), ("Connection", None), ], before_record_response=self.response_filter, custom_patches=( (pygithub.MainClass, "HTTPSConnection", vcr.stubs.VCRHTTPSConnection), ), ) if RECORD: github.CachedToken.STORAGE = {} else: # Never expire token during replay mock.patch.object( github_app.GithubBearerAuth, "get_or_create_jwt", return_value="<TOKEN>" ).start() mock.patch.object( github.GithubInstallationAuth, "get_access_token", return_value="<TOKEN>", ).start() github.CachedToken.STORAGE = {} github.CachedToken( installation_id=config.INSTALLATION_ID, token="<TOKEN>", expiration=datetime.datetime.utcnow() + datetime.timedelta(minutes=10), ) github_app_client = github_app._Client() mock.patch.object(github_app, "get_client", lambda: github_app_client).start() mock.patch.object(branch_updater.utils, "Gitter", self.get_gitter).start() mock.patch.object(duplicate_pull.utils, "Gitter", self.get_gitter).start() if not RECORD: # NOTE(sileht): Don't wait exponentialy during replay mock.patch.object( context.Context._ensure_complete.retry, "wait", None ).start() # Web authentification always pass mock.patch("hmac.compare_digest", return_value=True).start() branch_prefix_path = os.path.join(self.cassette_library_dir, "branch_prefix") if RECORD: self.BRANCH_PREFIX = datetime.datetime.utcnow().strftime("%Y%m%d%H%M%S") with open(branch_prefix_path, "w") as f: f.write(self.BRANCH_PREFIX) else: with open(branch_prefix_path, "r") as f: self.BRANCH_PREFIX = f.read() self.master_branch_name = self.get_full_branch_name("master") self.git = self.get_gitter(LOG) self.addCleanup(self.git.cleanup) self.app = testclient.TestClient(web.app) # NOTE(sileht): Prepare a fresh redis self.redis = utils.get_redis_for_cache() self.redis.flushall() self.subscription = { "tokens": {"mergifyio-testing": config.MAIN_TOKEN}, "subscription_active": False, "subscription_reason": "You're not nice", } loop = asyncio.get_event_loop() loop.run_until_complete( sub_utils.save_subscription_to_cache( config.INSTALLATION_ID, self.subscription, ) ) # Let's start recording cassette = self.recorder.use_cassette("http.json") cassette.__enter__() self.addCleanup(cassette.__exit__) integration = pygithub.GithubIntegration( config.INTEGRATION_ID, config.PRIVATE_KEY ) self.installation_token = integration.get_access_token( config.INSTALLATION_ID ).token base_url = config.GITHUB_API_URL self.g_integration = pygithub.Github(self.installation_token, base_url=base_url) self.g_admin = pygithub.Github(config.MAIN_TOKEN, base_url=base_url) self.g_fork = pygithub.Github(config.FORK_TOKEN, base_url=base_url) self.o_admin = self.g_admin.get_organization(config.TESTING_ORGANIZATION) self.o_integration = self.g_integration.get_organization( config.TESTING_ORGANIZATION ) self.u_fork = self.g_fork.get_user() assert self.o_admin.login == "mergifyio-testing" assert self.o_integration.login == "mergifyio-testing" assert self.u_fork.login == "mergify-test2" # NOTE(sileht): The repository have been manually created in mergifyio-testing # organization and then forked in mergify-test2 user account self.name = "functional-testing-repo" self.r_o_admin = self.o_admin.get_repo(self.name) self.r_o_integration = self.o_integration.get_repo(self.name) self.r_fork = self.u_fork.get_repo(self.name) self.url_main = f"{config.GITHUB_URL}/{self.r_o_integration.full_name}" self.url_fork = ( f"{config.GITHUB_URL}/{self.u_fork.login}/{self.r_o_integration.name}" ) installation = {"id": config.INSTALLATION_ID} self.cli_integration = github.get_client( config.TESTING_ORGANIZATION, self.name, installation ) real_get_subscription = sub_utils.get_subscription def fake_retrieve_subscription_from_db(install_id): if int(install_id) == config.INSTALLATION_ID: return self.subscription else: return { "tokens": {}, "subscription_active": False, "subscription_reason": "We're just testing", } def fake_subscription(r, install_id): if int(install_id) == config.INSTALLATION_ID: return real_get_subscription(r, install_id) else: return { "tokens": {}, "subscription_active": False, "subscription_reason": "We're just testing", } mock.patch( "mergify_engine.branch_updater.sub_utils.get_subscription", side_effect=fake_subscription, ).start() mock.patch( "mergify_engine.branch_updater.sub_utils._retrieve_subscription_from_db", side_effect=fake_retrieve_subscription_from_db, ).start() mock.patch( "mergify_engine.sub_utils.get_subscription", side_effect=fake_subscription, ).start() mock.patch( "github.MainClass.Installation.Installation.get_repos", return_value=[self.r_o_integration], ).start() self._event_reader = EventReader(self.app) self._event_reader.drain() self._worker_thread = WorkerThread() self._worker_thread.start()
def test_badge_endpoint(): with testclient.TestClient(web.app) as client: reply = client.get("/badges/mergifyio/mergify-engine", allow_redirects=False) assert reply.headers["Location"] == ( "https://dashboard.mergify.io/badges/mergifyio/mergify-engine")
def TestClient(): return testclient.TestClient(app)