Skip to content

Commit

Permalink
create microsoft entra id tests
Browse files Browse the repository at this point in the history
  • Loading branch information
GabsCoding committed Jul 27, 2024
1 parent 908a2ff commit cd1cd7a
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 66 deletions.
7 changes: 5 additions & 2 deletions src/Authentication/MicrosoftEntraId.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public function getAccount(): string

public function getAuthentication(Request $request): string
{
if (!empty($this->token) && $this->tokenExpiresAt > new DateTime()) {
if (!empty($this->token) && $this->tokenExpiresAt && $this->tokenExpiresAt > new DateTime()) {
return $this->token;
}

Expand All @@ -71,9 +71,12 @@ protected function authenticate(): void
'scope' => 'https://storage.azure.com/.default',
],
]);

// @codeCoverageIgnoreStart
} catch (RequestExceptionInterface $e) {
throw RequestException::createFromRequestException($e);
}
// @codeCoverageIgnoreEnd

/** @var array{token_type: string, expires_in: int, access_token: string} $body */
$body = json_decode((string) $response->getBody(), true);
Expand All @@ -85,7 +88,7 @@ protected function authenticate(): void
protected function getRequestClient(): ClientInterface
{
if (!isset($this->client)) {
$this->client = new Client();
$this->client = new Client(); // @codeCoverageIgnore
}

return $this->client;
Expand Down
78 changes: 78 additions & 0 deletions tests/Fakes/ClientFake.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

declare(strict_types=1);

namespace Xray\Tests\Fakes;

use Closure;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Promise\{Promise, PromiseInterface};
use GuzzleHttp\Psr7\Response;
use PHPUnit\Framework\Assert;
use Psr\Http\Message\{RequestInterface, ResponseInterface};

class ClientFake implements ClientInterface
{
/** @var array<string, array{uri: string, options: array<string, scalar>}> */
protected array $requests = [];

protected int $status = 200;

protected array $headers = [];

protected ?string $body = null;

public function withResponseFake(?string $body = null, array $headers = [], int $status = 200): self
{
$this->status = $status;
$this->headers = $headers;
$this->body = $body;

return $this;
}

/** @param array<string, scalar> $options */
public function send(RequestInterface $request, array $options = []): ResponseInterface
{
return new Response($this->status, $this->headers, $this->body);
}

/** @param array<string, scalar> $options */
public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface
{
return new Promise();
}

/** @param array<string, scalar> $options */
public function request(string $method, mixed $uri, array $options = []): ResponseInterface
{
/** @phpstan-ignore-next-line */
$this->requests[$method] = [
'uri' => $uri,
'options' => $options,
];

return new Response($this->status, $this->headers, $this->body);
}

/** @param array<string, scalar> $options */
public function requestAsync(string $method, mixed $uri, array $options = []): PromiseInterface
{
return new Promise();
}

public function getConfig(?string $option = null): mixed
{
return [];
}

public function assertRequestSent(string $method, string $uri, ?Closure $options = null): void
{
Assert::assertArrayHasKey($method, $this->requests, 'Request not sent');
Assert::assertSame($uri, $this->requests[$method]['uri'], 'Invalid URI');

if (!is_null($options)) {
Assert::assertTrue($options($this->requests[$method]['options']), 'Invalid options');
}
}
}
57 changes: 57 additions & 0 deletions tests/Feature/Authentication/MicrosoftEntraIdTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

use Xray\AzureStoragePhpSdk\Authentication\MicrosoftEntraId;
use Xray\AzureStoragePhpSdk\BlobStorage\Enums\HttpVerb;
use Xray\AzureStoragePhpSdk\Contracts\Authentication\Auth;
use Xray\AzureStoragePhpSdk\Tests\Http\RequestFake;
use Xray\Tests\Fakes\ClientFake;

uses()->group('authentications');

it('should implements Auth interface', function () {
expect(MicrosoftEntraId::class)
->toImplement(Auth::class);
});

it('should get date formatted correctly', function () {
$auth = new MicrosoftEntraId('account', 'directory', 'application', 'secret');

expect($auth->getDate())
->toBe(gmdate('D, d M Y H:i:s T'));
});

it('should get the authentication account', function () {
$auth = new MicrosoftEntraId('account', 'directory', 'application', 'secret');

expect($auth->getAccount())
->toBe('account');
});

it('should get correctly the authentication signature from a login request', function () {
$client = (new ClientFake())
->withResponseFake(json_encode([
'token_type' => $tokeType = 'Bearer',
'access_token' => $token = 'token',
'expires_in' => 3600,
]));

$auth = (new MicrosoftEntraId('account', 'directory', $application = 'application', $secret = 'secret'))
->withRequestClient($client);

expect($auth->getAuthentication(new RequestFake()))
->toBe("{$tokeType} {$token}");

expect($auth->getAuthentication(new RequestFake()))
->toBe("{$tokeType} {$token}");

$client->assertRequestSent(HttpVerb::POST->value, 'https://login.microsoftonline.com/directory/oauth2/v2.0/token', fn (array $options): bool => $options === [
'form_params' => [
'grant_type' => 'client_credentials',
'client_id' => $application,
'client_secret' => $secret,
'scope' => 'https://storage.azure.com/.default',
],
]);
});
7 changes: 7 additions & 0 deletions tests/Feature/Authentication/SharedKeyAuthTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@
->toBe(gmdate('D, d M Y H:i:s T'));
});

