From 0dc10bd279876345da71b105d380f4d68c8ecbf9 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 4 Oct 2025 21:51:14 +0300 Subject: [PATCH] Fix authorization with header #10 --- composer.json | 2 +- src/Client.php | 11 +++--- tests/ClientTest.php | 82 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 79 insertions(+), 16 deletions(-) diff --git a/composer.json b/composer.json index c5988e7..8561291 100644 --- a/composer.json +++ b/composer.json @@ -66,7 +66,7 @@ } }, "scripts": { - "analyse": "vendor/bin/phpstan analyse -c phpstan.neon --memory-limit=256M", + "analyse": "vendor/bin/phpstan analyse -c phpstan.neon --memory-limit=512M", "format": "vendor/bin/php-cs-fixer fix --allow-risky=yes src", "test": "vendor/bin/phpunit", "test-coverage": "vendor/bin/phpunit --coverage-html coverage", diff --git a/src/Client.php b/src/Client.php index 742cbb9..999b889 100644 --- a/src/Client.php +++ b/src/Client.php @@ -71,7 +71,9 @@ public function request(string $method, string $uri, array $queryParams = [], ar ]); $fullUrl = $this->baseUrl . $uri . '?' . http_build_query($queryParams); - $request = $this->requestFactory->createRequest($method, $fullUrl); + $request = $this->requestFactory + ->createRequest($method, $fullUrl) + ->withHeader('Authorization', $this->accessToken); if (!empty($body)) { try { @@ -82,8 +84,7 @@ public function request(string $method, string $uri, array $queryParams = [], ar $stream = $this->streamFactory->createStream($payload); $request = $request ->withBody($stream) - ->withHeader('Content-Type', 'application/json; charset=utf-8') - ->withHeader('Authorization', $this->accessToken); + ->withHeader('Content-Type', 'application/json; charset=utf-8'); } try { @@ -143,6 +144,7 @@ public function multipartUpload(string $uri, mixed $fileContents, string $fileNa $request = $this->requestFactory ->createRequest('POST', $uri) ->withHeader('Content-Type', 'multipart/form-data; boundary=' . $boundary) + ->withHeader('Authorization', $this->accessToken) ->withBody($bodyStream); try { @@ -198,7 +200,8 @@ public function resumableUpload( ->withBody($chunkStream) ->withHeader('Content-Type', 'application/octet-stream') ->withHeader('Content-Disposition', 'attachment; filename="' . $fileName . '"') - ->withHeader('Content-Range', "bytes {$startByte}-{$endByte}/{$fileSize}"); + ->withHeader('Content-Range', "bytes {$startByte}-{$endByte}/{$fileSize}") + ->withHeader('Authorization', $this->accessToken); try { $response = $this->httpClient->sendRequest($request); diff --git a/tests/ClientTest.php b/tests/ClientTest.php index d2a85d1..b118007 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -107,6 +107,12 @@ public function successfulGetRequest(): void ->with('GET', $expectedUrl) ->willReturn($this->requestMock); + $this->requestMock + ->expects($this->once()) + ->method('withHeader') + ->with('Authorization', self::FAKE_TOKEN) + ->willReturn($this->requestMock); + $this->httpClientMock ->expects($this->once()) ->method('sendRequest') @@ -161,17 +167,18 @@ public function successfulPostRequestWithJsonBody(): void ->method('withHeader') ->willReturnCallback(function (string $header, string $value) use (&$headerCallCount) { if ($headerCallCount === 0) { - $this->assertSame('Content-Type', $header); - $this->assertSame('application/json; charset=utf-8', $value); - } elseif ($headerCallCount === 1) { $this->assertSame('Authorization', $header); $this->assertSame(self::FAKE_TOKEN, $value); + } elseif ($headerCallCount === 1) { + $this->assertSame('Content-Type', $header); + $this->assertSame('application/json; charset=utf-8', $value); } $headerCallCount++; return $this->requestMock; }); + $this->responseMock->method('getStatusCode')->willReturn(200); $this->streamMock->method('__toString')->willReturn(json_encode($responsePayload)); @@ -307,11 +314,23 @@ public function uploadMethodSendsCorrectMultipartRequest(): void ) ->willReturn($this->requestMock); + $headerCallCount = 0; $this->requestMock - ->expects($this->once()) + ->expects($this->exactly(2)) ->method('withHeader') - ->with($this->stringStartsWith('Content-Type'), $this->stringStartsWith('multipart/form-data')) - ->willReturn($this->requestMock); + ->willReturnCallback(function (string $header, string $value) use (&$headerCallCount) { + if ($headerCallCount === 0) { + $this->assertSame('Content-Type', $header); + $this->assertStringStartsWith('multipart/form-data; boundary=', $value); + } elseif ($headerCallCount === 1) { + $this->assertSame('Authorization', $header); + $this->assertSame(self::FAKE_TOKEN, $value); + } + + $headerCallCount++; + + return $this->requestMock; + }); $this->requestFactoryMock ->expects($this->once()) @@ -339,9 +358,26 @@ public function uploadMethodHandlesStreamResourceCorrectly(): void rewind($tmpFileHandle); $this->requestFactoryMock->method('createRequest')->willReturn($this->requestMock); - $this->requestMock->method('withHeader')->willReturn($this->requestMock); + + $headerCallCount = 0; + $this->requestMock + ->expects($this->exactly(2)) + ->method('withHeader') + ->willReturnCallback(function (string $header, string $value) use (&$headerCallCount) { + if ($headerCallCount === 0) { + $this->assertSame('Content-Type', $header); + $this->assertStringStartsWith('multipart/form-data; boundary=', $value); + } elseif ($headerCallCount === 1) { + $this->assertSame('Authorization', $header); + $this->assertSame(self::FAKE_TOKEN, $value); + } + + $headerCallCount++; + + return $this->requestMock; + }); + $this->requestMock->method('withBody')->willReturn($this->requestMock); -// $this->httpClientMock->method('sendRequest')->willReturn($this->responseMock); $this->responseMock->method('getStatusCode')->willReturn(200); $this->streamMock->method('__toString')->willReturn(json_encode($responsePayload)); @@ -475,7 +511,30 @@ public function resumableUploadSuccessfullyUploadsSingleChunk(): void $this->requestFactoryMock->method('createRequest')->willReturn($this->requestMock); $this->requestMock->method('withBody')->willReturnSelf(); - $this->requestMock->method('withHeader')->willReturnSelf(); + + $headerCallCount = 0; + $this->requestMock + ->expects($this->exactly(4)) + ->method('withHeader') + ->willReturnCallback(function (string $header, string $value) use (&$headerCallCount, $fileName, $fileSize) { + if ($headerCallCount === 0) { + $this->assertSame('Content-Type', $header); + $this->assertSame('application/octet-stream', $value); + } elseif ($headerCallCount === 1) { + $this->assertSame('Content-Disposition', $header); + $this->assertSame('attachment; filename="' . $fileName . '"', $value); + } elseif ($headerCallCount === 2) { + $this->assertSame('Content-Range', $header); + $this->assertSame("bytes 0-8/{$fileSize}", $value); + } elseif ($headerCallCount === 3) { + $this->assertSame('Authorization', $header); + $this->assertSame(self::FAKE_TOKEN, $value); + } + + $headerCallCount++; + + return $this->requestMock; + }); $this->httpClientMock ->expects($this->once()) @@ -495,7 +554,8 @@ public function resumableUploadSuccessfullyUploadsSingleChunk(): void #[Test] public function resumableUploadSuccessfullyUploadsMultipleChunks(): void { - $fileContents = str_repeat('A', 3 * 1024 * 1024); // 3 MB + $chunkSize = 1024 * 1024; + $fileContents = str_repeat('A', 3 * $chunkSize); // 3 MB $fileResource = fopen('php://memory', 'w+'); fwrite($fileResource, $fileContents); rewind($fileResource); @@ -522,7 +582,7 @@ public function resumableUploadSuccessfullyUploadsMultipleChunks(): void ->method('__toString') ->willReturnOnConsecutiveCalls('', '', '1'); - $result = $this->client->resumableUpload($uploadUrl, $fileResource, $fileName, $fileSize, 1024 * 1024); + $result = $this->client->resumableUpload($uploadUrl, $fileResource, $fileName, $fileSize, $chunkSize); $this->assertSame('1', $result); fclose($fileResource);