Skip to content

Commit

Permalink
feat: added fake provider
Browse files Browse the repository at this point in the history
Adds a fake provider that allows for faking the cdn providers default
country
  • Loading branch information
Marcus Hansen authored and ThePpeecc committed Jan 26, 2023
1 parent dffe363 commit 0bfd876
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 32 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
],
"require-dev": {
"pestphp/pest": "1.22.2",
"worksome/coding-style": "2.3.2"
"worksome/coding-style": "2.3.2",
"mockery/mockery": "1.5.1"
},
"require": {
"php": "^8.2",
Expand Down
10 changes: 10 additions & 0 deletions config/cdn-headers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);


// config for Worksome/cdn-headers
return [
'default-provider' => env('CDN_HEADERS_PROVIDER', 'cloudflare'),
'default-country' => env('CDN_COUNTRY_CODE', null),
];
20 changes: 12 additions & 8 deletions src/CdnHeadersManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,31 @@
namespace Worksome\CdnHeaders;

use Illuminate\Support\Manager;
use JetBrains\PhpStorm\Pure;
use Worksome\CdnHeaders\CloudFlare\CloudFlareProvider;
use Worksome\CdnHeaders\Contracts\CdnHeadersProvider as CdnHeadersProviderContract;
use Worksome\CdnHeaders\Contracts\CdnHeadersProvider;
use Worksome\CdnHeaders\Providers\CloudFlare\CloudFlareProvider;
use Worksome\CdnHeaders\Providers\FakeProvider;

class CdnHeadersManager extends Manager
{
#[Pure]
public function createCloudFlareDriver(): CloudFlareProvider
public function createCloudFlareDriver(): CdnHeadersProvider
{
return new CloudFlareProvider(
$this->config->get('cdn-headers') ?? [],
$this->container->get(ServerHeadersRepository::class)
);
}

#[Pure]
public function createFakeDriver(): CdnHeadersProvider
{
return new FakeProvider($this->config->get('cdn-headers') ?? []);
}

public function getDefaultDriver(): string
{
return 'cloudflare';
return $this->config->get('cdn-headers.default-provider') ?? 'cloudflare';
}

public function provider(string $driver): CdnHeadersProviderContract
public function provider(string $driver): CdnHeadersProvider
{
return $this->driver($driver);
}
Expand Down
8 changes: 4 additions & 4 deletions src/CdnHeadersServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
use Worksome\CdnHeaders\Contracts\CdnHeadersProvider as CdnHeadersProviderContract;
use Worksome\CdnHeaders\Contracts\CdnHeadersProvider;

class CdnHeadersServiceProvider extends ServiceProvider implements DeferrableProvider
{
public function boot(): void
{
$this->app->get(CdnHeadersProviderContract::class)->boot();
$this->app->get(CdnHeadersProvider::class)->boot();
}

public function register(): void
Expand All @@ -22,13 +22,13 @@ public function register(): void
);

$this->app->singleton(
CdnHeadersProviderContract::class,
CdnHeadersProvider::class,
static fn(Container $app) => $app->get(CdnHeadersManager::class)->driver()
);
}

public function provides(): array
{
return [CdnHeadersProviderContract::class, CdnHeadersManager::class];
return [CdnHeadersProvider::class, CdnHeadersManager::class];
}
}
6 changes: 3 additions & 3 deletions src/Contracts/CdnHeadersProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface CdnHeadersProvider
*
* @return non-empty-string|null
*/
public function getCountryCode(): ?string;
public function getCountryCode(): string|null;

public function hasCountryCode(): bool;

Expand All @@ -19,9 +19,9 @@ public function hasCountryCode(): bool;
*
* @return non-empty-string|null
*/
public function getConnectingIp(): ?string;
public function getConnectingIp(): string|null;

public function getTraceId(): ?string;
public function getTraceId(): string|null;

