repository = $this->createMock(AllegroIntegrationRepository::class); $this->oauthClient = $this->createMock(AllegroOAuthClient::class); $this->manager = new AllegroTokenManager($this->repository, $this->oauthClient); } public function testResolveTokenReturnsCachedTokenWhenFresh(): void { $expiresAt = (new DateTimeImmutable('now')) ->add(new DateInterval('PT30M')) ->format('Y-m-d H:i:s'); $this->repository ->method('getTokenCredentials') ->willReturn([ 'environment' => 'sandbox', 'client_id' => 'cid', 'client_secret' => 'cs', 'refresh_token' => 'rt', 'access_token' => 'fresh-token', 'token_expires_at' => $expiresAt, ]); $this->oauthClient ->expects($this->never()) ->method('refreshAccessToken'); $result = $this->manager->resolveToken(); $this->assertSame('fresh-token', $result[0]); $this->assertSame('sandbox', $result[1]); } public function testResolveTokenRefreshesWhenExpiresWithinFiveMinutes(): void { $expiresAt = (new DateTimeImmutable('now')) ->add(new DateInterval('PT3M')) ->format('Y-m-d H:i:s'); $credentials = [ 'environment' => 'production', 'client_id' => 'cid', 'client_secret' => 'cs', 'refresh_token' => 'rt', 'access_token' => 'old-token', 'token_expires_at' => $expiresAt, ]; $this->repository ->method('getTokenCredentials') ->willReturnOnConsecutiveCalls( $credentials, $credentials, array_merge($credentials, ['access_token' => 'new-token']) ); $this->oauthClient ->expects($this->once()) ->method('refreshAccessToken') ->with('production', 'cid', 'cs', 'rt') ->willReturn([ 'access_token' => 'new-token', 'refresh_token' => 'new-rt', 'token_type' => 'Bearer', 'scope' => '', 'expires_in' => 3600, ]); $this->repository ->expects($this->once()) ->method('saveTokens'); $result = $this->manager->resolveToken(); $this->assertSame('new-token', $result[0]); $this->assertSame('production', $result[1]); } public function testResolveTokenRefreshesWhenAlreadyExpired(): void { $expiresAt = (new DateTimeImmutable('now')) ->sub(new DateInterval('PT10M')) ->format('Y-m-d H:i:s'); $credentials = [ 'environment' => 'sandbox', 'client_id' => 'cid', 'client_secret' => 'cs', 'refresh_token' => 'rt', 'access_token' => 'expired-token', 'token_expires_at' => $expiresAt, ]; $this->repository ->method('getTokenCredentials') ->willReturnOnConsecutiveCalls( $credentials, $credentials, array_merge($credentials, ['access_token' => 'refreshed-token']) ); $this->oauthClient ->expects($this->once()) ->method('refreshAccessToken') ->willReturn([ 'access_token' => 'refreshed-token', 'refresh_token' => 'rt', 'token_type' => 'Bearer', 'scope' => '', 'expires_in' => 3600, ]); $this->repository->expects($this->once())->method('saveTokens'); $result = $this->manager->resolveToken(); $this->assertSame('refreshed-token', $result[0]); } public function testResolveTokenThrowsWhenNoOAuthConfig(): void { $this->repository ->method('getTokenCredentials') ->willReturn(null); $this->expectException(AllegroOAuthException::class); $this->expectExceptionMessage('Brak polaczenia OAuth Allegro'); $this->manager->resolveToken(); } public function testResolveTokenRefreshesWhenAccessTokenEmpty(): void { $credentials = [ 'environment' => 'sandbox', 'client_id' => 'cid', 'client_secret' => 'cs', 'refresh_token' => 'rt', 'access_token' => '', 'token_expires_at' => '', ]; $this->repository ->method('getTokenCredentials') ->willReturnOnConsecutiveCalls( $credentials, $credentials, array_merge($credentials, ['access_token' => 'brand-new']) ); $this->oauthClient ->expects($this->once()) ->method('refreshAccessToken') ->willReturn([ 'access_token' => 'brand-new', 'refresh_token' => 'rt', 'token_type' => 'Bearer', 'scope' => '', 'expires_in' => 3600, ]); $this->repository->expects($this->once())->method('saveTokens'); $result = $this->manager->resolveToken(); $this->assertSame('brand-new', $result[0]); } public function testForceRefreshReReadsTokenFromRepository(): void { $expiresAt = (new DateTimeImmutable('now')) ->sub(new DateInterval('PT1M')) ->format('Y-m-d H:i:s'); $credentials = [ 'environment' => 'sandbox', 'client_id' => 'cid', 'client_secret' => 'cs', 'refresh_token' => 'rt', 'access_token' => 'stale', 'token_expires_at' => $expiresAt, ]; $this->repository ->expects($this->exactly(3)) ->method('getTokenCredentials') ->willReturnOnConsecutiveCalls( $credentials, $credentials, array_merge($credentials, ['access_token' => 'from-db']) ); $this->oauthClient ->method('refreshAccessToken') ->willReturn([ 'access_token' => 'api-returned', 'refresh_token' => 'rt', 'token_type' => 'Bearer', 'scope' => '', 'expires_in' => 3600, ]); $this->repository->expects($this->once())->method('saveTokens'); $result = $this->manager->resolveToken(); // Token comes from re-read (3rd call), not directly from API response $this->assertSame('from-db', $result[0]); } public function testResolveTokenRefreshesWhenExpiresAtInvalidFormat(): void { $credentials = [ 'environment' => 'sandbox', 'client_id' => 'cid', 'client_secret' => 'cs', 'refresh_token' => 'rt', 'access_token' => 'some-token', 'token_expires_at' => 'not-a-date', ]; $this->repository ->method('getTokenCredentials') ->willReturnOnConsecutiveCalls( $credentials, $credentials, array_merge($credentials, ['access_token' => 'refreshed']) ); $this->oauthClient ->expects($this->once()) ->method('refreshAccessToken') ->willReturn([ 'access_token' => 'refreshed', 'refresh_token' => 'rt', 'token_type' => 'Bearer', 'scope' => '', 'expires_in' => 3600, ]); $this->repository->expects($this->once())->method('saveTokens'); $result = $this->manager->resolveToken(); $this->assertSame('refreshed', $result[0]); } }