diff --git a/tests/plugins/github/config/process/test_config_auto_merge.py b/tests/plugins/github/config/process/test_config_auto_merge.py index d8feb335..3947a18e 100644 --- a/tests/plugins/github/config/process/test_config_auto_merge.py +++ b/tests/plugins/github/config/process/test_config_auto_merge.py @@ -7,7 +7,6 @@ assert_subprocess_run_calls, get_github_bot, mock_subprocess_run_with_side_effect, - should_call_apis, ) @@ -48,32 +47,25 @@ async def test_config_auto_merge( event = get_mock_event(PullRequestReviewSubmitted) event.payload.pull_request.labels = get_issue_labels(["Config", "Plugin"]) - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.pulls.async_merge", - "result": True, - }, - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - { - "owner": "he0119", - "repo": "action-test", - "pull_number": 100, - "merge_method": "rebase", - }, - ], + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.pulls.async_merge", + { + "owner": "he0119", + "repo": "action-test", + "pull_number": 100, + "merge_method": "rebase", + }, + True, ) ctx.receive_event(bot, event) diff --git a/tests/plugins/github/config/process/test_config_check.py b/tests/plugins/github/config/process/test_config_check.py index c4d9801f..21573334 100644 --- a/tests/plugins/github/config/process/test_config_check.py +++ b/tests/plugins/github/config/process/test_config_check.py @@ -10,14 +10,12 @@ from tests.plugins.github.config.utils import generate_issue_body from tests.plugins.github.event import get_mock_event from tests.plugins.github.utils import ( - GitHubApi, MockIssue, assert_subprocess_run_calls, check_json_data, get_github_bot, get_issue_labels, mock_subprocess_run_with_side_effect, - should_call_apis, ) @@ -113,55 +111,23 @@ async def test_process_config_check( event = get_mock_event(IssuesOpened) event.payload.issue.labels = get_config_labels() - # 定义要调用的 API 列表 - apis: list[GitHubApi] = [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_update_comment", - "result": True, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - { - "api": "rest.pulls.async_create", - "result": mock_pull_resp, - }, - { - "api": "rest.issues.async_add_labels", - "result": None, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - ] - - # 对应的 API 数据 - api_data = [ + ctx.should_call_api( + "rest.apps.async_get_repo_installation", {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", snapshot( { "owner": "he0119", @@ -188,7 +154,15 @@ async def test_process_config_check( """, } ), + None, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_update_comment", snapshot( { "owner": "he0119", @@ -225,6 +199,10 @@ async def test_process_config_check( """, } ), + True, + ) + ctx.should_call_api( + "rest.issues.async_update", snapshot( { "owner": "he0119", @@ -233,6 +211,10 @@ async def test_process_config_check( "title": "Plugin: name", } ), + None, + ) + ctx.should_call_api( + "rest.pulls.async_create", snapshot( { "owner": "he0119", @@ -243,6 +225,10 @@ async def test_process_config_check( "head": "config/issue80", } ), + mock_pull_resp, + ) + ctx.should_call_api( + "rest.issues.async_add_labels", snapshot( { "owner": "he0119", @@ -251,6 +237,10 @@ async def test_process_config_check( "labels": ["Plugin", "Config"], } ), + None, + ) + ctx.should_call_api( + "rest.issues.async_update", snapshot( { "owner": "he0119", @@ -277,10 +267,8 @@ async def test_process_config_check( """, } ), - ] - - # 使用辅助函数调用 API - should_call_apis(ctx, apis, api_data) + None, + ) ctx.receive_event(bot, event) # 测试 git 命令 diff --git a/tests/plugins/github/config/process/test_config_pull_request.py b/tests/plugins/github/config/process/test_config_pull_request.py index 97cea8a9..b648482d 100644 --- a/tests/plugins/github/config/process/test_config_pull_request.py +++ b/tests/plugins/github/config/process/test_config_pull_request.py @@ -12,7 +12,6 @@ assert_subprocess_run_calls, get_github_bot, mock_subprocess_run_with_side_effect, - should_call_apis, ) @@ -45,43 +44,36 @@ async def test_config_process_pull_request( event.payload.pull_request.labels = get_pr_labels(["Config", "Plugin"]) event.payload.pull_request.merged = True - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_update", - "result": True, - }, - { - "api": "rest.pulls.async_list", - "result": mock_pulls_resp, - }, - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 76}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "state": "closed", - "state_reason": "completed", - }, - {"owner": "he0119", "repo": "action-test", "state": "open"}, - ], + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 76}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "state": "closed", + "state_reason": "completed", + }, + True, + ) + ctx.should_call_api( + "rest.pulls.async_list", + {"owner": "he0119", "repo": "action-test", "state": "open"}, + mock_pulls_resp, ) ctx.receive_event(bot, event) @@ -133,38 +125,31 @@ async def test_process_config_pull_request_not_merged( event = get_mock_event(PullRequestClosed) event.payload.pull_request.labels = get_pr_labels(["Config", "Plugin"]) - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_update", - "result": True, - }, - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 76}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "state": "closed", - "state_reason": "not_planned", - }, - ], + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 76}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "state": "closed", + "state_reason": "not_planned", + }, + True, ) ctx.receive_event(bot, event) diff --git a/tests/plugins/github/handlers/test_github_handler.py b/tests/plugins/github/handlers/test_github_handler.py index 5aca1c69..25e2904b 100644 --- a/tests/plugins/github/handlers/test_github_handler.py +++ b/tests/plugins/github/handlers/test_github_handler.py @@ -4,7 +4,7 @@ from nonebug import App from pytest_mock import MockerFixture -from tests.plugins.github.utils import GitHubApi, get_github_bot, should_call_apis +from tests.plugins.github.utils import get_github_bot async def test_update_issue_title(app: App) -> None: @@ -20,21 +20,17 @@ async def test_update_issue_title(app: App) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.issues.async_update", result=True), - ], + ctx.should_call_api( + "rest.issues.async_update", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - "title": "new title", - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + "title": "new title", + } ), + True, ) await github_handler.update_issue_title("new title", 76) @@ -52,21 +48,17 @@ async def test_update_issue_body(app: App) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.issues.async_update", result=True), - ], + ctx.should_call_api( + "rest.issues.async_update", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - "body": "new body", - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + "body": "new body", + } ), + True, ) await github_handler.update_issue_body("new body", 76) @@ -84,21 +76,17 @@ async def test_create_dispatch_event(app: App) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.repos.async_create_dispatch_event", result=True), - ], + ctx.should_call_api( + "rest.repos.async_create_dispatch_event", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "event_type": "event", - "client_payload": {"key": "value"}, - }, - ] + { + "owner": "owner", + "repo": "repo", + "event_type": "event", + "client_payload": {"key": "value"}, + } ), + True, ) await github_handler.create_dispatch_event("event", {"key": "value"}) @@ -119,22 +107,16 @@ async def test_list_comments(app: App, mocker: MockerFixture) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", result=mock_comments_resp - ), - ], + ctx.should_call_api( + "rest.issues.async_list_comments", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + } ), + mock_comments_resp, ) await github_handler.list_comments(76) @@ -152,21 +134,17 @@ async def test_create_comment(app: App) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.issues.async_create_comment", result=True), - ], + ctx.should_call_api( + "rest.issues.async_create_comment", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - "body": "new comment", - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + "body": "new comment", + } ), + True, ) await github_handler.create_comment("new comment", 76) @@ -184,21 +162,17 @@ async def test_update_comment(app: App) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.issues.async_update_comment", result=True), - ], + ctx.should_call_api( + "rest.issues.async_update_comment", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "comment_id": 123, - "body": "updated comment", - }, - ] + { + "owner": "owner", + "repo": "repo", + "comment_id": 123, + "body": "updated comment", + } ), + True, ) await github_handler.update_comment(123, "updated comment") @@ -219,25 +193,22 @@ async def test_comment_issue(app: App, mocker: MockerFixture) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", result=mock_comments_resp - ), - GitHubApi(api="rest.issues.async_create_comment", result=True), - ], + ctx.should_call_api( + "rest.issues.async_list_comments", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 76}), + mock_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", snapshot( - [ - {"owner": "owner", "repo": "repo", "issue_number": 76}, - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - "body": "new comment", - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + "body": "new comment", + } ), + True, ) await github_handler.resuable_comment_issue("new comment", 76) @@ -261,25 +232,22 @@ async def test_comment_issue_reuse(app: App, mocker: MockerFixture) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", result=mock_comments_resp - ), - GitHubApi(api="rest.issues.async_update_comment", result=True), - ], + ctx.should_call_api( + "rest.issues.async_list_comments", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 76}), + mock_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_update_comment", snapshot( - [ - {"owner": "owner", "repo": "repo", "issue_number": 76}, - { - "owner": "owner", - "repo": "repo", - "comment_id": 123, - "body": "new comment", - }, - ] + { + "owner": "owner", + "repo": "repo", + "comment_id": 123, + "body": "new comment", + } ), + True, ) await github_handler.resuable_comment_issue("new comment", 76) @@ -303,18 +271,10 @@ async def test_comment_issue_reuse_no_change(app: App, mocker: MockerFixture) -> repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", result=mock_comments_resp - ), - ], - snapshot( - [ - {"owner": "owner", "repo": "repo", "issue_number": 76}, - ] - ), + ctx.should_call_api( + "rest.issues.async_list_comments", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 76}), + mock_comments_resp, ) await github_handler.resuable_comment_issue("comment\n", 76) @@ -345,16 +305,10 @@ async def test_get_pull_requests_by_label(app: App, mocker: MockerFixture) -> No repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.pulls.async_list", result=mock_pulls_resp), - ], - snapshot( - [ - {"owner": "owner", "repo": "repo", "state": "open"}, - ] - ), + ctx.should_call_api( + "rest.pulls.async_list", + snapshot({"owner": "owner", "repo": "repo", "state": "open"}), + mock_pulls_resp, ) pulls = await github_handler.get_pull_requests_by_label("Plugin") assert pulls == [mock_pull_plugin] @@ -377,16 +331,10 @@ async def test_get_pull_request_by_branch(app: App, mocker: MockerFixture) -> No repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.pulls.async_list", result=mock_pulls_resp), - ], - snapshot( - [ - {"owner": "owner", "repo": "repo", "head": "owner:branch"}, - ] - ), + ctx.should_call_api( + "rest.pulls.async_list", + snapshot({"owner": "owner", "repo": "repo", "head": "owner:branch"}), + mock_pulls_resp, ) pull = await github_handler.get_pull_request_by_branch("branch") assert pull == mock_pull @@ -410,16 +358,10 @@ async def test_get_pull_request_by_branch_empty( repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.pulls.async_list", result=mock_pulls_resp), - ], - snapshot( - [ - {"owner": "owner", "repo": "repo", "head": "owner:branch"}, - ] - ), + ctx.should_call_api( + "rest.pulls.async_list", + snapshot({"owner": "owner", "repo": "repo", "head": "owner:branch"}), + mock_pulls_resp, ) with pytest.raises(ValueError, match="找不到分支 branch 对应的拉取请求"): await github_handler.get_pull_request_by_branch("branch") @@ -442,19 +384,10 @@ async def test_get_pull_request(app: App, mocker: MockerFixture) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.pulls.async_get", - result=mock_pull_resp, - ), - ], - snapshot( - [ - {"owner": "owner", "repo": "repo", "pull_number": 123}, - ] - ), + ctx.should_call_api( + "rest.pulls.async_get", + snapshot({"owner": "owner", "repo": "repo", "pull_number": 123}), + mock_pull_resp, ) pull = await github_handler.get_pull_request(123) assert pull == mock_pull @@ -479,32 +412,28 @@ async def test_draft_pull_request(app: App, mocker: MockerFixture) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.pulls.async_list", - result=mock_pulls_resp, - ), - GitHubApi(api="async_graphql", result=None), - ], + ctx.should_call_api( + "rest.pulls.async_list", + snapshot({"owner": "owner", "repo": "repo", "head": "owner:branch"}), + mock_pulls_resp, + ) + ctx.should_call_api( + "async_graphql", snapshot( - [ - {"owner": "owner", "repo": "repo", "head": "owner:branch"}, - { - "query": """\ + { + "query": """\ mutation convertPullRequestToDraft($pullRequestId: ID!) { convertPullRequestToDraft(input: {pullRequestId: $pullRequestId}) { clientMutationId } }\ """, - "variables": { - "pullRequestId": 123, - }, + "variables": { + "pullRequestId": 123, }, - ] + } ), + None, ) await github_handler.draft_pull_request("branch") @@ -525,19 +454,10 @@ async def test_draft_pull_request_no_pr(app: App, mocker: MockerFixture) -> None repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.pulls.async_list", - result=mock_pulls_resp, - ), - ], - snapshot( - [ - {"owner": "owner", "repo": "repo", "head": "owner:branch"}, - ] - ), + ctx.should_call_api( + "rest.pulls.async_list", + snapshot({"owner": "owner", "repo": "repo", "head": "owner:branch"}), + mock_pulls_resp, ) await github_handler.draft_pull_request("branch") @@ -560,19 +480,10 @@ async def test_draft_pull_request_drafted(app: App, mocker: MockerFixture) -> No repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.pulls.async_list", - result=mock_pulls_resp, - ), - ], - snapshot( - [ - {"owner": "owner", "repo": "repo", "head": "owner:branch"}, - ] - ), + ctx.should_call_api( + "rest.pulls.async_list", + snapshot({"owner": "owner", "repo": "repo", "head": "owner:branch"}), + mock_pulls_resp, ) await github_handler.draft_pull_request("branch") @@ -594,24 +505,17 @@ async def test_merge_pull_request(app: App, mocker: MockerFixture) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.pulls.async_merge", - result=mock_pull, - ), - ], + ctx.should_call_api( + "rest.pulls.async_merge", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "pull_number": 123, - "merge_method": "rebase", - }, - ] + { + "owner": "owner", + "repo": "repo", + "pull_number": 123, + "merge_method": "rebase", + } ), + mock_pull, ) await github_handler.merge_pull_request(123, "rebase") @@ -637,34 +541,38 @@ async def test_update_pull_request_status(app: App, mocker: MockerFixture) -> No repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.pulls.async_list", result=mock_pulls_resp), - GitHubApi(api="rest.pulls.async_update", result=None), - GitHubApi(api="async_graphql", result=None), - ], + ctx.should_call_api( + "rest.pulls.async_list", + snapshot({"owner": "owner", "repo": "repo", "head": "owner:branch"}), + mock_pulls_resp, + ) + ctx.should_call_api( + "rest.pulls.async_update", snapshot( - [ - {"owner": "owner", "repo": "repo", "head": "owner:branch"}, - { - "owner": "owner", - "repo": "repo", - "pull_number": 111, - "title": "new title", - }, - { - "query": """\ + { + "owner": "owner", + "repo": "repo", + "pull_number": 111, + "title": "new title", + } + ), + None, + ) + ctx.should_call_api( + "async_graphql", + snapshot( + { + "query": """\ mutation markPullRequestReadyForReview($pullRequestId: ID!) { markPullRequestReadyForReview(input: {pullRequestId: $pullRequestId}) { clientMutationId } }\ """, - "variables": {"pullRequestId": 222}, - }, - ] + "variables": {"pullRequestId": 222}, + } ), + None, ) await github_handler.update_pull_request_status("new title", "branch") @@ -686,23 +594,19 @@ async def test_create_pull_request(app: App, mocker: MockerFixture) -> None: bot=bot, repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.pulls.async_create", result=mock_pull_resp), - ], + ctx.should_call_api( + "rest.pulls.async_create", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "title": "new title", - "body": "new body", - "base": "main", - "head": "branch", - }, - ] + { + "owner": "owner", + "repo": "repo", + "title": "new title", + "body": "new body", + "base": "main", + "head": "branch", + } ), + mock_pull_resp, ) number = await github_handler.create_pull_request( "main", "new title", "branch", "new body" @@ -723,21 +627,17 @@ async def test_add_labels(app: App) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.issues.async_add_labels", result=True), - ], + ctx.should_call_api( + "rest.issues.async_add_labels", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - "labels": ["Publish", "Plugin"], - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + "labels": ["Publish", "Plugin"], + } ), + True, ) await github_handler.add_labels(76, ["Publish", "Plugin"]) @@ -755,25 +655,21 @@ async def test_ready_pull_request(app: App) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="async_graphql", result=None), - ], + ctx.should_call_api( + "async_graphql", snapshot( - [ - { - "query": """\ + { + "query": """\ mutation markPullRequestReadyForReview($pullRequestId: ID!) { markPullRequestReadyForReview(input: {pullRequestId: $pullRequestId}) { clientMutationId } }\ """, - "variables": {"pullRequestId": "node_id"}, - }, - ] + "variables": {"pullRequestId": "node_id"}, + } ), + None, ) await github_handler.ready_pull_request("node_id") @@ -791,21 +687,17 @@ async def test_update_pull_request_title(app: App) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.pulls.async_update", result=True), - ], + ctx.should_call_api( + "rest.pulls.async_update", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "pull_number": 123, - "title": "new title", - }, - ] + { + "owner": "owner", + "repo": "repo", + "pull_number": 123, + "title": "new title", + } ), + True, ) await github_handler.update_pull_request_title("new title", 123) @@ -828,16 +720,10 @@ async def test_get_user_name(app: App, mocker: MockerFixture) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.users.async_get_by_id", result=mock_user_resp), - ], - snapshot( - [ - {"account_id": 1}, - ] - ), + ctx.should_call_api( + "rest.users.async_get_by_id", + snapshot({"account_id": 1}), + mock_user_resp, ) await github_handler.get_user_name(1) @@ -860,18 +746,10 @@ async def test_get_user_id(app: App, mocker: MockerFixture) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.users.async_get_by_username", result=mock_user_resp - ), - ], - snapshot( - [ - {"username": "name"}, - ] - ), + ctx.should_call_api( + "rest.users.async_get_by_username", + snapshot({"username": "name"}), + mock_user_resp, ) await github_handler.get_user_id("name") @@ -893,16 +771,10 @@ async def test_get_issue(app: App, mocker: MockerFixture) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.issues.async_get", result=mock_issue_resp), - ], - snapshot( - [ - {"owner": "owner", "repo": "repo", "issue_number": 123}, - ] - ), + ctx.should_call_api( + "rest.issues.async_get", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 123}), + mock_issue_resp, ) issue = await github_handler.get_issue(123) assert issue == mock_issue @@ -921,22 +793,18 @@ async def test_close_issue(app: App) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.issues.async_update", result=True), - ], + ctx.should_call_api( + "rest.issues.async_update", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 123, - "state": "closed", - "state_reason": "completed", - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 123, + "state": "closed", + "state_reason": "completed", + } ), + True, ) await github_handler.close_issue("completed", 123) @@ -959,16 +827,10 @@ async def test_to_issue_handler(app: App, mocker: MockerFixture) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.issues.async_get", result=mock_issue_resp), - ], - snapshot( - [ - {"owner": "owner", "repo": "repo", "issue_number": 123}, - ] - ), + ctx.should_call_api( + "rest.issues.async_get", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 123}), + mock_issue_resp, ) issue_handler = await github_handler.to_issue_handler(123) assert isinstance(issue_handler, IssueHandler) @@ -999,22 +861,16 @@ async def test_get_self_comment(app: App, mocker: MockerFixture) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", result=mock_comments_resp - ), - ], + ctx.should_call_api( + "rest.issues.async_list_comments", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + } ), + mock_comments_resp, ) comment = await github_handler.get_self_comment(76) assert comment == mock_comment_bot @@ -1040,22 +896,16 @@ async def test_get_self_comment_not_found(app: App, mocker: MockerFixture) -> No repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", result=mock_comments_resp - ), - ], + ctx.should_call_api( + "rest.issues.async_list_comments", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + } ), + mock_comments_resp, ) comment = await github_handler.get_self_comment(76) assert comment is None @@ -1074,21 +924,17 @@ async def test_comment_issue_new(app: App, mocker: MockerFixture) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.issues.async_create_comment", result=True), - ], + ctx.should_call_api( + "rest.issues.async_create_comment", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - "body": "new comment", - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + "body": "new comment", + } ), + True, ) await github_handler.comment_issue("new comment", 76) @@ -1110,21 +956,17 @@ async def test_comment_issue_update(app: App, mocker: MockerFixture) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.issues.async_update_comment", result=True), - ], + ctx.should_call_api( + "rest.issues.async_update_comment", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "comment_id": 123, - "body": "new comment", - }, - ] + { + "owner": "owner", + "repo": "repo", + "comment_id": 123, + "body": "new comment", + } ), + True, ) await github_handler.comment_issue("new comment", 76, mock_comment) @@ -1166,24 +1008,17 @@ async def test_download_artifact(app: App, mocker: MockerFixture) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.actions.async_download_artifact", - result=mock_download_resp, - ), - ], + ctx.should_call_api( + "rest.actions.async_download_artifact", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "artifact_id": 123, - "archive_format": "zip", - }, - ] + { + "owner": "owner", + "repo": "repo", + "artifact_id": 123, + "archive_format": "zip", + } ), + mock_download_resp, ) result = await github_handler.download_artifact(123) @@ -1211,24 +1046,17 @@ async def test_download_artifact_with_custom_repo( custom_repo = RepoInfo(owner="custom_owner", repo="custom_repo") - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.actions.async_download_artifact", - result=mock_download_resp, - ), - ], + ctx.should_call_api( + "rest.actions.async_download_artifact", snapshot( - [ - { - "owner": "custom_owner", - "repo": "custom_repo", - "artifact_id": 456, - "archive_format": "zip", - }, - ] + { + "owner": "custom_owner", + "repo": "custom_repo", + "artifact_id": 456, + "archive_format": "zip", + } ), + mock_download_resp, ) result = await github_handler.download_artifact(456, custom_repo) diff --git a/tests/plugins/github/handlers/test_issue_handler.py b/tests/plugins/github/handlers/test_issue_handler.py index 7613b86d..ebc8da5e 100644 --- a/tests/plugins/github/handlers/test_issue_handler.py +++ b/tests/plugins/github/handlers/test_issue_handler.py @@ -5,7 +5,7 @@ from nonebug import App from pytest_mock import MockerFixture -from tests.plugins.github.utils import GitHubApi, get_github_bot, should_call_apis +from tests.plugins.github.utils import get_github_bot async def test_issue_property(app: App, mocker: MockerFixture) -> None: @@ -56,21 +56,17 @@ async def test_update_issue_title(app: App, mocker: MockerFixture) -> None: issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.issues.async_update", result=True), - ], + ctx.should_call_api( + "rest.issues.async_update", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - "title": "new title", - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + "title": "new title", + } ), + True, ) await issue_handler.update_issue_title("new title") assert mock_issue.title == "new title" @@ -96,21 +92,17 @@ async def test_update_issue_body(app: App, mocker: MockerFixture) -> None: issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.issues.async_update", result=True), - ], + ctx.should_call_api( + "rest.issues.async_update", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - "body": "new body", - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + "body": "new body", + } ), + True, ) await issue_handler.update_issue_body("new body") assert mock_issue.body == "new body" @@ -136,22 +128,18 @@ async def test_close_issue(app: App, mocker: MockerFixture) -> None: issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.issues.async_update", result=True), - ], + ctx.should_call_api( + "rest.issues.async_update", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 123, - "state": "closed", - "state_reason": "completed", - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 123, + "state": "closed", + "state_reason": "completed", + } ), + True, ) await issue_handler.close_issue("completed") @@ -177,23 +165,19 @@ async def test_create_pull_request(app: App, mocker: MockerFixture) -> None: repo_info=RepoInfo(owner="owner", repo="repo"), issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.pulls.async_create", result=mock_pull_resp), - ], + ctx.should_call_api( + "rest.pulls.async_create", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "title": "new title", - "body": "resolve #76", - "base": "main", - "head": "branch", - }, - ] + { + "owner": "owner", + "repo": "repo", + "title": "new title", + "body": "resolve #76", + "base": "main", + "head": "branch", + } ), + mock_pull_resp, ) number = await issue_handler.create_pull_request("main", "new title", "branch") assert number == 123 @@ -219,22 +203,16 @@ async def test_list_comments(app: App, mocker: MockerFixture) -> None: issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", result=mock_comments_resp - ), - ], + ctx.should_call_api( + "rest.issues.async_list_comments", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + } ), + mock_comments_resp, ) await issue_handler.list_comments() @@ -259,25 +237,22 @@ async def test_comment_issue(app: App, mocker: MockerFixture) -> None: issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", result=mock_comments_resp - ), - GitHubApi(api="rest.issues.async_create_comment", result=True), - ], + ctx.should_call_api( + "rest.issues.async_list_comments", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 76}), + mock_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", snapshot( - [ - {"owner": "owner", "repo": "repo", "issue_number": 76}, - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - "body": "new comment", - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + "body": "new comment", + } ), + True, ) await issue_handler.resuable_comment_issue("new comment") @@ -302,18 +277,10 @@ async def test_should_skip_test(app: App, mocker: MockerFixture) -> None: issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", result=mock_comments_resp - ), - ], - snapshot( - [ - {"owner": "owner", "repo": "repo", "issue_number": 76}, - ] - ), + ctx.should_call_api( + "rest.issues.async_list_comments", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 76}), + mock_comments_resp, ) assert await issue_handler.should_skip_test() is False @@ -342,18 +309,10 @@ async def test_should_skip_test_true(app: App, mocker: MockerFixture) -> None: issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", result=mock_comments_resp - ), - ], - snapshot( - [ - {"owner": "owner", "repo": "repo", "issue_number": 76}, - ] - ), + ctx.should_call_api( + "rest.issues.async_list_comments", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 76}), + mock_comments_resp, ) assert await issue_handler.should_skip_test() is True @@ -382,18 +341,10 @@ async def test_should_skip_test_not_admin(app: App, mocker: MockerFixture) -> No issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", result=mock_comments_resp - ), - ], - snapshot( - [ - {"owner": "owner", "repo": "repo", "issue_number": 76}, - ] - ), + ctx.should_call_api( + "rest.issues.async_list_comments", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 76}), + mock_comments_resp, ) assert await issue_handler.should_skip_test() is False @@ -472,18 +423,10 @@ async def test_get_self_comment(app: App, mocker: MockerFixture) -> None: issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", result=mock_comments_resp - ), - ], - snapshot( - [ - {"owner": "owner", "repo": "repo", "issue_number": 76}, - ] - ), + ctx.should_call_api( + "rest.issues.async_list_comments", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 76}), + mock_comments_resp, ) comment = await issue_handler.get_self_comment() assert comment == mock_comment_bot @@ -512,18 +455,10 @@ async def test_get_self_comment_not_found(app: App, mocker: MockerFixture) -> No issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", result=mock_comments_resp - ), - ], - snapshot( - [ - {"owner": "owner", "repo": "repo", "issue_number": 76}, - ] - ), + ctx.should_call_api( + "rest.issues.async_list_comments", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 76}), + mock_comments_resp, ) comment = await issue_handler.get_self_comment() assert comment is None @@ -546,21 +481,17 @@ async def test_comment_issue_new(app: App, mocker: MockerFixture) -> None: issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.issues.async_create_comment", result=True), - ], + ctx.should_call_api( + "rest.issues.async_create_comment", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - "body": "test comment", - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + "body": "test comment", + } ), + True, ) await issue_handler.comment_issue("test comment") @@ -586,20 +517,16 @@ async def test_comment_issue_update_existing(app: App, mocker: MockerFixture) -> issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi(api="rest.issues.async_update_comment", result=True), - ], + ctx.should_call_api( + "rest.issues.async_update_comment", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "comment_id": 123, - "body": "updated comment", - }, - ] + { + "owner": "owner", + "repo": "repo", + "comment_id": 123, + "body": "updated comment", + } ), + True, ) await issue_handler.comment_issue("updated comment", self_comment=mock_comment) diff --git a/tests/plugins/github/publish/process/test_auto_merge.py b/tests/plugins/github/publish/process/test_auto_merge.py index 05787642..b1934a84 100644 --- a/tests/plugins/github/publish/process/test_auto_merge.py +++ b/tests/plugins/github/publish/process/test_auto_merge.py @@ -3,12 +3,7 @@ from pytest_mock import MockerFixture from tests.plugins.github.event import get_mock_event -from tests.plugins.github.utils import ( - GitHubApi, - assert_subprocess_run_calls, - get_github_bot, - should_call_apis, -) +from tests.plugins.github.utils import assert_subprocess_run_calls, get_github_bot async def test_auto_merge( @@ -31,29 +26,25 @@ async def test_auto_merge( _adapter, bot = get_github_bot(ctx) event = get_mock_event(PullRequestReviewSubmitted) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.apps.async_get_repo_installation", - result=mock_installation, - ), - GitHubApi( - api="rest.apps.async_create_installation_access_token", - result=mock_installation_token, - ), - GitHubApi(api="rest.pulls.async_merge", result=True), - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - { - "owner": "he0119", - "repo": "action-test", - "pull_number": 100, - "merge_method": "rebase", - }, - ], + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.pulls.async_merge", + { + "owner": "he0119", + "repo": "action-test", + "pull_number": 100, + "merge_method": "rebase", + }, + True, ) ctx.receive_event(bot, event) diff --git a/tests/plugins/github/publish/process/test_publish_check.py b/tests/plugins/github/publish/process/test_publish_check.py index afe3008d..97c1d294 100644 --- a/tests/plugins/github/publish/process/test_publish_check.py +++ b/tests/plugins/github/publish/process/test_publish_check.py @@ -20,7 +20,6 @@ get_github_bot, get_issue_labels, mock_subprocess_run_with_side_effect, - should_call_apis, ) @@ -66,49 +65,34 @@ async def test_bot_process_publish_check( _adapter, bot = get_github_bot(ctx) event = get_mock_event(IssuesOpened) - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_create_comment", - "result": True, - }, - { - "api": "rest.pulls.async_create", - "result": mock_pulls_resp, - }, - { - "api": "rest.issues.async_add_labels", - "result": True, - }, - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": snapshot( - """\ + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": snapshot( + """\ # 📃 商店发布检查结果 > Bot: test @@ -137,23 +121,31 @@ async def test_bot_process_publish_check( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """ - ), - }, - { - "owner": "he0119", - "repo": "action-test", - "title": "Bot: test", - "body": "resolve #80", - "base": "master", - "head": "publish/issue80", - }, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 2, - "labels": ["Publish", "Bot"], - }, - ], + ), + }, + True, + ) + ctx.should_call_api( + "rest.pulls.async_create", + { + "owner": "he0119", + "repo": "action-test", + "title": "Bot: test", + "body": "resolve #80", + "base": "master", + "head": "publish/issue80", + }, + mock_pulls_resp, + ) + ctx.should_call_api( + "rest.issues.async_add_labels", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 2, + "labels": ["Publish", "Bot"], + }, + True, ) ctx.receive_event(bot, event) @@ -249,53 +241,34 @@ async def test_adapter_process_publish_check( event = get_mock_event(IssuesOpened) event.payload.issue.labels = get_issue_labels(["Adapter", "Publish"]) - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_create_comment", - "result": True, - }, - { - "api": "rest.issues.async_update", - "result": True, - }, - { - "api": "rest.pulls.async_create", - "result": mock_pulls_resp, - }, - { - "api": "rest.issues.async_add_labels", - "result": True, - }, - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": snapshot( - """\ + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": snapshot( + """\ # 📃 商店发布检查结果 > Adapter: test @@ -324,31 +297,43 @@ async def test_adapter_process_publish_check( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """ - ), - }, - snapshot( - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "title": "Adapter: test", - } ), + }, + True, + ) + ctx.should_call_api( + "rest.issues.async_update", + snapshot( { "owner": "he0119", "repo": "action-test", - "title": snapshot("Adapter: test"), - "body": "resolve #80", - "base": "master", - "head": "publish/issue80", - }, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 2, - "labels": ["Publish", "Adapter"], - }, - ], + "issue_number": 80, + "title": "Adapter: test", + } + ), + True, + ) + ctx.should_call_api( + "rest.pulls.async_create", + { + "owner": "he0119", + "repo": "action-test", + "title": snapshot("Adapter: test"), + "body": "resolve #80", + "base": "master", + "head": "publish/issue80", + }, + mock_pulls_resp, + ) + ctx.should_call_api( + "rest.issues.async_add_labels", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 2, + "labels": ["Publish", "Adapter"], + }, + True, ) ctx.receive_event(bot, event) @@ -451,62 +436,34 @@ async def test_edit_title( _adapter, bot = get_github_bot(ctx) event = get_mock_event(IssuesOpened) - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_create_comment", - "result": True, - }, - { - "api": "rest.issues.async_update", - "result": True, - }, - { - "api": "rest.pulls.async_create", - "exception": RequestFailed( - Response( - httpx.Response(422, request=httpx.Request("test", "test")), - None, # type: ignore - ) - ), - }, - { - "api": "rest.pulls.async_list", - "result": mock_pulls_resp, - }, - { - "api": "rest.pulls.async_update", - "result": True, - }, - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": snapshot( - """\ + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": snapshot( + """\ # 📃 商店发布检查结果 > Bot: test1 @@ -535,34 +492,56 @@ async def test_edit_title( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """ - ), - }, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "title": "Bot: test1", - }, - { - "owner": "he0119", - "repo": "action-test", - "title": "Bot: test1", - "body": "resolve #80", - "base": "master", - "head": "publish/issue80", - }, - { - "owner": "he0119", - "repo": "action-test", - "head": "he0119:publish/issue80", - }, - { - "owner": "he0119", - "repo": "action-test", - "pull_number": 2, - "title": "Bot: test1", - }, - ], + ), + }, + True, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "title": "Bot: test1", + }, + True, + ) + ctx.should_call_api( + "rest.pulls.async_create", + { + "owner": "he0119", + "repo": "action-test", + "title": "Bot: test1", + "body": "resolve #80", + "base": "master", + "head": "publish/issue80", + }, + None, + exception=RequestFailed( + Response( + httpx.Response(422, request=httpx.Request("test", "test")), + None, # type: ignore + ) + ), + ) + ctx.should_call_api( + "rest.pulls.async_list", + { + "owner": "he0119", + "repo": "action-test", + "head": "he0119:publish/issue80", + }, + mock_pulls_resp, + ) + ctx.should_call_api( + "rest.pulls.async_update", + { + "owner": "he0119", + "repo": "action-test", + "pull_number": 2, + "title": "Bot: test1", + }, + True, ) ctx.receive_event(bot, event) @@ -662,49 +641,34 @@ async def test_edit_title_too_long( _adapter, bot = get_github_bot(ctx) event = get_mock_event(IssuesOpened) - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_create_comment", - "result": True, - }, - { - "api": "rest.issues.async_update", - "result": True, - }, - { - "api": "rest.pulls.async_list", - "result": mock_pulls_resp, - }, - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": snapshot( - """\ + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": snapshot( + """\ # 📃 商店发布检查结果 > Bot: looooooooooooooooooooooooooooooooooooooooooooooooooooooong @@ -734,20 +698,28 @@ async def test_edit_title_too_long( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """ - ), - }, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "title": "Bot: looooooooooooooooooooooooooooooooooooooooooooooooo", - }, - { - "owner": "he0119", - "repo": "action-test", - "head": "he0119:publish/issue80", - }, - ], + ), + }, + True, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "title": "Bot: looooooooooooooooooooooooooooooooooooooooooooooooo", + }, + True, + ) + ctx.should_call_api( + "rest.pulls.async_list", + { + "owner": "he0119", + "repo": "action-test", + "head": "he0119:publish/issue80", + }, + mock_pulls_resp, ) ctx.receive_event(bot, event) @@ -803,45 +775,34 @@ async def test_process_publish_check_not_pass( _adapter, bot = get_github_bot(ctx) event = get_mock_event(IssuesOpened) - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_create_comment", - "result": True, - }, - { - "api": "rest.pulls.async_list", - "result": mock_pulls_resp, - }, - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": snapshot( - """\ + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": snapshot( + """\ # 📃 商店发布检查结果 > Bot: test @@ -869,14 +830,18 @@ async def test_process_publish_check_not_pass( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """ - ), - }, - { - "owner": "he0119", - "repo": "action-test", - "head": "he0119:publish/issue80", - }, - ], + ), + }, + True, + ) + ctx.should_call_api( + "rest.pulls.async_list", + { + "owner": "he0119", + "repo": "action-test", + "head": "he0119:publish/issue80", + }, + mock_pulls_resp, ) ctx.receive_event(bot, event) @@ -937,27 +902,20 @@ async def test_issue_state_closed( _adapter, bot = get_github_bot(ctx) event = get_mock_event(IssuesOpened) - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - ], + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, ) ctx.receive_event(bot, event) @@ -1052,49 +1010,34 @@ async def test_convert_pull_request_to_draft( _adapter, bot = get_github_bot(ctx) event = get_mock_event(IssuesOpened) - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_create_comment", - "result": True, - }, - { - "api": "rest.pulls.async_list", - "result": mock_pulls_resp, - }, - { - "api": "async_graphql", - "result": True, - }, - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": snapshot( - """\ + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": snapshot( + """\ # 📃 商店发布检查结果 > Bot: test @@ -1122,18 +1065,26 @@ async def test_convert_pull_request_to_draft( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """ - ), - }, - { - "owner": "he0119", - "repo": "action-test", - "head": "he0119:publish/issue80", - }, - { - "query": "mutation convertPullRequestToDraft($pullRequestId: ID!) {\n convertPullRequestToDraft(input: {pullRequestId: $pullRequestId}) {\n clientMutationId\n }\n }", - "variables": {"pullRequestId": "123"}, - }, - ], + ), + }, + True, + ) + ctx.should_call_api( + "rest.pulls.async_list", + { + "owner": "he0119", + "repo": "action-test", + "head": "he0119:publish/issue80", + }, + mock_pulls_resp, + ) + ctx.should_call_api( + "async_graphql", + { + "query": "mutation convertPullRequestToDraft($pullRequestId: ID!) {\n convertPullRequestToDraft(input: {pullRequestId: $pullRequestId}) {\n clientMutationId\n }\n }", + "variables": {"pullRequestId": "123"}, + }, + True, ) ctx.receive_event(bot, event) @@ -1195,58 +1146,34 @@ async def test_process_publish_check_ready_for_review( _adapter, bot = get_github_bot(ctx) event = get_mock_event(IssuesOpened) - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_create_comment", - "result": True, - }, - { - "api": "rest.pulls.async_create", - "exception": RequestFailed( - Response( - httpx.Response(422, request=httpx.Request("test", "test")), - None, # type: ignore - ) - ), - }, - { - "api": "rest.pulls.async_list", - "result": mock_pulls_resp, - }, - { - "api": "async_graphql", - "result": True, - }, - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": snapshot( - """\ + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": snapshot( + """\ # 📃 商店发布检查结果 > Bot: test @@ -1275,34 +1202,52 @@ async def test_process_publish_check_ready_for_review( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """ - ), - }, - { - "owner": "he0119", - "repo": "action-test", - "title": "Bot: test", - "body": "resolve #80", - "base": "master", - "head": "publish/issue80", - }, - { - "owner": "he0119", - "repo": "action-test", - "head": "he0119:publish/issue80", - }, - { - "query": snapshot( - """\ + ), + }, + True, + ) + ctx.should_call_api( + "rest.pulls.async_create", + { + "owner": "he0119", + "repo": "action-test", + "title": "Bot: test", + "body": "resolve #80", + "base": "master", + "head": "publish/issue80", + }, + None, + exception=RequestFailed( + Response( + httpx.Response(422, request=httpx.Request("test", "test")), + None, # type: ignore + ) + ), + ) + ctx.should_call_api( + "rest.pulls.async_list", + { + "owner": "he0119", + "repo": "action-test", + "head": "he0119:publish/issue80", + }, + mock_pulls_resp, + ) + ctx.should_call_api( + "async_graphql", + { + "query": snapshot( + """\ mutation markPullRequestReadyForReview($pullRequestId: ID!) { markPullRequestReadyForReview(input: {pullRequestId: $pullRequestId}) { clientMutationId } }\ """ - ), - "variables": {"pullRequestId": "123"}, - }, - ], + ), + "variables": {"pullRequestId": "123"}, + }, + True, ) ctx.receive_event(bot, event) @@ -1403,45 +1348,34 @@ async def test_comment_immediate_after_pull_request_closed( _adapter, bot = get_github_bot(ctx) event = get_mock_event(IssuesOpened) - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_create_comment", - "result": True, - }, - { - "api": "rest.pulls.async_list", - "result": mock_pulls_resp, - }, - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": snapshot( - """\ + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": snapshot( + """\ # 📃 商店发布检查结果 > Bot: test @@ -1470,14 +1404,18 @@ async def test_comment_immediate_after_pull_request_closed( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """ - ), - }, - { - "owner": "he0119", - "repo": "action-test", - "head": "he0119:publish/issue80", - }, - ], + ), + }, + True, + ) + ctx.should_call_api( + "rest.pulls.async_list", + { + "owner": "he0119", + "repo": "action-test", + "head": "he0119:publish/issue80", + }, + mock_pulls_resp, ) ctx.receive_event(bot, event) diff --git a/tests/plugins/github/publish/process/test_publish_check_plugin.py b/tests/plugins/github/publish/process/test_publish_check_plugin.py index f368ad7b..d86ff2ba 100644 --- a/tests/plugins/github/publish/process/test_publish_check_plugin.py +++ b/tests/plugins/github/publish/process/test_publish_check_plugin.py @@ -17,7 +17,6 @@ get_github_bot, get_issue_labels, mock_subprocess_run_with_side_effect, - should_call_apis, ) @@ -78,64 +77,28 @@ async def test_plugin_process_publish_check( event.payload.issue.labels = get_issue_labels(["Plugin", "Publish"]) ctx.receive_event(bot, event) - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_create_comment", - "result": None, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - { - "api": "rest.pulls.async_create", - "result": mock_pulls_resp, - }, - { - "api": "rest.issues.async_add_labels", - "result": None, - }, - ], - snapshot( - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": 123}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": """\ + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": 123}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": """\ ### PyPI 项目名 project_link @@ -158,13 +121,21 @@ async def test_plugin_process_publish_check( - [x] 🔥插件测试中,请稍候\ """, - }, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": """\ + }, + None, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": """\ ### PyPI 项目名 project_link @@ -187,13 +158,21 @@ async def test_plugin_process_publish_check( - [ ] 如需重新运行插件测试,请勾选左侧勾选框\ """, - }, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": """\ + }, + None, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": """\ # 📃 商店发布检查结果 > Plugin: name @@ -222,29 +201,40 @@ async def test_plugin_process_publish_check( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """, - }, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "title": "Plugin: name", - }, - { - "owner": "he0119", - "repo": "action-test", - "title": "Plugin: name", - "body": "resolve #80", - "base": "master", - "head": "publish/issue80", - }, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 2, - "labels": ["Publish", "Plugin"], - }, - ] - ), + }, + None, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "title": "Plugin: name", + }, + None, + ) + ctx.should_call_api( + "rest.pulls.async_create", + { + "owner": "he0119", + "repo": "action-test", + "title": "Plugin: name", + "body": "resolve #80", + "base": "master", + "head": "publish/issue80", + }, + mock_pulls_resp, + ) + ctx.should_call_api( + "rest.issues.async_add_labels", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 2, + "labels": ["Publish", "Plugin"], + }, + None, ) # 测试 git 命令 @@ -357,64 +347,28 @@ async def test_plugin_process_publish_check_re_run( event.payload.issue.labels = get_issue_labels(["Plugin", "Publish"]) ctx.receive_event(bot, event) - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_create_comment", - "result": None, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - { - "api": "rest.pulls.async_create", - "result": mock_pulls_resp, - }, - { - "api": "rest.issues.async_add_labels", - "result": None, - }, - ], - snapshot( - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": 123}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": """\ + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": 123}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": """\ ### PyPI 项目名 project_link @@ -437,13 +391,21 @@ async def test_plugin_process_publish_check_re_run( - [x] 🔥插件测试中,请稍候\ """, - }, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": """\ + }, + None, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": """\ ### PyPI 项目名 project_link @@ -466,13 +428,21 @@ async def test_plugin_process_publish_check_re_run( - [ ] 如需重新运行插件测试,请勾选左侧勾选框\ """, - }, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": """\ + }, + None, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": """\ # 📃 商店发布检查结果 > Plugin: name @@ -501,29 +471,40 @@ async def test_plugin_process_publish_check_re_run( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """, - }, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "title": "Plugin: name", - }, - { - "owner": "he0119", - "repo": "action-test", - "title": "Plugin: name", - "body": "resolve #80", - "base": "master", - "head": "publish/issue80", - }, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 2, - "labels": ["Publish", "Plugin"], - }, - ] - ), + }, + None, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "title": "Plugin: name", + }, + None, + ) + ctx.should_call_api( + "rest.pulls.async_create", + { + "owner": "he0119", + "repo": "action-test", + "title": "Plugin: name", + "body": "resolve #80", + "base": "master", + "head": "publish/issue80", + }, + mock_pulls_resp, + ) + ctx.should_call_api( + "rest.issues.async_add_labels", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 2, + "labels": ["Publish", "Plugin"], + }, + None, ) # 测试 git 命令 @@ -624,60 +605,28 @@ async def test_plugin_process_publish_check_missing_metadata( event.payload.issue.labels = get_issue_labels(["Plugin", "Publish"]) ctx.receive_event(bot, event) - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_create_comment", - "result": None, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - { - "api": "rest.pulls.async_list", - "result": mock_pulls_resp, - }, - ], - snapshot( - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": 123}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": """\ + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": 123}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": """\ ### PyPI 项目名 project_link @@ -700,13 +649,21 @@ async def test_plugin_process_publish_check_missing_metadata( - [x] 🔥插件测试中,请稍候\ """, - }, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": """\ + }, + None, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": """\ ### PyPI 项目名 project_link @@ -729,13 +686,21 @@ async def test_plugin_process_publish_check_missing_metadata( - [ ] 如需重新运行插件测试,请勾选左侧勾选框\ """, - }, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": """\ + }, + None, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": """\ # 📃 商店发布检查结果 > Plugin: project_link @@ -765,20 +730,27 @@ async def test_plugin_process_publish_check_missing_metadata( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """, - }, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "title": "Plugin: project_link", - }, - { - "owner": "he0119", - "repo": "action-test", - "head": "he0119:publish/issue80", - }, - ] - ), + }, + None, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "title": "Plugin: project_link", + }, + None, + ) + ctx.should_call_api( + "rest.pulls.async_list", + { + "owner": "he0119", + "repo": "action-test", + "head": "he0119:publish/issue80", + }, + mock_pulls_resp, ) # 测试 git 命令 @@ -835,66 +807,30 @@ async def test_skip_plugin_check( event = get_mock_event(IssueCommentCreated, "issue-comment-skip") ctx.receive_event(bot, event) - should_call_apis( - ctx, - [ - # 获取安装信息 - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - # 获取议题信息 - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.issues.async_create_comment", - "result": None, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - { - "api": "rest.pulls.async_list", - "result": mock_pulls_resp, - }, - ], - snapshot( - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": 123}, - {"owner": "he0119", "repo": "action-test", "issue_number": 70}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 70, - "body": """\ + # 获取安装信息 + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": 123}, + mock_installation_token, + ) + # 获取议题信息 + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 70}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 70, + "body": """\ ### PyPI 项目名 project_link @@ -917,13 +853,21 @@ async def test_skip_plugin_check( - [x] 🔥插件测试中,请稍候\ """, - }, - {"owner": "he0119", "repo": "action-test", "issue_number": 70}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 70, - "body": """\ + }, + None, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 70}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 70, + "body": """\ ### 插件名称 ### 插件描述 @@ -956,12 +900,16 @@ async def test_skip_plugin_check( - [x] 🔥插件测试中,请稍候\ """, - }, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 70, - "body": """\ + }, + None, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 70, + "body": """\ ### 插件名称 ### 插件描述 @@ -994,13 +942,21 @@ async def test_skip_plugin_check( - [ ] 如需重新运行插件测试,请勾选左侧勾选框\ """, - }, - {"owner": "he0119", "repo": "action-test", "issue_number": 70}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 70, - "body": """\ + }, + None, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 70}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 70, + "body": """\ # 📃 商店发布检查结果 > Plugin: project_link @@ -1030,20 +986,27 @@ async def test_skip_plugin_check( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """, - }, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 70, - "title": "Plugin: project_link", - }, - { - "owner": "he0119", - "repo": "action-test", - "head": "he0119:publish/issue70", - }, - ] - ), + }, + None, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 70, + "title": "Plugin: project_link", + }, + None, + ) + ctx.should_call_api( + "rest.pulls.async_list", + { + "owner": "he0119", + "repo": "action-test", + "head": "he0119:publish/issue70", + }, + mock_pulls_resp, ) # 测试 git 命令 diff --git a/tests/plugins/github/publish/process/test_publish_pull_request.py b/tests/plugins/github/publish/process/test_publish_pull_request.py index 159e7106..69813c3e 100644 --- a/tests/plugins/github/publish/process/test_publish_pull_request.py +++ b/tests/plugins/github/publish/process/test_publish_pull_request.py @@ -11,7 +11,6 @@ assert_subprocess_run_calls, get_github_bot, mock_subprocess_run_with_side_effect, - should_call_apis, ) @@ -66,68 +65,63 @@ async def test_process_pull_request( event = get_mock_event(PullRequestClosed) event.payload.pull_request.merged = True - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.actions.async_list_workflow_run_artifacts", - "result": mock_list_artifacts_resp, - }, - { - "api": "rest.repos.async_create_dispatch_event", - "result": None, - }, - { - "api": "rest.issues.async_update", - "result": None, - }, - { - "api": "rest.pulls.async_list", - "result": mock_pulls_resp, - }, - ], + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + snapshot({"owner": "he0119", "repo": "action-test"}), + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + snapshot({"installation_id": mock_installation.parsed_data.id}), + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + snapshot({"owner": "he0119", "repo": "action-test", "issue_number": 76}), + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + snapshot({"owner": "he0119", "repo": "action-test", "issue_number": 80}), + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.actions.async_list_workflow_run_artifacts", + snapshot({"owner": "he0119", "repo": "action-test", "run_id": 3}), + mock_list_artifacts_resp, + ) + ctx.should_call_api( + "rest.repos.async_create_dispatch_event", snapshot( - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 76}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - {"owner": "he0119", "repo": "action-test", "run_id": 3}, - { - "owner": "owner", - "repo": "registry", - "event_type": "registry_update", - "client_payload": { - "repo_info": {"owner": "he0119", "repo": "action-test"}, - "artifact_id": 233, - }, - }, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "state": "closed", - "state_reason": "completed", + { + "owner": "owner", + "repo": "registry", + "event_type": "registry_update", + "client_payload": { + "repo_info": {"owner": "he0119", "repo": "action-test"}, + "artifact_id": 233, }, - {"owner": "he0119", "repo": "action-test", "state": "open"}, - ] + } + ), + None, + ) + ctx.should_call_api( + "rest.issues.async_update", + snapshot( + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "state": "closed", + "state_reason": "completed", + } ), + None, + ) + ctx.should_call_api( + "rest.pulls.async_list", + snapshot({"owner": "he0119", "repo": "action-test", "state": "open"}), + mock_pulls_resp, ) ctx.receive_event(bot, event) @@ -164,38 +158,31 @@ async def test_process_pull_request_not_merged( event = get_mock_event(PullRequestClosed) assert isinstance(event, PullRequestClosed) - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_update", - "result": True, - }, - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 76}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "state": "closed", - "state_reason": "not_planned", - }, - ], + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 76}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "state": "closed", + "state_reason": "not_planned", + }, + True, ) ctx.receive_event(bot, event) diff --git a/tests/plugins/github/publish/utils/test_comment_issue.py b/tests/plugins/github/publish/utils/test_comment_issue.py index bb6c3807..8a37c8aa 100644 --- a/tests/plugins/github/publish/utils/test_comment_issue.py +++ b/tests/plugins/github/publish/utils/test_comment_issue.py @@ -1,7 +1,7 @@ from nonebug import App from pytest_mock import MockerFixture -from tests.plugins.github.utils import GitHubApi, get_github_bot, should_call_apis +from tests.plugins.github.utils import get_github_bot async def test_comment_issue(app: App, mocker: MockerFixture): @@ -22,27 +22,20 @@ async def test_comment_issue(app: App, mocker: MockerFixture): async with app.test_api() as ctx: _adapter, bot = get_github_bot(ctx) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", - result=mock_list_comments_resp, - ), - GitHubApi( - api="rest.issues.async_create_comment", - result=True, - ), - ], - [ - {"owner": "owner", "repo": "repo", "issue_number": 1}, - { - "owner": "owner", - "repo": "repo", - "issue_number": 1, - "body": "test", - }, - ], + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "owner", "repo": "repo", "issue_number": 1}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "owner", + "repo": "repo", + "issue_number": 1, + "body": "test", + }, + True, ) handler = GithubHandler(bot=bot, repo_info=RepoInfo(owner="owner", repo="repo")) @@ -70,27 +63,20 @@ async def test_comment_issue_reuse(app: App, mocker: MockerFixture): async with app.test_api() as ctx: _adapter, bot = get_github_bot(ctx) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", - result=mock_list_comments_resp, - ), - GitHubApi( - api="rest.issues.async_update_comment", - result=True, - ), - ], - [ - {"owner": "owner", "repo": "repo", "issue_number": 1}, - { - "owner": "owner", - "repo": "repo", - "comment_id": 123, - "body": "test", - }, - ], + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "owner", "repo": "repo", "issue_number": 1}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_update_comment", + { + "owner": "owner", + "repo": "repo", + "comment_id": 123, + "body": "test", + }, + True, ) handler = GithubHandler(bot=bot, repo_info=RepoInfo(owner="owner", repo="repo")) @@ -115,17 +101,10 @@ async def test_comment_issue_reuse_same(app: App, mocker: MockerFixture): async with app.test_api() as ctx: _adapter, bot = get_github_bot(ctx) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", - result=mock_list_comments_resp, - ), - ], - [ - {"owner": "owner", "repo": "repo", "issue_number": 1}, - ], + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "owner", "repo": "repo", "issue_number": 1}, + mock_list_comments_resp, ) handler = GithubHandler(bot=bot, repo_info=RepoInfo(owner="owner", repo="repo")) diff --git a/tests/plugins/github/publish/utils/test_ensure_issue_content.py b/tests/plugins/github/publish/utils/test_ensure_issue_content.py index 799ca973..6b7c05c1 100644 --- a/tests/plugins/github/publish/utils/test_ensure_issue_content.py +++ b/tests/plugins/github/publish/utils/test_ensure_issue_content.py @@ -3,10 +3,8 @@ from pytest_mock import MockerFixture from tests.plugins.github.utils import ( - GitHubApi, MockIssue, get_github_bot, - should_call_apis, ) @@ -25,21 +23,14 @@ async def test_ensure_issue_content(app: App, mocker: MockerFixture): issue=issue.as_mock(mocker), ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_update", - result=True, - ) - ], - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 1, - "body": snapshot( - """\ + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "owner", + "repo": "repo", + "issue_number": 1, + "body": snapshot( + """\ ### 插件名称 ### 插件描述 @@ -52,9 +43,9 @@ async def test_ensure_issue_content(app: App, mocker: MockerFixture): 什么都没有\ """ - ), - } - ], + ), + }, + True, ) await ensure_issue_content(handler) @@ -76,22 +67,15 @@ async def test_ensure_issue_content_partial(app: App, mocker: MockerFixture): issue=issue.as_mock(mocker), ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_update", - result=True, - ) - ], - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 1, - "body": "### 插件描述\n\n### 插件项目仓库/主页链接\n\n### 插件支持的适配器\n\n### 插件名称\n\nname\n\n### 插件类型\n", - } - ], + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "owner", + "repo": "repo", + "issue_number": 1, + "body": "### 插件描述\n\n### 插件项目仓库/主页链接\n\n### 插件支持的适配器\n\n### 插件名称\n\nname\n\n### 插件类型\n", + }, + True, ) await ensure_issue_content(handler) diff --git a/tests/plugins/github/publish/utils/test_ensure_issue_plugin_test_button.py b/tests/plugins/github/publish/utils/test_ensure_issue_plugin_test_button.py index fa5be3c6..7b644a4e 100644 --- a/tests/plugins/github/publish/utils/test_ensure_issue_plugin_test_button.py +++ b/tests/plugins/github/publish/utils/test_ensure_issue_plugin_test_button.py @@ -3,11 +3,9 @@ from pytest_mock import MockerFixture from tests.plugins.github.utils import ( - GitHubApi, MockBody, MockIssue, get_github_bot, - should_call_apis, ) @@ -27,21 +25,14 @@ async def test_ensure_issue_plugin_test_button(app: App, mocker: MockerFixture): async with app.test_api() as ctx: _adapter, bot = get_github_bot(ctx) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_update", - result=True, - ) - ], - [ - snapshot( - { - "owner": "owner", - "repo": "repo", - "issue_number": 1, - "body": """\ + ctx.should_call_api( + "rest.issues.async_update", + snapshot( + { + "owner": "owner", + "repo": "repo", + "issue_number": 1, + "body": """\ ### PyPI 项目名 project_link @@ -64,9 +55,9 @@ async def test_ensure_issue_plugin_test_button(app: App, mocker: MockerFixture): - [ ] 如需重新运行插件测试,请勾选左侧勾选框\ """, - } - ) - ], + } + ), + True, ) handler = IssueHandler( @@ -94,21 +85,14 @@ async def test_ensure_issue_plugin_test_button_checked(app: App, mocker: MockerF async with app.test_api() as ctx: _adapter, bot = get_github_bot(ctx) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_update", - result=True, - ) - ], - [ - snapshot( - { - "owner": "owner", - "repo": "repo", - "issue_number": 1, - "body": """\ + ctx.should_call_api( + "rest.issues.async_update", + snapshot( + { + "owner": "owner", + "repo": "repo", + "issue_number": 1, + "body": """\ ### PyPI 项目名 project_link @@ -131,9 +115,9 @@ async def test_ensure_issue_plugin_test_button_checked(app: App, mocker: MockerF - [ ] 如需重新运行插件测试,请勾选左侧勾选框\ """, - } - ) - ], + } + ), + True, ) handler = IssueHandler( @@ -190,21 +174,14 @@ async def test_ensure_issue_plugin_test_button_in_progress( async with app.test_api() as ctx: _adapter, bot = get_github_bot(ctx) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_update", - result=True, - ) - ], - [ - snapshot( - { - "owner": "owner", - "repo": "repo", - "issue_number": 1, - "body": """\ + ctx.should_call_api( + "rest.issues.async_update", + snapshot( + { + "owner": "owner", + "repo": "repo", + "issue_number": 1, + "body": """\ ### PyPI 项目名 project_link @@ -227,9 +204,9 @@ async def test_ensure_issue_plugin_test_button_in_progress( - [x] 🔥插件测试中,请稍候\ """, - } - ) - ], + } + ), + True, ) handler = IssueHandler( diff --git a/tests/plugins/github/publish/utils/test_get_noneflow_artifact.py b/tests/plugins/github/publish/utils/test_get_noneflow_artifact.py index fd95ad9c..6f7e79a5 100644 --- a/tests/plugins/github/publish/utils/test_get_noneflow_artifact.py +++ b/tests/plugins/github/publish/utils/test_get_noneflow_artifact.py @@ -4,7 +4,7 @@ from nonebug import App from pytest_mock import MockerFixture -from tests.plugins.github.utils import GitHubApi, get_github_bot, should_call_apis +from tests.plugins.github.utils import get_github_bot async def test_get_noneflow_artifact_success(app: App, mocker: MockerFixture) -> None: @@ -70,32 +70,27 @@ async def test_get_noneflow_artifact_success(app: App, mocker: MockerFixture) -> issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", - result=mock_comments_resp, - ), - GitHubApi( - api="rest.actions.async_list_workflow_run_artifacts", - result=mock_artifacts_resp, - ), - ], + ctx.should_call_api( + "rest.issues.async_list_comments", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - }, - { - "owner": "owner", - "repo": "repo", - "run_id": 12345678901, - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + } ), + mock_comments_resp, + ) + ctx.should_call_api( + "rest.actions.async_list_workflow_run_artifacts", + snapshot( + { + "owner": "owner", + "repo": "repo", + "run_id": 12345678901, + } + ), + mock_artifacts_resp, ) result = await get_noneflow_artifact(issue_handler) @@ -127,23 +122,16 @@ async def test_get_noneflow_artifact_no_comment( issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", - result=mock_comments_resp, - ), - ], + ctx.should_call_api( + "rest.issues.async_list_comments", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + } ), + mock_comments_resp, ) with pytest.raises( @@ -180,23 +168,16 @@ async def test_get_noneflow_artifact_empty_comment( issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", - result=mock_comments_resp, - ), - ], + ctx.should_call_api( + "rest.issues.async_list_comments", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + } ), + mock_comments_resp, ) with pytest.raises( @@ -240,23 +221,16 @@ async def test_get_noneflow_artifact_no_history( issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", - result=mock_comments_resp, - ), - ], + ctx.should_call_api( + "rest.issues.async_list_comments", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + } ), + mock_comments_resp, ) with pytest.raises(ValueError, match="无法从评论中获取历史工作流信息"): @@ -313,32 +287,27 @@ async def test_get_noneflow_artifact_no_noneflow_artifact( issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", - result=mock_comments_resp, - ), - GitHubApi( - api="rest.actions.async_list_workflow_run_artifacts", - result=mock_artifacts_resp, - ), - ], + ctx.should_call_api( + "rest.issues.async_list_comments", + snapshot( + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + } + ), + mock_comments_resp, + ) + ctx.should_call_api( + "rest.actions.async_list_workflow_run_artifacts", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - }, - { - "owner": "owner", - "repo": "repo", - "run_id": 12345678901, - }, - ] + { + "owner": "owner", + "repo": "repo", + "run_id": 12345678901, + } ), + mock_artifacts_resp, ) with pytest.raises(ValueError, match="未找到 NoneFlow Artifact"): @@ -384,23 +353,16 @@ async def test_get_noneflow_artifact_invalid_run_id( issue=mock_issue, ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", - result=mock_comments_resp, - ), - ], + ctx.should_call_api( + "rest.issues.async_list_comments", snapshot( - [ - { - "owner": "owner", - "repo": "repo", - "issue_number": 76, - }, - ] + { + "owner": "owner", + "repo": "repo", + "issue_number": 76, + } ), + mock_comments_resp, ) with pytest.raises(ValueError, match="无法从评论中获取历史工作流信息"): diff --git a/tests/plugins/github/publish/utils/test_get_pull_requests_by_label.py b/tests/plugins/github/publish/utils/test_get_pull_requests_by_label.py index 2867a9a4..2838e697 100644 --- a/tests/plugins/github/publish/utils/test_get_pull_requests_by_label.py +++ b/tests/plugins/github/publish/utils/test_get_pull_requests_by_label.py @@ -1,7 +1,7 @@ from nonebug import App from pytest_mock import MockerFixture -from tests.plugins.github.utils import GitHubApi, get_github_bot, should_call_apis +from tests.plugins.github.utils import get_github_bot async def test_get_pull_requests_by_label(app: App, mocker: MockerFixture) -> None: @@ -22,10 +22,10 @@ async def test_get_pull_requests_by_label(app: App, mocker: MockerFixture) -> No async with app.test_api() as ctx: _adapter, bot = get_github_bot(ctx) - should_call_apis( - ctx, - [GitHubApi(api="rest.pulls.async_list", result=mock_pulls_resp)], - [{"owner": "owner", "repo": "repo", "state": "open"}], + ctx.should_call_api( + "rest.pulls.async_list", + {"owner": "owner", "repo": "repo", "state": "open"}, + mock_pulls_resp, ) pulls = await get_pull_requests_by_label( @@ -54,10 +54,10 @@ async def test_get_pull_requests_by_label_not_match( async with app.test_api() as ctx: _adapter, bot = get_github_bot(ctx) - should_call_apis( - ctx, - [GitHubApi(api="rest.pulls.async_list", result=mock_pulls_resp)], - [{"owner": "owner", "repo": "repo", "state": "open"}], + ctx.should_call_api( + "rest.pulls.async_list", + {"owner": "owner", "repo": "repo", "state": "open"}, + mock_pulls_resp, ) pulls = await get_pull_requests_by_label( diff --git a/tests/plugins/github/publish/utils/test_publish_resolve_conflict_pull_requests.py b/tests/plugins/github/publish/utils/test_publish_resolve_conflict_pull_requests.py index ff0b0d05..2c353671 100644 --- a/tests/plugins/github/publish/utils/test_publish_resolve_conflict_pull_requests.py +++ b/tests/plugins/github/publish/utils/test_publish_resolve_conflict_pull_requests.py @@ -9,7 +9,6 @@ from respx import MockRouter from tests.plugins.github.utils import ( - GitHubApi, MockBody, MockIssue, MockUser, @@ -17,7 +16,6 @@ check_json_data, get_github_bot, mock_subprocess_run_with_side_effect, - should_call_apis, ) @@ -133,39 +131,32 @@ async def test_resolve_conflict_pull_requests_adapter( handler = GithubHandler(bot=bot, repo_info=RepoInfo(owner="owner", repo="repo")) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_get", - result=mock_issue_resp, - ), - GitHubApi( - api="rest.issues.async_list_comments", - result=mock_list_comments_resp, - ), - GitHubApi( - api="rest.actions.async_list_workflow_run_artifacts", - result=mock_artifact_resp, - ), - GitHubApi( - api="rest.actions.async_download_artifact", - result=mock_download_artifact_resp, - ), - ], + ctx.should_call_api( + "rest.issues.async_get", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 1}), + mock_issue_resp, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 1}), + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.actions.async_list_workflow_run_artifacts", + snapshot({"owner": "owner", "repo": "repo", "run_id": 14156878699}), + mock_artifact_resp, + ) + ctx.should_call_api( + "rest.actions.async_download_artifact", snapshot( - [ - {"owner": "owner", "repo": "repo", "issue_number": 1}, - {"owner": "owner", "repo": "repo", "issue_number": 1}, - {"owner": "owner", "repo": "repo", "run_id": 14156878699}, - { - "owner": "owner", - "repo": "repo", - "artifact_id": 123456789, - "archive_format": "zip", - }, - ] + { + "owner": "owner", + "repo": "repo", + "artifact_id": 123456789, + "archive_format": "zip", + } ), + mock_download_artifact_resp, ) await resolve_conflict_pull_requests(handler, [mock_pull]) @@ -325,39 +316,32 @@ async def test_resolve_conflict_pull_requests_bot( handler = GithubHandler(bot=bot, repo_info=RepoInfo(owner="owner", repo="repo")) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_get", - result=mock_issue_repo, - ), - GitHubApi( - api="rest.issues.async_list_comments", - result=mock_list_comments_resp, - ), - GitHubApi( - api="rest.actions.async_list_workflow_run_artifacts", - result=mock_artifact_resp, - ), - GitHubApi( - api="rest.actions.async_download_artifact", - result=mock_download_artifact_resp, - ), - ], + ctx.should_call_api( + "rest.issues.async_get", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 1}), + mock_issue_repo, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 1}), + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.actions.async_list_workflow_run_artifacts", + snapshot({"owner": "owner", "repo": "repo", "run_id": 14156878699}), + mock_artifact_resp, + ) + ctx.should_call_api( + "rest.actions.async_download_artifact", snapshot( { - 0: {"owner": "owner", "repo": "repo", "issue_number": 1}, - 1: {"owner": "owner", "repo": "repo", "issue_number": 1}, - 2: {"owner": "owner", "repo": "repo", "run_id": 14156878699}, - 3: { - "owner": "owner", - "repo": "repo", - "artifact_id": 123456789, - "archive_format": "zip", - }, + "owner": "owner", + "repo": "repo", + "artifact_id": 123456789, + "archive_format": "zip", } ), + mock_download_artifact_resp, ) await resolve_conflict_pull_requests(handler, [mock_pull]) @@ -519,39 +503,32 @@ async def test_resolve_conflict_pull_requests_plugin( handler = GithubHandler(bot=bot, repo_info=RepoInfo(owner="owner", repo="repo")) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_get", - result=mock_issue_repo, - ), - GitHubApi( - api="rest.issues.async_list_comments", - result=mock_list_comments_resp, - ), - GitHubApi( - api="rest.actions.async_list_workflow_run_artifacts", - result=mock_artifact_resp, - ), - GitHubApi( - api="rest.actions.async_download_artifact", - result=mock_download_artifact_resp, - ), - ], + ctx.should_call_api( + "rest.issues.async_get", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 1}), + mock_issue_repo, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 1}), + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.actions.async_list_workflow_run_artifacts", + snapshot({"owner": "owner", "repo": "repo", "run_id": 14156878699}), + mock_artifact_resp, + ) + ctx.should_call_api( + "rest.actions.async_download_artifact", snapshot( - [ - {"owner": "owner", "repo": "repo", "issue_number": 1}, - {"owner": "owner", "repo": "repo", "issue_number": 1}, - {"owner": "owner", "repo": "repo", "run_id": 14156878699}, - { - "owner": "owner", - "repo": "repo", - "artifact_id": 123456789, - "archive_format": "zip", - }, - ] + { + "owner": "owner", + "repo": "repo", + "artifact_id": 123456789, + "archive_format": "zip", + } ), + mock_download_artifact_resp, ) await resolve_conflict_pull_requests(handler, [mock_pull]) @@ -655,22 +632,15 @@ async def test_resolve_conflict_pull_requests_plugin_not_valid( handler = GithubHandler(bot=bot, repo_info=RepoInfo(owner="owner", repo="repo")) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_get", - result=mock_issue_repo, - ), - GitHubApi( - api="rest.issues.async_list_comments", - result=mock_list_comments_resp, - ), - ], - [ - snapshot({"owner": "owner", "repo": "repo", "issue_number": 1}), - {"owner": "owner", "repo": "repo", "issue_number": 1}, - ], + ctx.should_call_api( + "rest.issues.async_get", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 1}), + mock_issue_repo, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "owner", "repo": "repo", "issue_number": 1}, + mock_list_comments_resp, ) await resolve_conflict_pull_requests(handler, [mock_pull]) diff --git a/tests/plugins/github/publish/utils/test_trigger_registry_update.py b/tests/plugins/github/publish/utils/test_trigger_registry_update.py index ee13ceb2..c1f79ad5 100644 --- a/tests/plugins/github/publish/utils/test_trigger_registry_update.py +++ b/tests/plugins/github/publish/utils/test_trigger_registry_update.py @@ -6,7 +6,6 @@ MockBody, MockIssue, get_github_bot, - should_call_apis, ) @@ -50,37 +49,30 @@ async def test_trigger_registry_update(app: App, mocker: MockerFixture): async with app.test_api() as ctx: _adapter, bot = get_github_bot(ctx) - should_call_apis( - ctx, - [ - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.actions.async_list_workflow_run_artifacts", - "result": mock_list_artifacts_resp, - }, + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "owner", "repo": "registry", "issue_number": 1}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.actions.async_list_workflow_run_artifacts", + {"owner": "owner", "repo": "registry", "run_id": 3}, + mock_list_artifacts_resp, + ) + ctx.should_call_api( + "rest.repos.async_create_dispatch_event", + snapshot( { - "api": "rest.repos.async_create_dispatch_event", - "result": True, - }, - ], - [ - {"owner": "owner", "repo": "registry", "issue_number": 1}, - {"owner": "owner", "repo": "registry", "run_id": 3}, - snapshot( - { - "repo": "registry", - "owner": "owner", - "event_type": "registry_update", - "client_payload": { - "repo_info": {"owner": "owner", "repo": "registry"}, - "artifact_id": 233, - }, - } - ), - ], + "repo": "registry", + "owner": "owner", + "event_type": "registry_update", + "client_payload": { + "repo_info": {"owner": "owner", "repo": "registry"}, + "artifact_id": 233, + }, + } + ), + True, ) handler = IssueHandler( @@ -111,17 +103,10 @@ async def test_trigger_registry_update_missing_comment(app: App, mocker: MockerF async with app.test_api() as ctx: _adapter, bot = get_github_bot(ctx) - should_call_apis( - ctx, - [ - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - ], - [ - {"owner": "owner", "repo": "registry", "issue_number": 1}, - ], + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "owner", "repo": "registry", "issue_number": 1}, + mock_list_comments_resp, ) handler = IssueHandler( @@ -175,22 +160,15 @@ async def test_trigger_registry_update_missing_artifact( async with app.test_api() as ctx: _adapter, bot = get_github_bot(ctx) - should_call_apis( - ctx, - [ - { - "api": "rest.issues.async_list_comments", - "result": mock_list_comments_resp, - }, - { - "api": "rest.actions.async_list_workflow_run_artifacts", - "result": mock_list_artifacts_resp, - }, - ], - [ - {"owner": "owner", "repo": "registry", "issue_number": 1}, - {"owner": "owner", "repo": "registry", "run_id": 3}, - ], + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "owner", "repo": "registry", "issue_number": 1}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.actions.async_list_workflow_run_artifacts", + {"owner": "owner", "repo": "registry", "run_id": 3}, + mock_list_artifacts_resp, ) handler = IssueHandler( diff --git a/tests/plugins/github/publish/utils/test_validate_info_from_issue.py b/tests/plugins/github/publish/utils/test_validate_info_from_issue.py index 0804ca61..3d97a407 100644 --- a/tests/plugins/github/publish/utils/test_validate_info_from_issue.py +++ b/tests/plugins/github/publish/utils/test_validate_info_from_issue.py @@ -5,13 +5,11 @@ from respx import MockRouter from tests.plugins.github.utils import ( - GitHubApi, generate_issue_body_adapter, generate_issue_body_bot, generate_issue_body_plugin, generate_issue_body_plugin_skip_test, get_github_bot, - should_call_apis, ) @@ -92,15 +90,10 @@ async def test_validate_info_from_issue_plugin( bot=bot, repo_info=RepoInfo(owner="owner", repo="repo"), issue=mock_issue ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", - result=mock_list_comments_resp, - ) - ], - [{"owner": "owner", "repo": "repo", "issue_number": 1}], + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "owner", "repo": "repo", "issue_number": 1}, + mock_list_comments_resp, ) result = await validate_plugin_info_from_issue(handler) @@ -169,15 +162,10 @@ async def test_validate_info_from_issue_plugin_skip_test( bot=bot, repo_info=RepoInfo(owner="owner", repo="repo"), issue=mock_issue ) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.issues.async_list_comments", - result=mock_list_comments_resp, - ) - ], - [{"owner": "owner", "repo": "repo", "issue_number": 1}], + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "owner", "repo": "repo", "issue_number": 1}, + mock_list_comments_resp, ) result = await validate_plugin_info_from_issue(handler) diff --git a/tests/plugins/github/remove/process/test_remove_auto_merge.py b/tests/plugins/github/remove/process/test_remove_auto_merge.py index 6920c65c..ef0acb08 100644 --- a/tests/plugins/github/remove/process/test_remove_auto_merge.py +++ b/tests/plugins/github/remove/process/test_remove_auto_merge.py @@ -4,10 +4,8 @@ from tests.plugins.github.event import get_mock_event from tests.plugins.github.utils import ( - GitHubApi, assert_subprocess_run_calls, get_github_bot, - should_call_apis, ) @@ -53,29 +51,25 @@ async def test_remove_auto_merge( event = get_mock_event(PullRequestReviewSubmitted) event.payload.pull_request.labels = get_issue_labels(["Remove", "Plugin"]) - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.apps.async_get_repo_installation", - result=mock_installation, - ), - GitHubApi( - api="rest.apps.async_create_installation_access_token", - result=mock_installation_token, - ), - GitHubApi(api="rest.pulls.async_merge", result=True), - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - { - "owner": "he0119", - "repo": "action-test", - "pull_number": 100, - "merge_method": "rebase", - }, - ], + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.pulls.async_merge", + { + "owner": "he0119", + "repo": "action-test", + "pull_number": 100, + "merge_method": "rebase", + }, + True, ) ctx.receive_event(bot, event) diff --git a/tests/plugins/github/remove/process/test_remove_check.py b/tests/plugins/github/remove/process/test_remove_check.py index 0e98dea2..e2988e06 100644 --- a/tests/plugins/github/remove/process/test_remove_check.py +++ b/tests/plugins/github/remove/process/test_remove_check.py @@ -8,7 +8,6 @@ from tests.plugins.github.event import get_mock_event from tests.plugins.github.utils import ( - GitHubApi, MockIssue, MockUser, assert_subprocess_run_calls, @@ -17,7 +16,6 @@ get_github_bot, get_issue_labels, mock_subprocess_run_with_side_effect, - should_call_apis, ) @@ -79,57 +77,80 @@ async def test_process_remove_bot_check( check_json_data(plugin_config.input_config.bot_path, data) - apis: list[GitHubApi] = [ - {"api": "rest.apps.async_get_repo_installation", "result": mock_installation}, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - {"api": "rest.issues.async_get", "result": mock_issues_resp}, - {"api": "rest.pulls.async_create", "result": mock_pulls_resp}, - {"api": "rest.issues.async_add_labels", "result": True}, - {"api": "rest.issues.async_update", "result": True}, - {"api": "rest.pulls.async_list", "result": mock_pulls_resp_list}, - {"api": "rest.issues.async_list_comments", "result": mock_list_comments_resp}, - {"api": "rest.issues.async_create_comment", "result": True}, - ] + async with app.test_matcher() as ctx: + _adapter, bot = get_github_bot(ctx) + event = get_mock_event(IssuesOpened) + event.payload.issue.labels = get_issue_labels(["Remove", remove_type]) - data_list = [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - snapshot( + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.pulls.async_create", + snapshot( + { + "owner": "owner", + "repo": "store", + "title": "Bot: Remove TESTBOT", + "body": "resolve he0119/action-test#80", + "base": "master", + "head": "remove/issue80", + } + ), + mock_pulls_resp, + ) + ctx.should_call_api( + "rest.issues.async_add_labels", { "owner": "owner", "repo": "store", - "title": "Bot: Remove TESTBOT", - "body": "resolve he0119/action-test#80", - "base": "master", - "head": "remove/issue80", - } - ), - { - "owner": "owner", - "repo": "store", - "issue_number": 2, - "labels": ["Remove", "Bot"], - }, - snapshot( + "issue_number": 2, + "labels": ["Remove", "Bot"], + }, + True, + ) + ctx.should_call_api( + "rest.issues.async_update", + snapshot( + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "title": "Bot: Remove TESTBOT", + } + ), + True, + ) + ctx.should_call_api( + "rest.pulls.async_list", + {"owner": "owner", "repo": "store", "head": "owner:remove/issue80"}, + mock_pulls_resp_list, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", { "owner": "he0119", "repo": "action-test", "issue_number": 80, - "title": "Bot: Remove TESTBOT", - } - ), - {"owner": "owner", "repo": "store", "head": "owner:remove/issue80"}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": snapshot( - """\ + "body": snapshot( + """\ # 📃 商店下架检查 > Bot: remove TESTBOT @@ -145,16 +166,10 @@ async def test_process_remove_bot_check( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """ - ), - }, - ] - - async with app.test_matcher() as ctx: - _adapter, bot = get_github_bot(ctx) - event = get_mock_event(IssuesOpened) - event.payload.issue.labels = get_issue_labels(["Remove", remove_type]) - - should_call_apis(ctx, apis, data_list) + ), + }, + True, + ) ctx.receive_event(bot, event) @@ -242,59 +257,82 @@ async def test_process_remove_plugin_check( check_json_data(plugin_config.input_config.plugin_path, data) - apis: list[GitHubApi] = [ - {"api": "rest.apps.async_get_repo_installation", "result": mock_installation}, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - {"api": "rest.issues.async_get", "result": mock_issues_resp}, - {"api": "rest.pulls.async_create", "result": mock_pulls_resp}, - {"api": "rest.issues.async_add_labels", "result": True}, - {"api": "rest.issues.async_update", "result": True}, - {"api": "rest.pulls.async_list", "result": mock_pulls_resp_list}, - {"api": "rest.issues.async_list_comments", "result": mock_list_comments_resp}, - {"api": "rest.issues.async_create_comment", "result": True}, - ] + async with app.test_matcher() as ctx: + _adapter, bot = get_github_bot(ctx) + event = get_mock_event(IssuesOpened) + event.payload.issue.labels = get_issue_labels(["Remove", remove_type]) - data_list = [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - snapshot( - { - "owner": "owner", - "repo": "store", - "title": "Plugin: Remove test", - "body": "resolve he0119/action-test#80", - "base": "master", - "head": "remove/issue80", - } - ), - snapshot( - { - "owner": "owner", - "repo": "store", - "issue_number": 2, - "labels": ["Remove", "Plugin"], - } - ), - snapshot( + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.pulls.async_create", + snapshot( + { + "owner": "owner", + "repo": "store", + "title": "Plugin: Remove test", + "body": "resolve he0119/action-test#80", + "base": "master", + "head": "remove/issue80", + } + ), + mock_pulls_resp, + ) + ctx.should_call_api( + "rest.issues.async_add_labels", + snapshot( + { + "owner": "owner", + "repo": "store", + "issue_number": 2, + "labels": ["Remove", "Plugin"], + } + ), + True, + ) + ctx.should_call_api( + "rest.issues.async_update", + snapshot( + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "title": "Plugin: Remove test", + } + ), + True, + ) + ctx.should_call_api( + "rest.pulls.async_list", + {"owner": "owner", "repo": "store", "head": "owner:remove/issue80"}, + mock_pulls_resp_list, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", { "owner": "he0119", "repo": "action-test", "issue_number": 80, - "title": "Plugin: Remove test", - } - ), - {"owner": "owner", "repo": "store", "head": "owner:remove/issue80"}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": snapshot( - """\ + "body": snapshot( + """\ # 📃 商店下架检查 > Plugin: remove test @@ -310,16 +348,10 @@ async def test_process_remove_plugin_check( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """ - ), - }, - ] - - async with app.test_matcher() as ctx: - _adapter, bot = get_github_bot(ctx) - event = get_mock_event(IssuesOpened) - event.payload.issue.labels = get_issue_labels(["Remove", remove_type]) - - should_call_apis(ctx, apis, data_list) + ), + }, + True, + ) ctx.receive_event(bot, event) @@ -387,28 +419,39 @@ async def test_process_remove_not_found_check( check_json_data(plugin_config.input_config.bot_path, []) - apis: list[GitHubApi] = [ - {"api": "rest.apps.async_get_repo_installation", "result": mock_installation}, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - {"api": "rest.issues.async_get", "result": mock_issues_resp}, - {"api": "rest.issues.async_list_comments", "result": mock_list_comments_resp}, - {"api": "rest.issues.async_create_comment", "result": True}, - ] + async with app.test_matcher() as ctx: + _adapter, bot = get_github_bot(ctx) + event = get_mock_event(IssuesOpened) + event.payload.issue.labels = get_issue_labels(["Remove", remove_type]) - data_list = [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": snapshot( - """\ + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": snapshot( + """\ # 📃 商店下架检查 > Error @@ -424,16 +467,10 @@ async def test_process_remove_not_found_check( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """ - ), - }, - ] - - async with app.test_matcher() as ctx: - _adapter, bot = get_github_bot(ctx) - event = get_mock_event(IssuesOpened) - event.payload.issue.labels = get_issue_labels(["Remove", remove_type]) - - should_call_apis(ctx, apis, data_list) + ), + }, + True, + ) ctx.receive_event(bot, event) @@ -498,28 +535,39 @@ async def test_process_remove_author_info_not_eq( check_json_data(plugin_config.input_config.bot_path, bot_data) - apis: list[GitHubApi] = [ - {"api": "rest.apps.async_get_repo_installation", "result": mock_installation}, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - {"api": "rest.issues.async_get", "result": mock_issues_resp}, - {"api": "rest.issues.async_list_comments", "result": mock_list_comments_resp}, - {"api": "rest.issues.async_create_comment", "result": True}, - ] + async with app.test_matcher() as ctx: + _adapter, bot = get_github_bot(ctx) + event = get_mock_event(IssuesOpened) + event.payload.issue.labels = get_issue_labels(["Remove", remove_type]) - data_list = [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": snapshot( - """\ + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": snapshot( + """\ # 📃 商店下架检查 > Error @@ -535,16 +583,10 @@ async def test_process_remove_author_info_not_eq( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """ - ), - }, - ] - - async with app.test_matcher() as ctx: - _adapter, bot = get_github_bot(ctx) - event = get_mock_event(IssuesOpened) - event.payload.issue.labels = get_issue_labels(["Remove", remove_type]) - - should_call_apis(ctx, apis, data_list) + ), + }, + True, + ) ctx.receive_event(bot, event) @@ -607,28 +649,39 @@ async def test_process_remove_issue_info_not_found( check_json_data(plugin_config.input_config.bot_path, bot_data) - apis: list[GitHubApi] = [ - {"api": "rest.apps.async_get_repo_installation", "result": mock_installation}, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - {"api": "rest.issues.async_get", "result": mock_issues_resp}, - {"api": "rest.issues.async_list_comments", "result": mock_list_comments_resp}, - {"api": "rest.issues.async_create_comment", "result": True}, - ] + async with app.test_matcher() as ctx: + _adapter, bot = get_github_bot(ctx) + event = get_mock_event(IssuesOpened) + event.payload.issue.labels = get_issue_labels(["Remove", remove_type]) - data_list = [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": snapshot( - """\ + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": snapshot( + """\ # 📃 商店下架检查 > Error @@ -644,16 +697,10 @@ async def test_process_remove_issue_info_not_found( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """ - ), - }, - ] - - async with app.test_matcher() as ctx: - _adapter, bot = get_github_bot(ctx) - event = get_mock_event(IssuesOpened) - event.payload.issue.labels = get_issue_labels(["Remove", remove_type]) - - should_call_apis(ctx, apis, data_list) + ), + }, + True, + ) ctx.receive_event(bot, event) @@ -697,28 +744,39 @@ async def test_process_remove_driver( mock_pulls_resp = mocker.MagicMock() mock_pulls_resp.parsed_data = mock_pull - apis: list[GitHubApi] = [ - {"api": "rest.apps.async_get_repo_installation", "result": mock_installation}, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - {"api": "rest.issues.async_get", "result": mock_issues_resp}, - {"api": "rest.issues.async_list_comments", "result": mock_list_comments_resp}, - {"api": "rest.issues.async_create_comment", "result": True}, - ] + async with app.test_matcher() as ctx: + _adapter, bot = get_github_bot(ctx) + event = get_mock_event(IssuesOpened) + event.payload.issue.labels = get_issue_labels(["Remove", remove_type]) - data_list = [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - {"owner": "he0119", "repo": "action-test", "issue_number": 80}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 80, - "body": snapshot( - """\ + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + {"owner": "he0119", "repo": "action-test", "issue_number": 80}, + mock_list_comments_resp, + ) + ctx.should_call_api( + "rest.issues.async_create_comment", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 80, + "body": snapshot( + """\ # 📃 商店下架检查 > Error @@ -734,16 +792,10 @@ async def test_process_remove_driver( 💪 Powered by [NoneFlow](https://github.com/nonebot/noneflow) """ - ), - }, - ] - - async with app.test_matcher() as ctx: - _adapter, bot = get_github_bot(ctx) - event = get_mock_event(IssuesOpened) - event.payload.issue.labels = get_issue_labels(["Remove", remove_type]) - - should_call_apis(ctx, apis, data_list) + ), + }, + True, + ) ctx.receive_event(bot, event) diff --git a/tests/plugins/github/remove/process/test_remove_pull_request.py b/tests/plugins/github/remove/process/test_remove_pull_request.py index eb895f3f..d2dce9d9 100644 --- a/tests/plugins/github/remove/process/test_remove_pull_request.py +++ b/tests/plugins/github/remove/process/test_remove_pull_request.py @@ -12,7 +12,6 @@ generate_issue_body_remove, get_github_bot, mock_subprocess_run_with_side_effect, - should_call_apis, ) @@ -48,43 +47,36 @@ async def test_remove_process_pull_request( event.payload.pull_request.labels = get_pr_labels(["Remove", "Bot"]) event.payload.pull_request.merged = True - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_update", - "result": True, - }, - { - "api": "rest.pulls.async_list", - "result": mock_pulls_resp, - }, - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 76}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 76, - "state": "closed", - "state_reason": "completed", - }, - {"owner": "he0119", "repo": "action-test", "state": "open"}, - ], + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 76}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 76, + "state": "closed", + "state_reason": "completed", + }, + True, + ) + ctx.should_call_api( + "rest.pulls.async_list", + {"owner": "he0119", "repo": "action-test", "state": "open"}, + mock_pulls_resp, ) ctx.receive_event(bot, event) @@ -139,38 +131,31 @@ async def test_process_remove_pull_request_not_merged( event = get_mock_event(PullRequestClosed) event.payload.pull_request.labels = get_pr_labels(["Remove", "Bot"]) - should_call_apis( - ctx, - [ - { - "api": "rest.apps.async_get_repo_installation", - "result": mock_installation, - }, - { - "api": "rest.apps.async_create_installation_access_token", - "result": mock_installation_token, - }, - { - "api": "rest.issues.async_get", - "result": mock_issues_resp, - }, - { - "api": "rest.issues.async_update", - "result": True, - }, - ], - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 76}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 76, - "state": "closed", - "state_reason": "not_planned", - }, - ], + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + {"owner": "he0119", "repo": "action-test"}, + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + {"installation_id": mock_installation.parsed_data.id}, + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + {"owner": "he0119", "repo": "action-test", "issue_number": 76}, + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 76, + "state": "closed", + "state_reason": "not_planned", + }, + True, ) ctx.receive_event(bot, event) diff --git a/tests/plugins/github/remove/utils/test_remove_resolve_pull_requests.py b/tests/plugins/github/remove/utils/test_remove_resolve_pull_requests.py index 8004aee5..aa7d1f5e 100644 --- a/tests/plugins/github/remove/utils/test_remove_resolve_pull_requests.py +++ b/tests/plugins/github/remove/utils/test_remove_resolve_pull_requests.py @@ -7,14 +7,12 @@ from respx import MockRouter from tests.plugins.github.utils import ( - GitHubApi, MockIssue, MockUser, assert_subprocess_run_calls, check_json_data, generate_issue_body_remove, get_github_bot, - should_call_apis, ) @@ -80,10 +78,10 @@ async def test_resolve_conflict_pull_requests_bot( handler = GithubHandler(bot=bot, repo_info=RepoInfo(owner="owner", repo="repo")) - should_call_apis( - ctx, - [GitHubApi(api="rest.issues.async_get", result=mock_issue_repo)], - snapshot([{"owner": "owner", "repo": "repo", "issue_number": 1}]), + ctx.should_call_api( + "rest.issues.async_get", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 1}), + mock_issue_repo, ) await resolve_conflict_pull_requests(handler, [mock_pull]) @@ -165,10 +163,10 @@ async def test_resolve_conflict_pull_requests_plugin( async with app.test_api() as ctx: _adapter, bot = get_github_bot(ctx) - should_call_apis( - ctx, - [GitHubApi(api="rest.issues.async_get", result=mock_issue_repo)], - snapshot([{"owner": "owner", "repo": "repo", "issue_number": 1}]), + ctx.should_call_api( + "rest.issues.async_get", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 1}), + mock_issue_repo, ) handler = GithubHandler(bot=bot, repo_info=RepoInfo(owner="owner", repo="repo")) @@ -240,10 +238,10 @@ async def test_resolve_conflict_pull_requests_not_found( async with app.test_api() as ctx: _adapter, bot = get_github_bot(ctx) - should_call_apis( - ctx, - [GitHubApi(api="rest.issues.async_get", result=mock_issue_repo)], - snapshot([{"owner": "owner", "repo": "repo", "issue_number": 1}]), + ctx.should_call_api( + "rest.issues.async_get", + snapshot({"owner": "owner", "repo": "repo", "issue_number": 1}), + mock_issue_repo, ) handler = GithubHandler(bot=bot, repo_info=RepoInfo(owner="owner", repo="repo")) diff --git a/tests/plugins/github/remove/validation/test_remove_validation.py b/tests/plugins/github/remove/validation/test_remove_validation.py new file mode 100644 index 00000000..4b6b474d --- /dev/null +++ b/tests/plugins/github/remove/validation/test_remove_validation.py @@ -0,0 +1,304 @@ +"""测试 plugins/github/plugins/remove/validation.py""" + +from pathlib import Path + +import pytest +from inline_snapshot import snapshot +from nonebug import App +from pydantic_core import PydanticCustomError +from pytest_mock import MockerFixture + +from tests.plugins.github.utils import ( + MockIssue, + MockUser, + generate_issue_body_remove, +) + + +async def test_load_publish_data_adapter( + app: App, mocker: MockerFixture, tmp_path: Path +): + """测试加载适配器数据""" + from src.plugins.github import plugin_config + from src.plugins.github.plugins.remove.validation import load_publish_data + from src.providers.utils import dump_json5 + from src.providers.validation.models import PublishType + + adapters = [ + { + "module_name": "nonebot.adapters.test", + "project_link": "nonebot-adapter-test", + "author_id": 1, + } + ] + adapter_path = tmp_path / "adapters.json5" + dump_json5(adapter_path, adapters) + mocker.patch.object(plugin_config.input_config, "adapter_path", adapter_path) + + result = load_publish_data(PublishType.ADAPTER) + + assert result == snapshot( + { + "nonebot-adapter-test:nonebot.adapters.test": { + "module_name": "nonebot.adapters.test", + "project_link": "nonebot-adapter-test", + "author_id": 1, + } + } + ) + + +async def test_load_publish_data_bot(app: App, mocker: MockerFixture, tmp_path: Path): + """测试加载机器人数据""" + from src.plugins.github import plugin_config + from src.plugins.github.plugins.remove.validation import load_publish_data + from src.providers.utils import dump_json5 + from src.providers.validation.models import PublishType + + bots = [ + { + "name": "TestBot", + "homepage": "https://nonebot.dev", + "author_id": 1, + } + ] + bot_path = tmp_path / "bots.json5" + dump_json5(bot_path, bots) + mocker.patch.object(plugin_config.input_config, "bot_path", bot_path) + + result = load_publish_data(PublishType.BOT) + + assert result == snapshot( + { + "TestBot:https://nonebot.dev": { + "name": "TestBot", + "homepage": "https://nonebot.dev", + "author_id": 1, + } + } + ) + + +async def test_load_publish_data_plugin( + app: App, mocker: MockerFixture, tmp_path: Path +): + """测试加载插件数据""" + from src.plugins.github import plugin_config + from src.plugins.github.plugins.remove.validation import load_publish_data + from src.providers.utils import dump_json5 + from src.providers.validation.models import PublishType + + plugins = [ + { + "module_name": "nonebot_plugin_test", + "project_link": "nonebot-plugin-test", + "author_id": 1, + } + ] + plugin_path = tmp_path / "plugins.json5" + dump_json5(plugin_path, plugins) + mocker.patch.object(plugin_config.input_config, "plugin_path", plugin_path) + + result = load_publish_data(PublishType.PLUGIN) + + assert result == snapshot( + { + "nonebot-plugin-test:nonebot_plugin_test": { + "module_name": "nonebot_plugin_test", + "project_link": "nonebot-plugin-test", + "author_id": 1, + } + } + ) + + +async def test_load_publish_data_driver_raises(app: App): + """测试加载驱动程序数据应该抛出异常""" + from src.plugins.github.plugins.remove.validation import load_publish_data + from src.providers.validation.models import PublishType + + with pytest.raises(ValueError, match="不支持的删除类型"): + load_publish_data(PublishType.DRIVER) + + +async def test_validate_author_info_adapter( + app: App, mocker: MockerFixture, tmp_path: Path +): + """测试验证适配器作者信息""" + from src.plugins.github import plugin_config + from src.plugins.github.plugins.remove.validation import validate_author_info + from src.providers.utils import dump_json5 + from src.providers.validation.models import PublishType + + adapters = [ + { + "name": "Test Adapter", + "module_name": "nonebot.adapters.test", + "project_link": "nonebot-adapter-test", + "author_id": 1, + } + ] + adapter_path = tmp_path / "adapters.json5" + dump_json5(adapter_path, adapters) + mocker.patch.object(plugin_config.input_config, "adapter_path", adapter_path) + + mock_issue = MockIssue( + body=generate_issue_body_remove( + "Adapter", "nonebot-adapter-test:nonebot.adapters.test" + ), + user=MockUser(login="test", id=1), + ).as_mock(mocker) + + result = await validate_author_info(mock_issue, PublishType.ADAPTER) + + assert result.publish_type == PublishType.ADAPTER + assert result.key == "nonebot-adapter-test:nonebot.adapters.test" + assert result.name == "Test Adapter" + + +async def test_validate_author_info_plugin_not_found( + app: App, mocker: MockerFixture, tmp_path: Path +): + """测试验证插件作者信息 - 插件未找到""" + from src.plugins.github import plugin_config + from src.plugins.github.plugins.remove.validation import validate_author_info + from src.providers.utils import dump_json5 + from src.providers.validation.models import PublishType + + plugins: list = [] + plugin_path = tmp_path / "plugins.json5" + dump_json5(plugin_path, plugins) + mocker.patch.object(plugin_config.input_config, "plugin_path", plugin_path) + + mock_issue = MockIssue( + body=generate_issue_body_remove("Plugin", "project_link:module_name"), + user=MockUser(login="test", id=1), + ).as_mock(mocker) + + with pytest.raises(PydanticCustomError) as exc_info: + await validate_author_info(mock_issue, PublishType.PLUGIN) + + assert exc_info.value.type == "not_found" + + +async def test_validate_author_info_author_mismatch( + app: App, mocker: MockerFixture, tmp_path: Path +): + """测试验证作者信息 - 作者不匹配""" + from src.plugins.github import plugin_config + from src.plugins.github.plugins.remove.validation import validate_author_info + from src.providers.utils import dump_json5 + from src.providers.validation.models import PublishType + + plugins = [ + { + "name": "Test Plugin", + "module_name": "module_name", + "project_link": "project_link", + "author_id": 999, # 不同的作者 ID + } + ] + plugin_path = tmp_path / "plugins.json5" + dump_json5(plugin_path, plugins) + mocker.patch.object(plugin_config.input_config, "plugin_path", plugin_path) + + mock_issue = MockIssue( + body=generate_issue_body_remove("Plugin", "project_link:module_name"), + user=MockUser(login="test", id=1), # 当前用户 ID 为 1 + ).as_mock(mocker) + + with pytest.raises(PydanticCustomError) as exc_info: + await validate_author_info(mock_issue, PublishType.PLUGIN) + + assert exc_info.value.type == "author_info" + + +async def test_validate_author_info_missing_info( + app: App, mocker: MockerFixture, tmp_path: Path +): + """测试验证作者信息 - 缺少必要信息""" + from src.plugins.github.plugins.remove.validation import validate_author_info + from src.providers.validation.models import PublishType + + # 创建一个没有完整信息的 issue body + mock_issue = MockIssue( + body="### PyPI 项目名\n\n\n\n### import 包名\n\n", # 空的项目名和模块名 + user=MockUser(login="test", id=1), + ).as_mock(mocker) + + with pytest.raises(PydanticCustomError) as exc_info: + await validate_author_info(mock_issue, PublishType.PLUGIN) + + assert exc_info.value.type == "info_not_found" + + +async def test_validate_author_info_unsupported_type( + app: App, mocker: MockerFixture, tmp_path: Path +): + """测试验证作者信息 - 不支持的类型""" + from src.plugins.github.plugins.remove.validation import validate_author_info + from src.providers.validation.models import PublishType + + mock_issue = MockIssue( + body="some content", + user=MockUser(login="test", id=1), + ).as_mock(mocker) + + with pytest.raises(PydanticCustomError) as exc_info: + await validate_author_info(mock_issue, PublishType.DRIVER) + + assert exc_info.value.type == "not_support" + + +async def test_validate_author_info_bot_missing_info( + app: App, mocker: MockerFixture, tmp_path: Path +): + """测试验证机器人作者信息 - 缺少必要信息""" + from src.plugins.github.plugins.remove.validation import validate_author_info + from src.providers.validation.models import PublishType + + # 创建一个缺少 homepage 的 issue body + mock_issue = MockIssue( + body="### 机器人名称\n\nTestBot\n\n### 机器人项目仓库/主页链接\n\n", + user=MockUser(login="test", id=1), + ).as_mock(mocker) + + with pytest.raises(PydanticCustomError) as exc_info: + await validate_author_info(mock_issue, PublishType.BOT) + + assert exc_info.value.type == "info_not_found" + + +async def test_validate_author_info_use_module_name_fallback( + app: App, mocker: MockerFixture, tmp_path: Path +): + """测试验证作者信息 - 使用 module_name 作为 name 的回退""" + from src.plugins.github import plugin_config + from src.plugins.github.plugins.remove.validation import validate_author_info + from src.providers.utils import dump_json5 + from src.providers.validation.models import PublishType + + plugins = [ + { + # 没有 name 字段 + "module_name": "nonebot_plugin_test", + "project_link": "nonebot-plugin-test", + "author_id": 1, + } + ] + plugin_path = tmp_path / "plugins.json5" + dump_json5(plugin_path, plugins) + mocker.patch.object(plugin_config.input_config, "plugin_path", plugin_path) + + mock_issue = MockIssue( + body=generate_issue_body_remove( + "Plugin", "nonebot-plugin-test:nonebot_plugin_test" + ), + user=MockUser(login="test", id=1), + ).as_mock(mocker) + + result = await validate_author_info(mock_issue, PublishType.PLUGIN) + + assert result.publish_type == PublishType.PLUGIN + # 应该使用 module_name 作为 name + assert result.name == "nonebot_plugin_test" diff --git a/tests/plugins/github/resolve/test_resolve_close_issue.py b/tests/plugins/github/resolve/test_resolve_close_issue.py index 757500ec..82fbc8a4 100644 --- a/tests/plugins/github/resolve/test_resolve_close_issue.py +++ b/tests/plugins/github/resolve/test_resolve_close_issue.py @@ -9,13 +9,11 @@ from tests.plugins.github.event import get_mock_event from tests.plugins.github.resolve.utils import get_pr_labels from tests.plugins.github.utils import ( - GitHubApi, MockIssue, assert_subprocess_run_calls, generate_issue_body_remove, get_github_bot, mock_subprocess_run_with_side_effect, - should_call_apis, ) @@ -47,40 +45,33 @@ async def test_resolve_close_issue( event.payload.pull_request.labels = get_pr_labels(["Publish", "Bot"]) event.payload.pull_request.merged = False - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.apps.async_get_repo_installation", - result=mock_installation, - ), - GitHubApi( - api="rest.apps.async_create_installation_access_token", - result=mock_installation_token, - ), - GitHubApi( - api="rest.issues.async_get", - result=mock_issues_resp, - ), - GitHubApi( - api="rest.issues.async_update", - result=mock_issues_resp, - ), - ], + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + snapshot({"owner": "he0119", "repo": "action-test"}), + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + snapshot({"installation_id": mock_installation.parsed_data.id}), + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + snapshot({"owner": "he0119", "repo": "action-test", "issue_number": 76}), + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", snapshot( - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 76}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 76, - "state": "closed", - "state_reason": "not_planned", - }, - ] + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 76, + "state": "closed", + "state_reason": "not_planned", + } ), + mock_issues_resp, ) ctx.receive_event(bot, event) ctx.should_pass_rule(pr_close_matcher) @@ -139,40 +130,33 @@ async def test_resolve_close_issue_already_closed( event.payload.pull_request.labels = get_pr_labels(["Publish", "Bot"]) event.payload.pull_request.merged = False - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.apps.async_get_repo_installation", - result=mock_installation, - ), - GitHubApi( - api="rest.apps.async_create_installation_access_token", - result=mock_installation_token, - ), - GitHubApi( - api="rest.issues.async_get", - result=mock_issues_resp, - ), - GitHubApi( - api="rest.issues.async_update", - result=mock_issues_resp, - ), - ], + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + snapshot({"owner": "he0119", "repo": "action-test"}), + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + snapshot({"installation_id": mock_installation.parsed_data.id}), + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + snapshot({"owner": "he0119", "repo": "action-test", "issue_number": 76}), + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", snapshot( - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 76}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 76, - "state": "closed", - "state_reason": "not_planned", - }, - ] + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 76, + "state": "closed", + "state_reason": "not_planned", + } ), + mock_issues_resp, ) ctx.receive_event(bot, event) ctx.should_pass_rule(pr_close_matcher) diff --git a/tests/plugins/github/resolve/test_resolve_pull_request.py b/tests/plugins/github/resolve/test_resolve_pull_request.py index 884a2c72..400c02fe 100644 --- a/tests/plugins/github/resolve/test_resolve_pull_request.py +++ b/tests/plugins/github/resolve/test_resolve_pull_request.py @@ -12,14 +12,12 @@ from tests.plugins.github.event import get_mock_event from tests.plugins.github.resolve.utils import get_pr_labels from tests.plugins.github.utils import ( - GitHubApi, MockIssue, assert_subprocess_run_calls, generate_issue_body_bot, generate_issue_body_remove, get_github_bot, mock_subprocess_run_with_side_effect, - should_call_apis, ) @@ -134,64 +132,76 @@ async def test_resolve_pull_request( event.payload.pull_request.labels = get_pr_labels(["Remove", "Bot"]) event.payload.pull_request.merged = True - should_call_apis( - ctx, - [ - GitHubApi( - api="rest.apps.async_get_repo_installation", - result=mock_installation, - ), - GitHubApi( - api="rest.apps.async_create_installation_access_token", - result=mock_installation_token, - ), - GitHubApi(api="rest.issues.async_get", result=mock_issues_resp), - GitHubApi(api="rest.issues.async_update", result=True), - GitHubApi(api="rest.pulls.async_list", result=mock_pulls_resp), - GitHubApi(api="rest.issues.async_get", result=mock_publish_issue_resp), - GitHubApi( - api="rest.issues.async_list_comments", - result=mock_publish_list_comments_resp, - ), - GitHubApi( - api="rest.actions.async_list_workflow_run_artifacts", - result=mock_publish_artifact_resp, - ), - GitHubApi( - api="rest.actions.async_download_artifact", - result=mock_publish_download_artifact_resp, - ), - GitHubApi(api="rest.issues.async_get", result=mock_remove_issue_resp), - ], + ctx.should_call_api( + "rest.apps.async_get_repo_installation", + snapshot({"owner": "he0119", "repo": "action-test"}), + mock_installation, + ) + ctx.should_call_api( + "rest.apps.async_create_installation_access_token", + snapshot({"installation_id": mock_installation.parsed_data.id}), + mock_installation_token, + ) + ctx.should_call_api( + "rest.issues.async_get", + snapshot({"owner": "he0119", "repo": "action-test", "issue_number": 76}), + mock_issues_resp, + ) + ctx.should_call_api( + "rest.issues.async_update", snapshot( - [ - {"owner": "he0119", "repo": "action-test"}, - {"installation_id": mock_installation.parsed_data.id}, - {"owner": "he0119", "repo": "action-test", "issue_number": 76}, - { - "owner": "he0119", - "repo": "action-test", - "issue_number": 76, - "state": "closed", - "state_reason": "completed", - }, - {"owner": "he0119", "repo": "action-test", "state": "open"}, - {"owner": "he0119", "repo": "action-test", "issue_number": 100}, - {"owner": "he0119", "repo": "action-test", "issue_number": 100}, - { - "owner": "he0119", - "repo": "action-test", - "run_id": 14156878699, - }, - { - "owner": "he0119", - "repo": "action-test", - "artifact_id": 123456789, - "archive_format": "zip", - }, - {"owner": "he0119", "repo": "action-test", "issue_number": 101}, - ] + { + "owner": "he0119", + "repo": "action-test", + "issue_number": 76, + "state": "closed", + "state_reason": "completed", + } ), + True, + ) + ctx.should_call_api( + "rest.pulls.async_list", + snapshot({"owner": "he0119", "repo": "action-test", "state": "open"}), + mock_pulls_resp, + ) + ctx.should_call_api( + "rest.issues.async_get", + snapshot({"owner": "he0119", "repo": "action-test", "issue_number": 100}), + mock_publish_issue_resp, + ) + ctx.should_call_api( + "rest.issues.async_list_comments", + snapshot({"owner": "he0119", "repo": "action-test", "issue_number": 100}), + mock_publish_list_comments_resp, + ) + ctx.should_call_api( + "rest.actions.async_list_workflow_run_artifacts", + snapshot( + { + "owner": "he0119", + "repo": "action-test", + "run_id": 14156878699, + } + ), + mock_publish_artifact_resp, + ) + ctx.should_call_api( + "rest.actions.async_download_artifact", + snapshot( + { + "owner": "he0119", + "repo": "action-test", + "artifact_id": 123456789, + "archive_format": "zip", + } + ), + mock_publish_download_artifact_resp, + ) + ctx.should_call_api( + "rest.issues.async_get", + snapshot({"owner": "he0119", "repo": "action-test", "issue_number": 101}), + mock_remove_issue_resp, ) ctx.receive_event(bot, event) ctx.should_pass_rule(pr_close_matcher) diff --git a/tests/plugins/github/utils.py b/tests/plugins/github/utils.py index d3d38b85..aabbfed6 100644 --- a/tests/plugins/github/utils.py +++ b/tests/plugins/github/utils.py @@ -1,29 +1,14 @@ import json from dataclasses import dataclass, field from pathlib import Path -from typing import Any, Literal, NotRequired, TypedDict +from typing import Any, Literal from unittest.mock import MagicMock, call import pyjson5 from githubkit.rest import Issue -from nonebug.mixin.call_api import ApiContext -from nonebug.mixin.process import MatcherContext from pytest_mock import MockerFixture, MockFixture, MockType -class GitHubApi(TypedDict): - api: str - result: Any | None - exception: NotRequired[Exception | None] - - -def should_call_apis( - ctx: MatcherContext | ApiContext, apis: list[GitHubApi], data: list[Any] -) -> None: - for n, api in enumerate(apis): - ctx.should_call_api(**api, data=data[n]) - - def mock_subprocess_run_with_side_effect( mocker: MockerFixture, commands: dict[str, str] = {} ): diff --git a/tests/plugins/github/utils/test_github_utils.py b/tests/plugins/github/utils/test_github_utils.py new file mode 100644 index 00000000..4dea16dc --- /dev/null +++ b/tests/plugins/github/utils/test_github_utils.py @@ -0,0 +1,112 @@ +"""测试 plugins/github/utils.py""" + +import re +import subprocess +from re import Pattern +from unittest.mock import MagicMock + +import pytest +from pytest_mock import MockerFixture + + +def test_run_shell_command_success(mocker: MockerFixture): + """测试 run_shell_command 命令执行成功的情况""" + from src.plugins.github.utils import run_shell_command + + mock_result = MagicMock() + mock_result.stdout.decode.return_value = "command output" + + mock_run = mocker.patch("subprocess.run", return_value=mock_result) + + result = run_shell_command(["git", "status"]) + + mock_run.assert_called_once_with(["git", "status"], check=True, capture_output=True) + assert result == mock_result + + +def test_run_shell_command_failure(mocker: MockerFixture): + """测试 run_shell_command 命令执行失败时抛出异常""" + from src.plugins.github.utils import run_shell_command + + # 创建一个模拟的 CalledProcessError + error = subprocess.CalledProcessError(1, ["git", "status"]) + error.stdout = b"standard output" + error.stderr = b"error output" + + mock_run = mocker.patch("subprocess.run", side_effect=error) + + with pytest.raises(subprocess.CalledProcessError): + run_shell_command(["git", "status"]) + + mock_run.assert_called_once_with(["git", "status"], check=True, capture_output=True) + + +def test_commit_message(): + """测试 commit_message 函数""" + from src.plugins.github.utils import commit_message + + result = commit_message(":sparkles:", "add feature", 123) + assert result == ":sparkles: add feature (#123)" + + +def test_extract_issue_info_from_issue_single_pattern(): + """测试 extract_issue_info_from_issue 使用单个正则表达式""" + from src.plugins.github.utils import extract_issue_info_from_issue + + patterns: dict[str, Pattern[str] | list[Pattern[str]]] = { + "name": re.compile(r"Name: (\w+)"), + "version": re.compile(r"Version: ([\d.]+)"), + } + body = "Name: TestPlugin\nVersion: 1.0.0\n" + + result = extract_issue_info_from_issue(patterns, body) + + assert result == {"name": "TestPlugin", "version": "1.0.0"} + + +def test_extract_issue_info_from_issue_list_pattern(): + """测试 extract_issue_info_from_issue 使用正则表达式列表""" + from src.plugins.github.utils import extract_issue_info_from_issue + + patterns: dict[str, Pattern[str] | list[Pattern[str]]] = { + "module": [ + re.compile(r"Module Name: (\w+)"), + re.compile(r"Import Name: (\w+)"), + ], + } + body = "Import Name: test_module\n" + + result = extract_issue_info_from_issue(patterns, body) + + assert result == {"module": "test_module"} + + +def test_extract_issue_info_from_issue_no_match(): + """测试 extract_issue_info_from_issue 未匹配时返回空字典""" + from src.plugins.github.utils import extract_issue_info_from_issue + + patterns: dict[str, Pattern[str] | list[Pattern[str]]] = { + "name": re.compile(r"Name: (\w+)"), + } + body = "No matching content here" + + result = extract_issue_info_from_issue(patterns, body) + + assert result == {} + + +def test_extract_issue_info_from_issue_partial_match(): + """测试 extract_issue_info_from_issue 部分匹配""" + from src.plugins.github.utils import extract_issue_info_from_issue + + patterns: dict[str, Pattern[str] | list[Pattern[str]]] = { + "name": re.compile(r"Name: (\w+)"), + "version": re.compile(r"Version: ([\d.]+)"), + } + body = "Name: TestPlugin\n" + + result = extract_issue_info_from_issue(patterns, body) + + # 只返回匹配到的项 + assert result == {"name": "TestPlugin"} + assert "version" not in result diff --git a/tests/providers/docker_test/test_docker_plugin_test.py b/tests/providers/docker_test/test_docker_plugin_test.py index 8f4d2f6b..3c41ff79 100644 --- a/tests/providers/docker_test/test_docker_plugin_test.py +++ b/tests/providers/docker_test/test_docker_plugin_test.py @@ -398,3 +398,65 @@ async def test_docker_plugin_test_metadata_some_fields_invalid( } }, ) + + +async def test_docker_plugin_test_file_invalid_and_output_invalid( + mocked_api: MockRouter, + mocker: MockerFixture, + tmp_path: Path, +): + """测试结果文件解析失败且容器输出也无法解析为 JSON""" + from src.providers.constants import DOCKER_BIND_RESULT_PATH + from src.providers.docker_test import DockerPluginTest, DockerTestResult + + mocker.patch("src.providers.docker_test.PLUGIN_TEST_DIR", tmp_path) + test_result_path = tmp_path / "project-link-module-name.json" + + # 写入无效的 JSON 到测试结果文件 + with open(test_result_path, "w", encoding="utf-8") as f: + f.write("invalid json {") + + mocked_run = mocker.Mock() + # 容器输出也是无效的 JSON + mocked_run.return_value = b"not a valid json output" + mocked_client = mocker.Mock() + mocked_client.containers.run = mocked_run + mocked_docker = mocker.patch("docker.DockerClient") + mocked_docker.return_value = mocked_client + + test = DockerPluginTest("project_link", "module_name") + result = await test.run("3.12") + + # 验证返回的结果 + assert result == snapshot( + DockerTestResult( + run=True, + load=False, + output="""\ + + 测试结果文件解析失败,输出内容写入失败。 + Expecting value: line 1 column 1 (char 0) + 输出内容:b'not a valid json output' + \ +""", + ) + ) + + assert not mocked_api["store_plugins"].called + mocked_run.assert_called_once_with( + "ghcr.io/nonebot/nonetest:latest", + environment={ + "PROJECT_LINK": "project_link", + "MODULE_NAME": "module_name", + "PLUGIN_CONFIG": "", + "PYTHON_VERSION": "3.12", + }, + detach=False, + remove=True, + volumes={ + test_result_path.resolve(strict=False).as_posix(): { + "bind": DOCKER_BIND_RESULT_PATH, + "mode": "rw", + } + }, + ) diff --git a/tests/providers/docker_test/test_plugin_test.py b/tests/providers/docker_test/test_plugin_test.py index 6885debc..94d7e35b 100644 --- a/tests/providers/docker_test/test_plugin_test.py +++ b/tests/providers/docker_test/test_plugin_test.py @@ -183,3 +183,412 @@ def command_output(cmd: str, timeout: int = 300): mocked_get_plugin_list.assert_called_once() mocked_command.assert_called() + + +async def test_plugin_test_dir_exists(mocker: MockerFixture, tmp_path: Path): + """测试项目目录已存在的情况""" + from src.providers.docker_test.plugin_test import PluginTest + + test = PluginTest("3.12", "project_link", "module_name") + + test_dir = tmp_path / "plugin_test" + test_dir.mkdir() + mocker.patch.object(test, "_test_dir", test_dir) + + # Mock command 函数 + async def mock_command(cmd: str, timeout: int = 300): # noqa: ASYNC109 + if cmd == "poetry show project_link": + return ( + True, + """ +name : project_link +version : 1.0.0 +description : A test plugin""", + "", + ) + if cmd == "poetry export --without-hashes": + return ( + True, + """ +nonebot2==2.4.0 ; python_version >= "3.9" +pydantic==2.10.0 ; python_version >= "3.9" +""", + "", + ) + if cmd == "poetry run python --version": + return (True, "Python 3.12.5", "") + if cmd == "poetry run python runner.py": + return (True, "", "") + return (False, "", "") + + mocker.patch.object(test, "command", mock_command) + mocker.patch( + "src.providers.docker_test.plugin_test.get_plugin_list", return_value={} + ) + + result = await test.run() + + # 验证跳过创建 + assert "已存在,跳过创建" in result["output"] + assert result["run"] is True + assert result["load"] is True + + +async def test_plugin_test_create_failed(mocker: MockerFixture, tmp_path: Path): + """测试项目创建失败的情况""" + from src.providers.docker_test.plugin_test import PluginTest + + # 使用连字符格式的 project_link,因为 canonicalize_name 会将其转换为这种格式 + test = PluginTest("3.12", "project-link", "module_name") + + mocker.patch.object(test, "_test_dir", tmp_path / "plugin_test") + + # Mock command 函数,模拟创建失败 + async def mock_command(cmd: str, timeout: int = 300): # noqa: ASYNC109 + if "poetry add" in cmd: + return ( + False, + "", + """ +Using version ^1.0.0 for project-link + +Updating dependencies +Resolving dependencies... (error) +""", + ) + return (False, "", "") + + mocker.patch.object(test, "command", mock_command) + mocker.patch( + "src.providers.docker_test.plugin_test.get_plugin_list", return_value={} + ) + + result = await test.run() + + # 验证创建失败 + assert "创建失败" in result["output"] + assert result["run"] is False + assert result["load"] is False + # 应该从错误输出中提取版本号 + assert result["version"] == "1.0.0" + + +async def test_plugin_test_show_package_info_failed( + mocker: MockerFixture, tmp_path: Path +): + """测试获取插件信息失败的情况""" + from src.providers.docker_test.plugin_test import PluginTest + + test = PluginTest("3.12", "project_link", "module_name") + + test_dir = tmp_path / "plugin_test" + test_dir.mkdir() + mocker.patch.object(test, "_test_dir", test_dir) + + async def mock_command(cmd: str, timeout: int = 300): # noqa: ASYNC109 + if cmd == "poetry show project_link": + return (False, "", "Error: package not found") + if cmd == "poetry export --without-hashes": + return ( + True, + "nonebot2==2.4.0 ; python_version >= '3.9'", + "", + ) + if cmd == "poetry run python --version": + return (True, "Python 3.12.5", "") + if cmd == "poetry run python runner.py": + return (True, "", "") + return (True, "", "") + + mocker.patch.object(test, "command", mock_command) + mocker.patch( + "src.providers.docker_test.plugin_test.get_plugin_list", return_value={} + ) + + result = await test.run() + + # 验证信息获取失败 + assert "信息获取失败" in result["output"] + + +async def test_plugin_test_run_failed(mocker: MockerFixture, tmp_path: Path): + """测试插件运行失败的情况""" + from src.providers.docker_test.plugin_test import PluginTest + + test = PluginTest("3.12", "project_link", "module_name") + + test_dir = tmp_path / "plugin_test" + test_dir.mkdir() + mocker.patch.object(test, "_test_dir", test_dir) + + async def mock_command(cmd: str, timeout: int = 300): # noqa: ASYNC109 + if cmd == "poetry show project_link": + return (True, "version : 1.0.0", "") + if cmd == "poetry export --without-hashes": + return (True, "nonebot2==2.4.0 ; python_version >= '3.9'", "") + if cmd == "poetry run python --version": + return (True, "Python 3.12.5", "") + if cmd == "poetry run python runner.py": + return (False, "", "ImportError: module not found") + return (True, "", "") + + mocker.patch.object(test, "command", mock_command) + mocker.patch( + "src.providers.docker_test.plugin_test.get_plugin_list", return_value={} + ) + + result = await test.run() + + assert "加载出错" in result["output"] + assert result["load"] is False + + +async def test_plugin_test_show_dependencies_failed( + mocker: MockerFixture, tmp_path: Path +): + """测试获取依赖失败的情况""" + from src.providers.docker_test.plugin_test import PluginTest + + test = PluginTest("3.12", "project_link", "module_name") + + test_dir = tmp_path / "plugin_test" + test_dir.mkdir() + mocker.patch.object(test, "_test_dir", test_dir) + + async def mock_command(cmd: str, timeout: int = 300): # noqa: ASYNC109 + if cmd == "poetry show project_link": + return (True, "version : 1.0.0", "") + if cmd == "poetry export --without-hashes": + return (False, "", "Error: could not export") + if cmd == "poetry run python --version": + return (True, "Python 3.12.5", "") + if cmd == "poetry run python runner.py": + return (True, "", "") + return (True, "", "") + + mocker.patch.object(test, "command", mock_command) + mocker.patch( + "src.providers.docker_test.plugin_test.get_plugin_list", return_value={} + ) + + result = await test.run() + + assert "依赖获取失败" in result["output"] + + +async def test_plugin_test_get_python_version_failed( + mocker: MockerFixture, tmp_path: Path +): + """测试获取 Python 版本失败的情况""" + from src.providers.docker_test.plugin_test import PluginTest + + test = PluginTest("3.12", "project_link", "module_name") + + test_dir = tmp_path / "plugin_test" + test_dir.mkdir() + mocker.patch.object(test, "_test_dir", test_dir) + + async def mock_command(cmd: str, timeout: int = 300): # noqa: ASYNC109 + if cmd == "poetry show project_link": + return (True, "version : 1.0.0", "") + if cmd == "poetry export --without-hashes": + return (True, "nonebot2==2.4.0 ; python_version >= '3.9'", "") + if cmd == "poetry run python --version": + return (False, "", "Python not found") + if cmd == "poetry run python runner.py": + return (True, "", "") + return (True, "", "") + + mocker.patch.object(test, "command", mock_command) + mocker.patch( + "src.providers.docker_test.plugin_test.get_plugin_list", return_value={} + ) + + result = await test.run() + + assert "Python 版本获取失败" in result["output"] + # 版本应该是 unknown + assert "python==unknown" in result["test_env"] + + +async def test_plugin_test_metadata_read_json_decode_error( + mocker: MockerFixture, tmp_path: Path +): + """测试 metadata.json 格式不正确的情况""" + from src.providers.docker_test.plugin_test import PluginTest + + test = PluginTest("3.12", "project_link", "module_name") + + test_dir = tmp_path / "plugin_test" + test_dir.mkdir() + mocker.patch.object(test, "_test_dir", test_dir) + + async def mock_command(cmd: str, timeout: int = 300): # noqa: ASYNC109 + if cmd == "poetry show project_link": + return (True, "version : 1.0.0", "") + if cmd == "poetry export --without-hashes": + return (True, "nonebot2==2.4.0 ; python_version >= '3.9'", "") + if cmd == "poetry run python --version": + return (True, "Python 3.12.5", "") + if cmd == "poetry run python runner.py": + # 写入格式不正确的 metadata.json + with open(test_dir / "metadata.json", "w") as f: + f.write("invalid json {") + return (True, "", "") + return (True, "", "") + + mocker.patch.object(test, "command", mock_command) + mocker.patch( + "src.providers.docker_test.plugin_test.get_plugin_list", return_value={} + ) + + result = await test.run() + + assert "metadata.json 格式不正确" in result["output"] + assert result["metadata"] is None + + +async def test_plugin_test_metadata_read_exception( + mocker: MockerFixture, tmp_path: Path +): + """测试 metadata.json 读取时发生其他异常的情况""" + from src.providers.docker_test.plugin_test import PluginTest + + test = PluginTest("3.12", "project_link", "module_name") + + test_dir = tmp_path / "plugin_test" + test_dir.mkdir() + mocker.patch.object(test, "_test_dir", test_dir) + + async def mock_command(cmd: str, timeout: int = 300): # noqa: ASYNC109 + if cmd == "poetry show project_link": + return (True, "version : 1.0.0", "") + if cmd == "poetry export --without-hashes": + return (True, "nonebot2==2.4.0 ; python_version >= '3.9'", "") + if cmd == "poetry run python --version": + return (True, "Python 3.12.5", "") + if cmd == "poetry run python runner.py": + # 创建 metadata.json,但模拟读取时出错 + metadata_path = test_dir / "metadata.json" + metadata_path.write_text('{"name": "test"}') + return (True, "", "") + return (True, "", "") + + mocker.patch.object(test, "command", mock_command) + mocker.patch( + "src.providers.docker_test.plugin_test.get_plugin_list", return_value={} + ) + + # Mock Path.read_text 使其抛出 OSError + original_read_text = Path.read_text + + def mock_read_text(self, *args, **kwargs): + if "metadata.json" in str(self): + raise OSError("Permission denied") + return original_read_text(self, *args, **kwargs) + + mocker.patch.object(Path, "read_text", mock_read_text) + + result = await test.run() + + assert "插件元数据读取失败" in result["output"] + assert result["metadata"] is None + + +async def test_plugin_test_get_deps_with_plugin_dependencies( + mocker: MockerFixture, tmp_path: Path +): + """测试获取依赖时包含其他插件的情况""" + from src.providers.docker_test.plugin_test import PluginTest + + test = PluginTest("3.12", "project-link", "module_name") + + test_dir = tmp_path / "plugin_test" + test_dir.mkdir() + mocker.patch.object(test, "_test_dir", test_dir) + + async def mock_command(cmd: str, timeout: int = 300): # noqa: ASYNC109 + if cmd == "poetry show project-link": + return (True, "version : 1.0.0", "") + if cmd == "poetry export --without-hashes": + return ( + True, + """ +nonebot2==2.4.0 ; python_version >= '3.9' +pydantic==2.10.0 ; python_version >= '3.9' +nonebot-plugin-dep==1.0.0 ; python_version >= '3.9' +project-link==1.0.0 ; python_version >= '3.9' +""", + "", + ) + if cmd == "poetry run python --version": + return (True, "Python 3.12.5", "") + if cmd == "poetry run python runner.py": + return (True, "", "") + return (True, "", "") + + mocker.patch.object(test, "command", mock_command) + # 模拟插件列表中包含 nonebot-plugin-dep + mocker.patch( + "src.providers.docker_test.plugin_test.get_plugin_list", + return_value={ + "nonebot-plugin-dep": "nonebot_plugin_dep", + "project-link": "module_name", # 自己不应该被包含 + }, + ) + + result = await test.run() + + # 验证依赖中包含 nonebot_plugin_dep,但不包含自己 + assert "nonebot_plugin_dep" in result["output"] + + +def test_strip_ansi(): + """测试 strip_ansi 函数""" + from src.providers.docker_test.plugin_test import strip_ansi + + # 测试普通字符串 + assert strip_ansi("Hello World") == "Hello World" + + # 测试带 ANSI 转义序列的字符串 + assert strip_ansi("\x1b[31mRed\x1b[0m") == "Red" + + # 测试 None + assert strip_ansi(None) == "" + + # 测试空字符串 + assert strip_ansi("") == "" + + +def test_canonicalize_name(): + """测试 canonicalize_name 函数""" + from src.providers.docker_test.plugin_test import canonicalize_name + + assert canonicalize_name("NoneBot-Plugin-Test") == "nonebot-plugin-test" + assert canonicalize_name("nonebot_plugin_test") == "nonebot-plugin-test" + assert canonicalize_name("nonebot.plugin.test") == "nonebot-plugin-test" + + +async def test_get_plugin_list(mocker: MockerFixture): + """测试 get_plugin_list 函数""" + from src.providers.docker_test.plugin_test import get_plugin_list + + mock_response = mocker.MagicMock() + mock_response.json.return_value = [ + {"project_link": "nonebot-plugin-test", "module_name": "nonebot_plugin_test"}, + { + "project_link": "nonebot-plugin-example", + "module_name": "nonebot_plugin_example", + }, + ] + + mock_get = mocker.patch("httpx.get", return_value=mock_response) + + result = get_plugin_list() + + assert result == { + "nonebot-plugin-test": "nonebot_plugin_test", + "nonebot-plugin-example": "nonebot_plugin_example", + } + + mock_get.assert_called_once() diff --git a/tests/providers/store_test/test_store_registry_update.py b/tests/providers/store_test/test_store_registry_update.py new file mode 100644 index 00000000..bacce18b --- /dev/null +++ b/tests/providers/store_test/test_store_registry_update.py @@ -0,0 +1,320 @@ +"""测试 store.py 中的 registry_update 函数不同分支""" + +from pathlib import Path + +from pytest_mock import MockerFixture +from respx import MockRouter + + +async def test_registry_update_adapter( + mocked_store_data: dict[str, Path], mocked_api: MockRouter, mocker: MockerFixture +) -> None: + """测试 registry_update 函数处理 RegistryAdapter 的分支""" + from src.providers.models import ( + Color, + RegistryAdapter, + RegistryArtifactData, + StoreAdapter, + Tag, + ) + from src.providers.store_test.store import StoreTest + + test = StoreTest() + + # 创建一个新的适配器数据 + new_adapter = RegistryAdapter( + module_name="nonebot.adapters.new", + project_link="nonebot-adapter-new", + name="New Adapter", + desc="A new adapter", + author="test_author", + homepage="https://example.com", + tags=[Tag(label="new", color=Color("#ffffff"))], + is_official=False, + time="2024-01-01T00:00:00Z", + version="1.0.0", + ) + + store_adapter = StoreAdapter( + module_name="nonebot.adapters.new", + project_link="nonebot-adapter-new", + name="New Adapter", + desc="A new adapter", + author_id=123, + homepage="https://example.com", + tags=[Tag(label="new", color=Color("#ffffff"))], + is_official=False, + ) + + artifact_data = RegistryArtifactData( + store=store_adapter, + registry=new_adapter, + store_test_result=None, + ) + + # 执行 registry_update + await test.registry_update(artifact_data) + + # 验证适配器已添加 + assert new_adapter.key in test._previous_adapters + assert test._previous_adapters[new_adapter.key] == new_adapter + + +async def test_registry_update_bot( + mocked_store_data: dict[str, Path], mocked_api: MockRouter, mocker: MockerFixture +) -> None: + """测试 registry_update 函数处理 RegistryBot 的分支""" + from src.providers.models import ( + Color, + RegistryArtifactData, + RegistryBot, + StoreBot, + Tag, + ) + from src.providers.store_test.store import StoreTest + + test = StoreTest() + + # 创建一个新的机器人数据 + new_bot = RegistryBot( + name="New Bot", + desc="A new bot", + author="test_author", + homepage="https://example.com/newbot", + tags=[Tag(label="new", color=Color("#ffffff"))], + is_official=False, + ) + + store_bot = StoreBot( + name="New Bot", + desc="A new bot", + author_id=123, + homepage="https://example.com/newbot", + tags=[Tag(label="new", color=Color("#ffffff"))], + is_official=False, + ) + + artifact_data = RegistryArtifactData( + store=store_bot, + registry=new_bot, + store_test_result=None, + ) + + # 执行 registry_update + await test.registry_update(artifact_data) + + # 验证机器人已添加 + assert new_bot.key in test._previous_bots + assert test._previous_bots[new_bot.key] == new_bot + + +async def test_registry_update_driver( + mocked_store_data: dict[str, Path], mocked_api: MockRouter, mocker: MockerFixture +) -> None: + """测试 registry_update 函数处理 RegistryDriver 的分支""" + from src.providers.models import ( + Color, + RegistryArtifactData, + RegistryDriver, + StoreDriver, + Tag, + ) + from src.providers.store_test.store import StoreTest + + test = StoreTest() + + # 创建一个新的驱动器数据 + new_driver = RegistryDriver( + module_name="~newdriver", + project_link="nonebot2[newdriver]", + name="New Driver", + desc="A new driver", + author="test_author", + homepage="https://example.com/newdriver", + tags=[Tag(label="new", color=Color("#ffffff"))], + is_official=True, + time="2024-01-01T00:00:00Z", + version="1.0.0", + ) + + store_driver = StoreDriver( + module_name="~newdriver", + project_link="nonebot2[newdriver]", + name="New Driver", + desc="A new driver", + author_id=123, + homepage="https://example.com/newdriver", + tags=[Tag(label="new", color=Color("#ffffff"))], + is_official=True, + ) + + artifact_data = RegistryArtifactData( + store=store_driver, + registry=new_driver, + store_test_result=None, + ) + + # 执行 registry_update + await test.registry_update(artifact_data) + + # 验证驱动器已添加 + assert new_driver.key in test._previous_drivers + assert test._previous_drivers[new_driver.key] == new_driver + + +async def test_registry_update_plugin_with_result( + mocked_store_data: dict[str, Path], mocked_api: MockRouter, mocker: MockerFixture +) -> None: + """测试 registry_update 函数处理带测试结果的 RegistryPlugin 的分支""" + from src.providers.models import ( + Color, + RegistryArtifactData, + RegistryPlugin, + StorePlugin, + StoreTestResult, + Tag, + ) + from src.providers.store_test.store import StoreTest + + test = StoreTest() + + # 创建一个新的插件数据 + new_plugin = RegistryPlugin( + module_name="nonebot_plugin_new", + project_link="nonebot-plugin-new", + name="New Plugin", + desc="A new plugin", + author="test_author", + homepage="https://example.com/newplugin", + tags=[Tag(label="new", color=Color("#ffffff"))], + is_official=False, + type="application", + supported_adapters=None, + valid=True, + time="2024-01-01T00:00:00Z", + version="1.0.0", + skip_test=False, + ) + + store_plugin = StorePlugin( + module_name="nonebot_plugin_new", + project_link="nonebot-plugin-new", + author_id=123, + tags=[Tag(label="new", color=Color("#ffffff"))], + is_official=False, + ) + + # 创建测试结果 + test_result = StoreTestResult( + time="2024-01-01T00:00:00+08:00", + config="TEST_CONFIG=value", + version="1.0.0", + test_env={"python==3.12": True}, + results={"validation": True, "load": True, "metadata": True}, + outputs={ + "validation": None, + "load": "Plugin loaded successfully", + "metadata": { + "name": "New Plugin", + "description": "A new plugin", + }, + }, + ) + + artifact_data = RegistryArtifactData( + store=store_plugin, + registry=new_plugin, + store_test_result=test_result, + ) + + # 执行 registry_update + await test.registry_update(artifact_data) + + # 验证插件已添加 + assert new_plugin.key in test._previous_plugins + assert test._previous_plugins[new_plugin.key] == new_plugin + + # 验证测试结果已添加 + assert new_plugin.key in test._previous_results + assert test._previous_results[new_plugin.key] == test_result + + # 验证配置已保存 + assert test._plugin_configs[new_plugin.key] == "TEST_CONFIG=value" + + +async def test_registry_update_existing_key_not_updated( + mocked_store_data: dict[str, Path], mocked_api: MockRouter, mocker: MockerFixture +) -> None: + """测试 registry_update 函数不会覆盖已存在的数据""" + from src.providers.models import ( + Color, + RegistryArtifactData, + RegistryPlugin, + StorePlugin, + StoreTestResult, + Tag, + ) + from src.providers.store_test.store import StoreTest + + test = StoreTest() + + # 获取一个已存在的插件 key + existing_key = next(iter(test._previous_plugins.keys())) + existing_plugin = test._previous_plugins[existing_key] + existing_result = test._previous_results.get(existing_key) + + # 尝试用新数据更新 + new_plugin = RegistryPlugin( + module_name=existing_plugin.module_name, + project_link=existing_plugin.project_link, + name="Updated Name", + desc="Updated desc", + author="updated_author", + homepage="https://updated.com", + tags=[Tag(label="updated", color=Color("#000000"))], + is_official=True, + type="library", + supported_adapters=["adapter1"], + valid=True, + time="2025-01-01T00:00:00Z", + version="2.0.0", + skip_test=True, + ) + + store_plugin = StorePlugin( + module_name=existing_plugin.module_name, + project_link=existing_plugin.project_link, + author_id=456, + tags=[Tag(label="updated", color=Color("#000000"))], + is_official=True, + ) + + new_result = StoreTestResult( + time="2025-01-01T00:00:00+08:00", + config="NEW_CONFIG=value", + version="2.0.0", + test_env={"python==3.13": True}, + results={"validation": True, "load": True, "metadata": True}, + outputs={ + "validation": None, + "load": "Updated load output", + "metadata": {"name": "Updated"}, + }, + ) + + artifact_data = RegistryArtifactData( + store=store_plugin, + registry=new_plugin, + store_test_result=new_result, + ) + + # 执行 registry_update + await test.registry_update(artifact_data) + + # 验证插件未被更新(因为 key 已存在) + assert test._previous_plugins[existing_key] == existing_plugin + assert test._previous_plugins[existing_key].name != "Updated Name" + + # 验证结果也未被更新(如果原来存在) + if existing_result is not None: + assert test._previous_results[existing_key] == existing_result