/**
* Anything required to be loaded in the boot
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,39 @@
<?php

namespace Worksome\CdnHeaders\CloudFlare;
namespace Worksome\CdnHeaders\Providers\CloudFlare;

use Worksome\CdnHeaders\Contracts\CdnHeadersProvider;
use Worksome\CdnHeaders\ServerHeadersRepository;

class CloudFlareProvider implements CdnHeadersProvider
{
public function __construct(
private array $config,
private ServerHeadersRepository $serverHeaders,
) {
}

public function getCountryCode(): ?string
public function getCountryCode(): string|null
{
return $this->serverHeaders->get('HTTP_CF_IPCOUNTRY');
return $this->serverHeaders->get('HTTP_CF_IPCOUNTRY') ?? $this->config['default-country'] ?? null;
}

public function hasCountryCode(): bool
{
return (bool) $this->getCountryCode();
}

public function getConnectingIp(): ?string
public function getConnectingIp(): string|null
{
return $this->serverHeaders->get('HTTP_CF_CONNECTING_IP');
}

/**
* https://support.cloudflare.com/hc/en-us/articles/203118044-What-is-the-CF-RAY-header-#h_f7a7396f-ec41-4c52-abf5-a110cadaca7c
* @link https://support.cloudflare.com/hc/en-us/articles/203118044-What-is-the-CF-RAY-header-#h_f7a7396f-ec41-4c52-abf5-a110cadaca7c
*
* @return non-empty-string|null
*/
public function getTraceId(): ?string
public function getTraceId(): string|null
{
return $this->serverHeaders->get('HTTP_CF_RAY');
}
Expand Down
36 changes: 36 additions & 0 deletions src/Providers/FakeProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Worksome\CdnHeaders\Providers;

use Worksome\CdnHeaders\Contracts\CdnHeadersProvider;

