186 lines
5.9 KiB
PHP
186 lines
5.9 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace Tests\Unit\Services;
|
||
|
|
||
|
use App\ContentProvider;
|
||
|
use App\MetadataResolver\MetadataResolver;
|
||
|
use App\MetadataResolver\ResolverCircuitBreakException;
|
||
|
use App\MetadataResolver\UncaughtResolverException;
|
||
|
use App\Services\MetadataResolveService;
|
||
|
use Carbon\Carbon;
|
||
|
use GuzzleHttp\Client;
|
||
|
use GuzzleHttp\Exception\ClientException;
|
||
|
use GuzzleHttp\Exception\ServerException;
|
||
|
use GuzzleHttp\Handler\MockHandler;
|
||
|
use GuzzleHttp\HandlerStack;
|
||
|
use GuzzleHttp\Psr7\Response;
|
||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||
|
use Mockery\MockInterface;
|
||
|
use Tests\TestCase;
|
||
|
|
||
|
class MetadataResolverServiceTest extends TestCase
|
||
|
{
|
||
|
use RefreshDatabase;
|
||
|
|
||
|
protected function setUp(): void
|
||
|
{
|
||
|
parent::setUp();
|
||
|
$this->seed();
|
||
|
Carbon::setTestNow('2020-07-21 19:19:19');
|
||
|
// FIXME: 今書かれてるテストはresolveのHTTPリクエストのみを考慮しているので、ContentProviderにデータがないとリクエスト回数がずれる
|
||
|
factory(ContentProvider::class)->create();
|
||
|
}
|
||
|
|
||
|
protected function tearDown(): void
|
||
|
{
|
||
|
parent::tearDown();
|
||
|
Carbon::setTestNow();
|
||
|
}
|
||
|
|
||
|
public function testOnRuntimeException()
|
||
|
{
|
||
|
$this->mock(MetadataResolver::class, function (MockInterface $mock) {
|
||
|
$mock->shouldReceive('resolve')->andReturnUsing(function ($url) {
|
||
|
throw new \RuntimeException('Something happened!');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
try {
|
||
|
$service = app()->make(MetadataResolveService::class);
|
||
|
$service->execute('http://example.com');
|
||
|
} catch (UncaughtResolverException $e) {
|
||
|
$this->assertDatabaseHas('metadata', [
|
||
|
'url' => 'http://example.com',
|
||
|
'error_at' => new Carbon('2020-07-21 19:19:19'),
|
||
|
'error_count' => 1,
|
||
|
'error_exception_class' => \RuntimeException::class,
|
||
|
'error_http_code' => null,
|
||
|
'error_body' => 'Something happened!',
|
||
|
]);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
$this->fail();
|
||
|
}
|
||
|
|
||
|
public function testOnHttpClientError()
|
||
|
{
|
||
|
$handler = HandlerStack::create(new MockHandler([new Response(404)]));
|
||
|
$client = new Client(['handler' => $handler]);
|
||
|
$this->instance(Client::class, $client);
|
||
|
|
||
|
try {
|
||
|
$service = app()->make(MetadataResolveService::class);
|
||
|
$service->execute('http://example.com');
|
||
|
} catch (UncaughtResolverException $e) {
|
||
|
$this->assertDatabaseHas('metadata', [
|
||
|
'url' => 'http://example.com',
|
||
|
'error_at' => new Carbon('2020-07-21 19:19:19'),
|
||
|
'error_count' => 1,
|
||
|
'error_exception_class' => ClientException::class,
|
||
|
'error_http_code' => 404,
|
||
|
]);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
$this->fail();
|
||
|
}
|
||
|
|
||
|
public function testOnHttpServerError()
|
||
|
{
|
||
|
$handler = HandlerStack::create(new MockHandler([new Response(503), new Response(503)]));
|
||
|
$client = new Client(['handler' => $handler]);
|
||
|
$this->instance(Client::class, $client);
|
||
|
|
||
|
try {
|
||
|
$service = app()->make(MetadataResolveService::class);
|
||
|
$service->execute('http://example.com');
|
||
|
} catch (UncaughtResolverException $e) {
|
||
|
$this->assertDatabaseHas('metadata', [
|
||
|
'url' => 'http://example.com',
|
||
|
'error_at' => new Carbon('2020-07-21 19:19:19'),
|
||
|
'error_count' => 1,
|
||
|
'error_exception_class' => ServerException::class,
|
||
|
'error_http_code' => 503,
|
||
|
]);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
$this->fail();
|
||
|
}
|
||
|
|
||
|
public function testCircuitBreak()
|
||
|
{
|
||
|
$this->mock(MetadataResolver::class, function (MockInterface $mock) {
|
||
|
$mock->shouldReceive('resolve')->andReturnUsing(function ($url) {
|
||
|
throw new \RuntimeException('Something happened!');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
try {
|
||
|
for ($i = 0; $i < 6; $i++) {
|
||
|
try {
|
||
|
$service = app()->make(MetadataResolveService::class);
|
||
|
$service->execute('http://example.com');
|
||
|
} catch (UncaughtResolverException $e) {
|
||
|
}
|
||
|
}
|
||
|
} catch (ResolverCircuitBreakException $e) {
|
||
|
$this->assertDatabaseHas('metadata', [
|
||
|
'url' => 'http://example.com',
|
||
|
'error_at' => new Carbon('2020-07-21 19:19:19'),
|
||
|
'error_count' => 5,
|
||
|
'error_exception_class' => \RuntimeException::class,
|
||
|
'error_http_code' => null,
|
||
|
'error_body' => 'Something happened!',
|
||
|
]);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
$this->fail();
|
||
|
}
|
||
|
|
||
|
public function testOnResurrect()
|
||
|
{
|
||
|
$successBody = <<<HTML
|
||
|
<!doctype html>
|
||
|
<html lang="ja">
|
||
|
<head>
|
||
|
<meta charset="UTF-8">
|
||
|
<meta name="og:title" content="OGP Title">
|
||
|
<meta name="og:description" content="OGP Description">
|
||
|
<title>Test Document</title>
|
||
|
</head>
|
||
|
<body>
|
||
|
</body>
|
||
|
</html>
|
||
|
HTML;
|
||
|
$handler = HandlerStack::create(new MockHandler([
|
||
|
new Response(404),
|
||
|
new Response(200, ['Content-Type' => 'text/html'], $successBody),
|
||
|
]));
|
||
|
$client = new Client(['handler' => $handler]);
|
||
|
$this->instance(Client::class, $client);
|
||
|
|
||
|
for ($i = 0; $i < 2; $i++) {
|
||
|
try {
|
||
|
$service = app()->make(MetadataResolveService::class);
|
||
|
$service->execute('http://example.com');
|
||
|
} catch (UncaughtResolverException $e) {
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$this->assertDatabaseHas('metadata', [
|
||
|
'url' => 'http://example.com',
|
||
|
'title' => 'OGP Title',
|
||
|
'description' => 'OGP Description',
|
||
|
'image' => '',
|
||
|
'error_at' => null,
|
||
|
'error_count' => 0,
|
||
|
'error_exception_class' => null,
|
||
|
'error_http_code' => null,
|
||
|
'error_body' => null,
|
||
|
]);
|
||
|
}
|
||
|
}
|