it('should get the authentication account', function () {
$auth = new SharedKeyAuth('account', 'key');

expect($auth->getAccount())
->toBe('account');
});

it('should get correctly the authentication signature for all http methods', function (HttpVerb $verb) {
$decodedKey = 'my-decoded-account-key';

Expand Down
73 changes: 9 additions & 64 deletions tests/Feature/Http/RequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,19 @@

declare(strict_types=1);

use GuzzleHttp\ClientInterface;
use GuzzleHttp\Promise\{Promise, PromiseInterface};
use GuzzleHttp\Psr7\Response;
use PHPUnit\Framework\Assert;
use Psr\Http\Message\{RequestInterface, ResponseInterface};
use Xray\AzureStoragePhpSdk\Authentication\SharedKeyAuth;
use Xray\AzureStoragePhpSdk\BlobStorage\Enums\HttpVerb;
use Xray\AzureStoragePhpSdk\BlobStorage\{Config, Resource};
use Xray\AzureStoragePhpSdk\Contracts\Http\Response as HttpResponse;
use Xray\AzureStoragePhpSdk\Http\{Headers, Request};
use Xray\Tests\Fakes\ClientFake;

uses()->group('http');

it('should send get, delete, and options requests', function (string $method, HttpVerb $verb): void {
$auth = new SharedKeyAuth('my_account', 'bar');

$request = (new Request($auth, client: $client = new Client()))
$request = (new Request($auth, client: $client = new ClientFake()))
->withAuthentication()
->usingAccount(fn (): string => 'foo')
->withOptions(['foo' => 'bar']);
Expand All @@ -43,7 +39,7 @@
it('should send post and put requests', function (string $method, HttpVerb $verb): void {
$auth = new SharedKeyAuth('my_account', 'bar');

$request = (new Request($auth, client: $client = new Client()))
$request = (new Request($auth, client: $client = new ClientFake()))
->withoutAuthentication()
->withHeaders(['foo' => 'bar']);

Expand Down Expand Up @@ -73,21 +69,21 @@
$auth = new SharedKeyAuth('my_account', 'bar');
$config = new Config();

expect((new Request($auth, $config, new Client()))->getConfig())
expect((new Request($auth, $config, new ClientFake()))->getConfig())
->toBe($config);
});

it('should get request auth', function (): void {
$auth = new SharedKeyAuth('my_account', 'bar');

expect((new Request($auth, client: new Client()))->getAuth())
expect((new Request($auth, client: new ClientFake()))->getAuth())
->toBe($auth);
});

it('should get the http verb from request', function (HttpVerb $verb) {
$auth = new SharedKeyAuth('my_account', 'bar');

$request = (new Request($auth, client: new Client()))
$request = (new Request($auth, client: new ClientFake()))
->withVerb($verb);

expect($request->getVerb())
Expand All @@ -98,7 +94,7 @@
it('should get the resource from request', function (): void {
$auth = new SharedKeyAuth('my_account', 'bar');

$request = (new Request($auth, client: new Client()))
$request = (new Request($auth, client: new ClientFake()))
->withResource('endpoint');

expect($request->getResource())
Expand All @@ -108,7 +104,7 @@
it('should get the headers from request', function (): void {
$auth = new SharedKeyAuth('my_account', 'bar');

$request = (new Request($auth, client: new Client()))
$request = (new Request($auth, client: new ClientFake()))
->withHttpHeaders(new Headers());

expect($request->getHttpHeaders())
Expand All @@ -118,60 +114,9 @@
it('should get the body from request', function (): void {
$auth = new SharedKeyAuth('my_account', 'bar');

$request = (new Request($auth, client: new Client()))
$request = (new Request($auth, client: new ClientFake()))
->withBody('body');

expect($request->getBody())
->toBe('body');
});

class Client implements ClientInterface
{
/** @var array<string, array{uri: string, options: array<string, scalar>}> */
protected array $requests = [];

/** @param array<string, scalar> $options */
public function send(RequestInterface $request, array $options = []): ResponseInterface
{
return new Response();
}

/** @param array<string, scalar> $options */
public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface
{
return new Promise();
}

/** @param array<string, scalar> $options */
public function request(string $method, mixed $uri, array $options = []): ResponseInterface
{
/** @phpstan-ignore-next-line */
$this->requests[$method] = [
'uri' => $uri,
'options' => $options,
];

return new Response();
}

/** @param array<string, scalar> $options */
public function requestAsync(string $method, mixed $uri, array $options = []): PromiseInterface
{
return new Promise();
}

public function getConfig(?string $option = null): mixed
{
return [];
}

public function assertRequestSent(string $method, string $uri, ?Closure $options = null): void
{
Assert::assertArrayHasKey($method, $this->requests, 'Request not sent');
Assert::assertSame($uri, $this->requests[$method]['uri'], 'Invalid URI');

if (!is_null($options)) {
Assert::assertTrue($options($this->requests[$method]['options']), 'Invalid options');
}
}
}

0 comments on commit cd1cd7a

Please sign in to comment.