class FakeProvider implements CdnHeadersProvider
{
public function __construct(private array $config)
{
}

public function getCountryCode(): string|null
{
return $this->config['default-country'] ?? null;
}

public function hasCountryCode(): bool
{
return (bool) $this->getCountryCode();
}

public function getConnectingIp(): string|null
{
return null;
}

public function getTraceId(): string|null
{
return null;
}

public function boot(): void
{
}
}
2 changes: 1 addition & 1 deletion src/ServerHeadersRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class ServerHeadersRepository
/**
* @return non-empty-string|null
*/
public function get(string $key): ?string
public function get(string $key): string|null
{
if (isset($_SERVER[$key])) {
return $_SERVER[$key];
Expand Down
45 changes: 45 additions & 0 deletions tests/CdnHeadersManagerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

use Illuminate\Contracts\Config\Repository;
use Illuminate\Contracts\Container\Container;
use Worksome\CdnHeaders\CdnHeadersManager;
use Worksome\CdnHeaders\ServerHeadersRepository;

beforeEach(function () {
$this->createMocks = function ($config) {
$this->mockContainer = Mockery::mock(Container::class);
$this->mockConfig = Mockery::mock(Repository::class);
$this->mockContainer->shouldReceive('make')->andReturn($this->mockConfig);
$this->mockContainer->shouldReceive('get')->andReturn(new ServerHeadersRepository());
$this->mockConfig->shouldReceive('get')
->with('cdn-headers.default-provider')
->andReturn($config['default-provider']);
$this->mockConfig->shouldReceive('get')
->with('cdn-headers')
->andReturn($config);
};
});

it('should return cloudflare as the default provider if no config param is present', function () {
$this->createMocks->__invoke([
'default-provider' => null,
]);
$manager = new CdnHeadersManager($this->mockContainer);
expect($manager->getDefaultDriver())->toBe('cloudflare');
});

it('should return fake as the provider if specified in config', function () {
$this->createMocks->__invoke([
'default-provider' => 'fake',
]);
$manager = new CdnHeadersManager($this->mockContainer);
expect($manager->getDefaultDriver())->toBe('fake');
});

it('should return cloudflare as the provider if specified in config', function () {
$this->createMocks->__invoke([
'default-provider' => 'cloudflare',
]);
$manager = new CdnHeadersManager($this->mockContainer);
expect($manager->getDefaultDriver())->toBe('cloudflare');
});
32 changes: 23 additions & 9 deletions tests/CloudFlare/CloudFlareProviderTest.php
Original file line number Diff line number Diff line change
@@ -1,46 +1,60 @@
<?php

use Worksome\CdnHeaders\CloudFlare\CloudFlareProvider;
use Worksome\CdnHeaders\Providers\CloudFlare\CloudFlareProvider;
use Worksome\CdnHeaders\ServerHeadersRepository;

beforeEach(fn () => $this->mock = Mockery::mock(ServerHeadersRepository::class));
beforeEach(function () {
$this->country = 'GB';
$this->mock = Mockery::mock(ServerHeadersRepository::class);
$this->config = [
'default-country' => $this->country,
];
});

it('should get null as a default country code', function () {
it('should get null as a default country code if no config is present', function () {
$this->mock->shouldReceive('get')->andReturn(null);
$provider = new CloudFlareProvider($this->mock);
$provider = new CloudFlareProvider([], $this->mock);

expect($provider->getCountryCode())->toBe(null);
expect($provider->hasCountryCode())->toBeFalse();
});

it('should get config default country code if present', function () {
$this->mock->shouldReceive('get')->andReturn(null);
$provider = new CloudFlareProvider($this->config, $this->mock);

expect($provider->getCountryCode())->toBe($this->country);
expect($provider->hasCountryCode())->toBeTrue();
});

it('should return a correct country code if server header present', function () {
$this->mock->shouldReceive('get')->andReturn('US');
$provider = new CloudFlareProvider($this->mock);
$provider = new CloudFlareProvider($this->config, $this->mock);

expect($provider->getCountryCode())->toBe('US');
expect($provider->hasCountryCode())->toBeTrue();
});

it('should get null as a default connecting ip', function () {
$this->mock->shouldReceive('get')->andReturn(null);
$provider = new CloudFlareProvider($this->mock);
$provider = new CloudFlareProvider($this->config, $this->mock);
expect($provider->getConnectingIp())->toBe(null);
});

it('should return an ip', function () {
$this->mock->shouldReceive('get')->andReturn('127.0.0.1');
$provider = new CloudFlareProvider($this->mock);
$provider = new CloudFlareProvider($this->config, $this->mock);
expect($provider->getConnectingIp())->toBe('127.0.0.1');
});

it('should get null as a default ray', function () {
$this->mock->shouldReceive('get')->andReturn(null);
$provider = new CloudFlareProvider($this->mock);
$provider = new CloudFlareProvider($this->config, $this->mock);
expect($provider->getTraceId())->toBe(null);
});

it('should return ray', function () {
$this->mock->shouldReceive('get')->andReturn('CF12345679');
$provider = new CloudFlareProvider($this->mock);
$provider = new CloudFlareProvider($this->config, $this->mock);
expect($provider->getTraceId())->toBe('CF12345679');
});
34 changes: 34 additions & 0 deletions tests/Faker/FakeProviderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

use Worksome\CdnHeaders\Providers\FakeProvider;

beforeEach(function () {
$this->country = 'GB';
$this->config = [
'default-country' => $this->country,
];
});

it('should get null as a default country code if no config is present', function () {
$provider = new FakeProvider([]);

expect($provider->getCountryCode())->toBe(null);
expect($provider->hasCountryCode())->toBeFalse();
});

it('should get config default country code if present', function () {
$provider = new FakeProvider($this->config);

expect($provider->getCountryCode())->toBe($this->country);
expect($provider->hasCountryCode())->toBeTrue();
});

it('should get null as a default connecting ip', function () {
$provider = new FakeProvider($this->config);
expect($provider->getConnectingIp())->toBe(null);
});

it('should get null as a default ray', function () {
$provider = new FakeProvider($this->config);
expect($provider->getTraceId())->toBe(null);
});

0 comments on commit 0bfd876

Please sign in to comment.