From 6ac84aee57f6c8d164a75104d11ef7574272e20e Mon Sep 17 00:00:00 2001 From: Gary Lockett Date: Wed, 17 Aug 2022 17:59:19 +0100 Subject: [PATCH 1/2] check the response code is >= 200 && <= 299 Signed-off-by: Gary Lockett --- src/Github/Api/V3/CreateReleaseThroughApiCall.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Github/Api/V3/CreateReleaseThroughApiCall.php b/src/Github/Api/V3/CreateReleaseThroughApiCall.php index cc6edebd..183f35f1 100644 --- a/src/Github/Api/V3/CreateReleaseThroughApiCall.php +++ b/src/Github/Api/V3/CreateReleaseThroughApiCall.php @@ -60,7 +60,7 @@ public function __invoke( $response = $this->client->sendRequest($request); - Psl\invariant($response->getStatusCode() >= 200 || $response->getStatusCode() <= 299, 'Failed to create release through GitHub API.'); + Psl\invariant($response->getStatusCode() >= 200 && $response->getStatusCode() <= 299, 'Failed to create release through GitHub API.'); $responseBody = $response ->getBody() From 926b6e0f1a2c458b0ae0a61f51e2e093510da64f Mon Sep 17 00:00:00 2001 From: Gary Lockett Date: Wed, 17 Aug 2022 18:35:45 +0100 Subject: [PATCH 2/2] add in test for release via api class Signed-off-by: Gary Lockett --- .../V3/CreateReleaseThroughApiCallTest.php | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 test/unit/Github/Api/V3/CreateReleaseThroughApiCallTest.php diff --git a/test/unit/Github/Api/V3/CreateReleaseThroughApiCallTest.php b/test/unit/Github/Api/V3/CreateReleaseThroughApiCallTest.php new file mode 100644 index 00000000..bae240b4 --- /dev/null +++ b/test/unit/Github/Api/V3/CreateReleaseThroughApiCallTest.php @@ -0,0 +1,186 @@ +httpClient = $this->createMock(ClientInterface::class); + $this->messageFactory = $this->createMock(RequestFactoryInterface::class); + $this->apiToken = 'apiToken' . SecureRandom\string(8); + $this->createRelease = new CreateReleaseThroughApiCall( + $this->messageFactory, + $this->httpClient, + $this->apiToken + ); + } + + /** + * @psalm-param positive-int $responseCode + * + * @dataProvider exampleValidResponseCodes + */ + public function testSuccessfulRequest(int $responseCode): void + { + $this->messageFactory + ->method('createRequest') + ->with('POST', 'https://api.github.com/repos/foo/bar/releases') + ->willReturn(new Request('https://the-domain.com/the-path')); + + $validResponse = (new Response()) + ->withStatus($responseCode); + + $validResponse->getBody() + ->write('{"html_url": "http://the-domain.com/release"}'); + + $this->httpClient + ->expects(self::once()) + ->method('sendRequest') + ->with(self::callback(function (RequestInterface $request): bool { + self::assertSame( + [ + 'Host' => ['the-domain.com'], + 'Content-Type' => ['application/json'], + 'User-Agent' => ['Ocramius\'s minimal API V3 client'], + 'Authorization' => ['token ' . $this->apiToken], + ], + $request->getHeaders() + ); + + self::assertJsonStringEqualsJsonString( + <<<'JSON' +{ + "body": "A description for my awesome release", + "name": "1.2.3", + "tag_name": "1.2.3" +} +JSON + , + $request->getBody() + ->__toString() + ); + + return true; + })) + ->willReturn($validResponse); + + self::assertEquals( + 'http://the-domain.com/release', + $this->createRelease->__invoke( + RepositoryName::fromFullName('foo/bar'), + SemVerVersion::fromMilestoneName('1.2.3'), + 'A description for my awesome release', + ) + ); + } + + /** @psalm-return non-empty-list */ + public function exampleValidResponseCodes(): array + { + return [ + [200], + [201], + [204], + ]; + } + + /** + * @psalm-param positive-int $responseCode + * + * @dataProvider exampleFailureResponseCodes + */ + public function testRequestFailedToCreateReleaseDueToInvalidResponseCode(int $responseCode): void + { + $this->messageFactory + ->method('createRequest') + ->with('POST', 'https://api.github.com/repos/foo/bar/releases') + ->willReturn(new Request('https://the-domain.com/the-path')); + + $invalidResponse = (new Response()) + ->withStatus($responseCode); + + $invalidResponse->getBody() + ->write('{"html_url": "http://the-domain.com/release"}'); + + $this->httpClient + ->expects(self::once()) + ->method('sendRequest') + ->willReturn($invalidResponse); + + $this->expectException(InvariantViolationException::class); + $this->expectExceptionMessage('Failed to create release through GitHub API.'); + + $this->createRelease->__invoke( + RepositoryName::fromFullName('foo/bar'), + SemVerVersion::fromMilestoneName('1.2.3'), + 'A description for my awesome release', + ); + } + + /** @psalm-return non-empty-list */ + public function exampleFailureResponseCodes(): array + { + return [ + [199], + [400], + [401], + [500], + ]; + } + + public function testRequestFailedToCreateReleaseDueToInvalidResponseBody(): void + { + $this->messageFactory + ->method('createRequest') + ->with('POST', 'https://api.github.com/repos/foo/bar/releases') + ->willReturn(new Request('https://the-domain.com/the-path')); + + $invalidResponse = (new Response()) + ->withStatus(200); + + $invalidResponse->getBody() + ->write('{"invalid": "response"}'); + + $this->httpClient + ->expects(self::once()) + ->method('sendRequest') + ->willReturn($invalidResponse); + + $this->expectException(DecodeException::class); + $this->expectExceptionMessage('"array{\'html_url\': non-empty-string}"'); + + $this->createRelease->__invoke( + RepositoryName::fromFullName('foo/bar'), + SemVerVersion::fromMilestoneName('1.2.3'), + 'A description for my awesome release', + ); + } +}