test(vcs): assert what a provider refuses instead of skipping - #220
Open
HarshMN2345 wants to merge 1 commit into
Open
test(vcs): assert what a provider refuses instead of skipping#220HarshMN2345 wants to merge 1 commit into
HarshMN2345 wants to merge 1 commit into
Conversation
A declared capability dropped the test that needed it. Where the adapter documents a refusal, the shared test now asserts it, and where the provider answers differently the test asserts that answer. Four behaviours the sharing surfaced: - Gitea says 'synchronized' for a pushed head. Consumers only act on 'synchronize', so a pull request update was read as an unknown action. - GitLab raised a bare Exception for a repository that does not exist, and answered the old path of a deleted one through a redirect. - GitHub asked for a user with no credential, the only call in the adapter that did. - getInstallationRepository() was stubbed three times over; the refusal belongs on Git, next to the other five. The pull request action mapping and the head commit test move into the unit tier, leaving no test of its own in GitLab's class. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
HarshMN2345
requested review from
Meldiron,
abnegate,
eldadfux and
loks0n
as code owners
September 7, 2026 07:49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A capability the shared suite declares unsupported dropped the test that needed it.
$supportsTags = falsemeant nobody ever checked what the adapter does when asked for a tag. This makes a capability narrow a test instead of removing it: where the adapter documents a refusal the test asserts it, and where the provider answers differently the test asserts that answer.The e2e base goes from 45 skips to 27. The unit tier gains two shared tests and loses three that were written out per adapter.
Refusals are asserted, not skipped
assertRefused()requires the message theGitdefaults already use,X() is not supported by <name>, so a 404 from a repository that never existed cannot pass for a refusal. Nine capabilities assert their refusal: repository languages, commit statuses and their lookup, pull request creation and lookup, tags, check runs, namespaces, and installation repositories.GitHub's three stubs said
Not implemented; Gogs's seven saidPull request API is not supported by Gogs. Both now name the method, which is what makes the assertion meaningful.Skips that were hiding an answer
testListBranchesEmptyRepository[master]— the adapter asks for an initial committestListTagsCommitlessRepository[], which holds either waytestGetCommitAuthorAvatar''assertCommitAuthorLinks'', so a provider that starts reporting one flips the flagtestGetOwnerNameWith{out,Zero,Null}RepositoryIdtestGenerateCloneCommandWithTagtestGetUserWithInvalidUsernametestGetRepositoryAfterDeleteFailsassertIsArrayon a method typed: array[]Adapter changes
Sharing a test meant running it against a provider for the first time, which is where these came from.
synchronizedfor a pushed head. Every consumer acts onsynchronize— Appwrite's four VCS event handlers each test for it — so a pull request update on Gitea, Forgejo and Gogs was read as an action nobody handles. The adapter normalizes it; every other action passes through as sent.Exceptionfor a repository that does not exist, which is why the e2e class had to declare$repositoryNotFoundException = \Exception::class.getRepositoryName()andgetOwnerName()now raiseRepositoryNotFoundon a 404, and the flag is gone.getRepository()reported a repository that had been deleted. It no longer follows that redirect, which also drops$deletesRepositoriesSynchronously.GitHub::getUser()sent no credential, the only call in the adapter that did not, and returned the whole response rather than the body — a 404 came back looking like a user. GitHub's user lookup was switched off in the suite because of it.getInstallationRepository()was stubbed in three adapters with the wording each chose. Only GitHub and Origin model installations, so the refusal moved toGitbeside the other five.Tests hoisted into the unit tier
Two tests were provider specific only because the payload going in was.
Unit\GitLabTestandUnit\BitbucketTest, is now a declared$pullRequestActionsmap of native to shared name.Baseasserts every provider covers the three actions consumers act on and that nothing falls outside the vocabulary. Bitbucket names the action in the event rather than the payload, which one hook expresses.pushPayload()takes the commits to list before the head, andBaseasserts the head's hash, message, author and url.Unit\GitLabTestnow holds no test of its own.Unit\BitbucketTestkeeps the two that are genuinely Bitbucket: batched pushes and a linked commit author.Unit\OriginTestis outside this contract and untouched.Also
testGetRepositoryContentasserts the exact byte size rather than "greater than zero",testGetRepositoryPresignedUrlWithInvalidFormatasserts the message rather than any exception, andtestGetRepositoryWithNonExistingOwnerandtestGetRepositoryNameWithInvalidIdexpectRepositoryNotFound. Thirteen cleanup blocks moved ontodiscardRepositories(), which retries and reports a repository it could not remove instead of leaving it to contaminate later runs.testGetDeletedRepositoryFailslooked up a repository that was never deleted; it is nowtestGetNonExistingRepositoryFails, beside the one that does delete.The adapter guide's file tree still drew
tests/VCS/Adapter/andtests/VCS/Base.php, which the tier split replaced. It now describes both tiers, their hooks, and what belongs in an adapter's own class.Verification
bin/monorepo check vcsandbin/monorepo validatepass.The unit tier runs on a bare host and is green: 94 tests, 445 assertions, the one skip being Origin's live suite.
The e2e tier was run locally against the self-hosted providers, before and after, on the same containers:
Both green. Six fewer test methods is the three
getOwnerNameWith*RepositoryIdtests collapsing into one across three classes; thirteen fewer skips and twenty-nine more assertions is the point of the change.GitHub, GitLab and Bitbucket are not covered by that run. CI's e2e job cannot cover them either right now:
tests/credentials.phpfails its GitHub App preflight on this branch withappStatus: 401, errorCategory: issuer, which exits before PHPUnit starts and takes the whole tier with it. That preflight is untouched here, and the three commits that added it (c4869998,a4d80b70,c78ce23e) are the in-flight diagnosis of the same problem, so it needs the CI secret sorted out rather than a change to this branch.🤖 Generated with Claude Code