From c3d6edcf42ccb8ae3ab4b0eb97f93cb70b49eb30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Thu, 18 Mar 2021 20:20:15 +0100 Subject: [PATCH 01/42] test(jobs): cover character info --- composer.json | 11 +- phpunit.xml | 28 +++ src/Models/Character/CharacterInfo.php | 9 + tests/Jobs/Esi/Character/TestInfo.php | 213 ++++++++++++++++++ tests/Jobs/Esi/JobEsiTestCase.php | 81 +++++++ tests/Mocks/Esi/EsiInMemoryCache.php | 149 ++++++++++++ tests/Mocks/Esi/EsiMockFetcher.php | 85 +++++++ .../Resources/Esi/Character/InfoResource.php | 36 +++ tests/artifacts/characters/info.json | 11 + ...17_225733_create_character_infos_table.php | 67 ++++++ 10 files changed, 689 insertions(+), 1 deletion(-) create mode 100644 phpunit.xml create mode 100644 tests/Jobs/Esi/Character/TestInfo.php create mode 100644 tests/Jobs/Esi/JobEsiTestCase.php create mode 100644 tests/Mocks/Esi/EsiInMemoryCache.php create mode 100644 tests/Mocks/Esi/EsiMockFetcher.php create mode 100644 tests/Resources/Esi/Character/InfoResource.php create mode 100644 tests/artifacts/characters/info.json create mode 100644 tests/database/migrations/2021_03_17_225733_create_character_infos_table.php diff --git a/composer.json b/composer.json index 7095729a..a8f8e64e 100644 --- a/composer.json +++ b/composer.json @@ -13,6 +13,11 @@ "Seat\\Eveapi\\": "src/" } }, + "autoload-dev": { + "psr-4": { + "Seat\\Eveapi\\Tests\\": "tests/" + } + }, "minimum-stability": "dev", "prefer-stable": true, "require": { @@ -24,9 +29,13 @@ "doctrine/dbal": "^2.9", "softcreatr/jsonpath": "^0.7", "ext-json": "*", - "ext-posix": "*", "ext-redis": "*" }, + "require-dev": { + "josiasmontag/laravel-redis-mock": "^1.0", + "orchestra/testbench": "^4.0", + "orchestra/database": "^4.0" + }, "extra": { "laravel": { "providers": [ diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 00000000..fc746430 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,28 @@ + + + + + src/ + + + + + + + + + ./tests/Jobs/Esi/ + + + + diff --git a/src/Models/Character/CharacterInfo.php b/src/Models/Character/CharacterInfo.php index 1693ee45..9bb08a58 100644 --- a/src/Models/Character/CharacterInfo.php +++ b/src/Models/Character/CharacterInfo.php @@ -64,6 +64,15 @@ class CharacterInfo extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'ancestry_id' => 'integer', + 'bloodline_id' => 'integer', + 'race_id' => 'integer', + ]; + /** * @var string */ diff --git a/tests/Jobs/Esi/Character/TestInfo.php b/tests/Jobs/Esi/Character/TestInfo.php new file mode 100644 index 00000000..b1ec5415 --- /dev/null +++ b/tests/Jobs/Esi/Character/TestInfo.php @@ -0,0 +1,213 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/characters/info.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testTags() + { + $job = new Info(180548812); + + $this->assertEqualsCanonicalizing(['public', 'character', 180548812], $job->tags()); + } + + public function testHandleSuccess() + { + $job = new Info(180548812); + $job->handle(); + + $character = CharacterInfo::find(180548812); + + // add extra field to be ESI structure compliant + $character->corporation_id = 109299958; + + $data = json_encode(new InfoResource($character)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/info.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $character = new CharacterInfo([ + 'character_id' => 180548812, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + $character->save(); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Info(180548812); + $job->handle(); + + $character = CharacterInfo::find(180548812); + + $this->assertEquals($character->created_at, $character->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v4/characters/180548812/', 'datasource=tranquility'); + + $character = new CharacterInfo([ + 'character_id' => 180548812, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + $character->save(); + + $data = json_encode(new InfoResource($character)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/info.json', $data); + + $job = new Info(180548812); + $job->handle(); + + $character = CharacterInfo::find(180548812); + + // add extra field to be ESI structure compliant + $character->corporation_id = 109299958; + + $data = json_encode(new InfoResource($character)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/info.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $job = new Info(404); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $job = new Info(420); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $job = new Info(500); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $job = new Info(503); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $job = new Info(504); + $job->handle(); + } +} diff --git a/tests/Jobs/Esi/JobEsiTestCase.php b/tests/Jobs/Esi/JobEsiTestCase.php new file mode 100644 index 00000000..0433ca0b --- /dev/null +++ b/tests/Jobs/Esi/JobEsiTestCase.php @@ -0,0 +1,81 @@ +set('database.redis.client', 'mock'); + + // database setup + $app['config']->set('database.default', 'testbench'); + $app['config']->set('database.connections.testbench', [ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => '', + ]); + + // eseye setup + $app['config']->set('esi.eseye_logfile', storage_path('logs')); + $app['config']->set('esi.eseye_cache', storage_path('eseye')); + $app['config']->set('esi.eseye_loglevel', 'debug'); + $app['config']->set('esi.eseye_esi_scheme', 'https'); + $app['config']->set('esi.eseye_esi_host', 'esi.evetech.net'); + $app['config']->set('esi.eseye_esi_port', 443); + $app['config']->set('esi.eseye_esi_datasource', 'tranquility'); + $app['config']->set('esi.eseye_sso_scheme', 'https'); + $app['config']->set('esi.eseye_sso_host', 'login.eveonline.com'); + $app['config']->set('esi.eseye_sso_port', 443); + } + + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + + // ensure cache from previous tests will not infer with current tests. + EsiInMemoryCache::clear(); + } + + protected function setUp(): void + { + parent::setUp(); + + // override guzzle fetcher by using esi mock + Configuration::getInstance()->fetcher = EsiMockFetcher::class; + + // override cache by using in-memory mock + Configuration::getInstance()->cache = EsiInMemoryCache::class; + + // override logs by using honey pot + Configuration::getInstance()->logger = NullLogger::class; + + $this->loadMigrationsFrom(realpath(__DIR__ . '/../../database/migrations')); + } + + /** + * @param \Illuminate\Foundation\Application $app + * @return string[] + */ + protected function getPackageProviders($app) + { + return [ + RedisMockServiceProvider::class, + EveapiServiceProvider::class, + ]; + } +} diff --git a/tests/Mocks/Esi/EsiInMemoryCache.php b/tests/Mocks/Esi/EsiInMemoryCache.php new file mode 100644 index 00000000..d5325295 --- /dev/null +++ b/tests/Mocks/Esi/EsiInMemoryCache.php @@ -0,0 +1,149 @@ +getCacheKey($uri, $query); + + self::$database[$key] = $data; + } + + /** + * @param string $uri + * @param string $query + * + * @return \Seat\Eseye\Containers\EsiResponse|bool + */ + public function get(string $uri, string $query = '') + { + $key = $this->getCacheKey($uri, $query); + + if (! array_key_exists($key, self::$database)) + return false; + + $data = self::$database[$key]; + + if ($data->expired() && ! $data->hasHeader('ETag')) { + $this->forget($uri, $query); + + return false; + } + + return $data; + } + + /** + * @param string $uri + * @param string $query + * + * @return void + */ + public function forget(string $uri, string $query = '') + { + $key = $this->getCacheKey($uri, $query); + + if (array_key_exists($key, self::$database)) + unset(self::$database[$key]); + } + + /** + * @param string $uri + * @param string $query + * + * @return bool|mixed + */ + public function has(string $uri, string $query = ''): bool + { + $key = $this->getCacheKey($uri, $query); + + return array_key_exists($key, self::$database); + } + + private function getCacheKey(string $uri, string $query = '') + { + return $this->buildHashPath($this->safePath($uri), $query); + } + + /** + * @param string $uri + * + * @return string + */ + private function safePath(string $uri): string + { + + return preg_replace('/[^A-Za-z0-9\/]/', '', $uri); + } + + /** + * @param string $path + * @param string $query + * + * @return string + */ + private function buildHashPath(string $path, string $query = ''): string + { + + // If the query string has data, hash it. + if ($query != '') + $query = $this->hashString($query); + + return strtr($path, ['/' => '_']) . $query; + } +} diff --git a/tests/Mocks/Esi/EsiMockFetcher.php b/tests/Mocks/Esi/EsiMockFetcher.php new file mode 100644 index 00000000..243a329d --- /dev/null +++ b/tests/Mocks/Esi/EsiMockFetcher.php @@ -0,0 +1,85 @@ +authentication = $authentication; + $this->scopes = ['public']; + + if (! is_null($authentication)) + $this->scopes = empty($authentication->scopes) ? ['public'] : $authentication->scopes; + } + + /** + * @param \Seat\Eseye\Containers\EsiResponse $response + */ + public static function add(EsiResponse $response) + { + array_push(static::$stack, $response); + } + + /** + * @inheritDoc + */ + public function call(string $method, string $uri, array $body, array $headers = []): EsiResponse + { + $response = array_pop(static::$stack); + + if ($response->getErrorCode() >= 400) { + $exception = new Exception('Dummy Exception'); + + throw new RequestFailedException($exception, $response); + } + + return $response; + } + + /** + * @inheritDoc + */ + public function getAuthenticationScopes(): array + { + return $this->scopes; + } + + /** + * @param array $scopes + */ + public function setAuthenticationScopes(array $scopes) + { + $this->scopes = $scopes; + } +} diff --git a/tests/Resources/Esi/Character/InfoResource.php b/tests/Resources/Esi/Character/InfoResource.php new file mode 100644 index 00000000..69f26e3b --- /dev/null +++ b/tests/Resources/Esi/Character/InfoResource.php @@ -0,0 +1,36 @@ + $this->when($this->alliance_id !== null, $this->alliance_id), + 'ancestry_id' => $this->when($this->ancestry_id !== null, $this->ancestry_id), + 'birthday' => $this->birthday, + 'bloodline_id' => $this->bloodline_id, + 'corporation_id' => $this->corporation_id, + 'description' => $this->when($this->description !== null, $this->description), + 'faction_id' => $this->when($this->faction_id !== null, $this->faction_id), + 'gender' => $this->gender, + 'name' => $this->name, + 'race_id' => $this->race_id, + 'security_status' => $this->when($this->security_status !== null, $this->security_status), + 'title' => $this->when($this->title !== null, $this->title), + ]; + } +} diff --git a/tests/artifacts/characters/info.json b/tests/artifacts/characters/info.json new file mode 100644 index 00000000..73021f2d --- /dev/null +++ b/tests/artifacts/characters/info.json @@ -0,0 +1,11 @@ +{ + "ancestry_id":19, + "birthday":"2015-03-24T11:37:00Z", + "bloodline_id":3, + "corporation_id":109299958, + "description":"", + "gender":"male", + "name":"CCP Bartender", + "race_id":2, + "title":"All round pretty awesome guy" +} \ No newline at end of file diff --git a/tests/database/migrations/2021_03_17_225733_create_character_infos_table.php b/tests/database/migrations/2021_03_17_225733_create_character_infos_table.php new file mode 100644 index 00000000..753c6ce5 --- /dev/null +++ b/tests/database/migrations/2021_03_17_225733_create_character_infos_table.php @@ -0,0 +1,67 @@ +bigInteger('character_id')->primary(); + $table->string('name'); + $table->text('description')->nullable(); + $table->string('birthday'); + $table->string('gender'); + $table->integer('race_id'); + $table->integer('bloodline_id'); + $table->integer('ancestry_id')->nullable(); + $table->double('security_status')->nullable(); + $table->string('title')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_infos'); + } +} From 98b7089a8c603fb954097ff07f6d4c26a748e5d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Thu, 18 Mar 2021 21:22:07 +0100 Subject: [PATCH 02/42] test(jobs): cover character affiliation --- src/Models/Character/CharacterAffiliation.php | 10 ++ tests/Jobs/Esi/Character/AffiliationTest.php | 139 ++++++++++++++++++ .../Esi/Character/AffiliationResource.php | 20 +++ tests/artifacts/characters/affiliation.json | 22 +++ ...08_create_character_affiliations_table.php | 65 ++++++++ 5 files changed, 256 insertions(+) create mode 100644 tests/Jobs/Esi/Character/AffiliationTest.php create mode 100644 tests/Resources/Esi/Character/AffiliationResource.php create mode 100644 tests/artifacts/characters/affiliation.json create mode 100644 tests/database/migrations/2021_03_18_205908_create_character_affiliations_table.php diff --git a/src/Models/Character/CharacterAffiliation.php b/src/Models/Character/CharacterAffiliation.php index 55a0acaf..d091e669 100644 --- a/src/Models/Character/CharacterAffiliation.php +++ b/src/Models/Character/CharacterAffiliation.php @@ -46,6 +46,16 @@ class CharacterAffiliation extends Model */ protected $primaryKey = 'character_id'; + /** + * @var string[] + */ + protected $casts = [ + 'character_id' => 'integer', + 'corporation_id' => 'integer', + 'alliance_id' => 'integer', + 'faction_id' => 'integer', + ]; + /** * @return \Illuminate\Database\Eloquent\Relations\HasOne */ diff --git a/tests/Jobs/Esi/Character/AffiliationTest.php b/tests/Jobs/Esi/Character/AffiliationTest.php new file mode 100644 index 00000000..13378858 --- /dev/null +++ b/tests/Jobs/Esi/Character/AffiliationTest.php @@ -0,0 +1,139 @@ + carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_success); // http@200 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $job = new Affiliation([95538921, 1477919642, 90795931, 96057938]); + $job->handle(); + + $affiliation = CharacterAffiliation::all(); + + $data = json_encode(AffiliationResource::collection($affiliation)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/affiliation.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleUpdated() + { + $affiliation = new CharacterAffiliation([ + 'character_id' => 90795931, + 'corporation_id' => 98413060, + ]); + $affiliation->save(); + + $data = json_encode($affiliation); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/affiliation.json', $data); + + $job = new Affiliation([90795931]); + $job->handle(); + + $affiliation = CharacterAffiliation::all(); + + $data = json_encode(AffiliationResource::collection($affiliation)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/affiliation.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $job = new Affiliation([404]); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $job = new Affiliation([420]); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $job = new Affiliation([500]); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $job = new Affiliation([503]); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $job = new Affiliation([504]); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Character/AffiliationResource.php b/tests/Resources/Esi/Character/AffiliationResource.php new file mode 100644 index 00000000..135b3a7e --- /dev/null +++ b/tests/Resources/Esi/Character/AffiliationResource.php @@ -0,0 +1,20 @@ + $this->when($this->alliance_id !== null, $this->alliance_id), + 'character_id' => $this->character_id, + 'corporation_id' => $this->corporation_id, + 'faction_id' => $this->when($this->faction_id !== null, $this->faction_id), + ]; + } +} \ No newline at end of file diff --git a/tests/artifacts/characters/affiliation.json b/tests/artifacts/characters/affiliation.json new file mode 100644 index 00000000..a698b78f --- /dev/null +++ b/tests/artifacts/characters/affiliation.json @@ -0,0 +1,22 @@ +[ + { + "alliance_id": 99008923, + "character_id": 90795931, + "corporation_id": 98413060 + }, + { + "alliance_id": 434243723, + "character_id": 95538921, + "corporation_id": 109299958 + }, + { + "alliance_id": 498125261, + "character_id": 96057938, + "corporation_id": 98056040 + }, + { + "alliance_id": 1354830081, + "character_id": 1477919642, + "corporation_id": 878023749 + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_03_18_205908_create_character_affiliations_table.php b/tests/database/migrations/2021_03_18_205908_create_character_affiliations_table.php new file mode 100644 index 00000000..1989dcb0 --- /dev/null +++ b/tests/database/migrations/2021_03_18_205908_create_character_affiliations_table.php @@ -0,0 +1,65 @@ +bigInteger('character_id')->primary(); + $table->bigInteger('corporation_id'); + $table->bigInteger('alliance_id')->nullable(); + $table->bigInteger('faction_id')->nullable(); + + $table->index(['corporation_id']); + $table->index(['alliance_id']); + $table->index(['faction_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_affiliations'); + } +} From 8db1c848233cbf4c2836fd430c43620a4c2aa6e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Thu, 18 Mar 2021 21:22:55 +0100 Subject: [PATCH 03/42] test(jobs): rename class to match with setup --- .../Character/{TestInfo.php => InfoTest.php} | 11 ++------- tests/Jobs/Esi/JobEsiTestCase.php | 3 +++ .../Resources/Esi/Character/InfoResource.php | 23 +++++++++---------- 3 files changed, 16 insertions(+), 21 deletions(-) rename tests/Jobs/Esi/Character/{TestInfo.php => InfoTest.php} (96%) diff --git a/tests/Jobs/Esi/Character/TestInfo.php b/tests/Jobs/Esi/Character/InfoTest.php similarity index 96% rename from tests/Jobs/Esi/Character/TestInfo.php rename to tests/Jobs/Esi/Character/InfoTest.php index b1ec5415..4db6143c 100644 --- a/tests/Jobs/Esi/Character/TestInfo.php +++ b/tests/Jobs/Esi/Character/InfoTest.php @@ -15,10 +15,10 @@ use Seat\Eveapi\Tests\Resources\Esi\Character\InfoResource; /** - * Class TestInfo + * Class InfoTest * @package Seat\Eveapi\Tests\Jobs\Esi\Character */ -class TestInfo extends JobEsiTestCase +class InfoTest extends JobEsiTestCase { public static function setUpBeforeClass(): void { @@ -72,13 +72,6 @@ public static function setUpBeforeClass(): void EsiMockFetcher::add($response_success); // http@200 } - public function testTags() - { - $job = new Info(180548812); - - $this->assertEqualsCanonicalizing(['public', 'character', 180548812], $job->tags()); - } - public function testHandleSuccess() { $job = new Info(180548812); diff --git a/tests/Jobs/Esi/JobEsiTestCase.php b/tests/Jobs/Esi/JobEsiTestCase.php index 0433ca0b..dfb7053b 100644 --- a/tests/Jobs/Esi/JobEsiTestCase.php +++ b/tests/Jobs/Esi/JobEsiTestCase.php @@ -3,6 +3,7 @@ namespace Seat\Eveapi\Tests\Jobs\Esi; +use Illuminate\Support\Facades\Event; use Lunaweb\RedisMock\Providers\RedisMockServiceProvider; use Orchestra\Testbench\TestCase; use Seat\Eseye\Configuration; @@ -55,6 +56,8 @@ protected function setUp(): void { parent::setUp(); + Event::fake(); + // override guzzle fetcher by using esi mock Configuration::getInstance()->fetcher = EsiMockFetcher::class; diff --git a/tests/Resources/Esi/Character/InfoResource.php b/tests/Resources/Esi/Character/InfoResource.php index 69f26e3b..90582d02 100644 --- a/tests/Resources/Esi/Character/InfoResource.php +++ b/tests/Resources/Esi/Character/InfoResource.php @@ -3,7 +3,6 @@ namespace Seat\Eveapi\Tests\Resources\Esi\Character; - use Illuminate\Http\Resources\Json\JsonResource; /** @@ -19,18 +18,18 @@ class InfoResource extends JsonResource public function toArray($request) { return [ - 'alliance_id' => $this->when($this->alliance_id !== null, $this->alliance_id), - 'ancestry_id' => $this->when($this->ancestry_id !== null, $this->ancestry_id), - 'birthday' => $this->birthday, - 'bloodline_id' => $this->bloodline_id, - 'corporation_id' => $this->corporation_id, - 'description' => $this->when($this->description !== null, $this->description), - 'faction_id' => $this->when($this->faction_id !== null, $this->faction_id), - 'gender' => $this->gender, - 'name' => $this->name, - 'race_id' => $this->race_id, + 'alliance_id' => $this->when($this->alliance_id !== null, $this->alliance_id), + 'ancestry_id' => $this->when($this->ancestry_id !== null, $this->ancestry_id), + 'birthday' => $this->birthday, + 'bloodline_id' => $this->bloodline_id, + 'corporation_id' => $this->corporation_id, + 'description' => $this->when($this->description !== null, $this->description), + 'faction_id' => $this->when($this->faction_id !== null, $this->faction_id), + 'gender' => $this->gender, + 'name' => $this->name, + 'race_id' => $this->race_id, 'security_status' => $this->when($this->security_status !== null, $this->security_status), - 'title' => $this->when($this->title !== null, $this->title), + 'title' => $this->when($this->title !== null, $this->title), ]; } } From 60bf7624bc973123fd87e6648d2e6e6f1480cc6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Thu, 18 Mar 2021 22:29:20 +0100 Subject: [PATCH 04/42] test(jobs): add character agent research coverage --- .../Character/CharacterAgentResearch.php | 10 + .../Jobs/Esi/Character/AgentResearchTest.php | 390 ++++++++++++++++++ tests/Mocks/Esi/EsiMockFetcher.php | 2 +- .../Esi/Character/AgentsResearchResource.php | 47 +++ .../artifacts/characters/agents_research.json | 23 ++ ..._18_213141_create_refresh_tokens_table.php | 66 +++ ..._create_character_agent_research_table.php | 68 +++ 7 files changed, 605 insertions(+), 1 deletion(-) create mode 100644 tests/Jobs/Esi/Character/AgentResearchTest.php create mode 100644 tests/Resources/Esi/Character/AgentsResearchResource.php create mode 100644 tests/artifacts/characters/agents_research.json create mode 100644 tests/database/migrations/2021_03_18_213141_create_refresh_tokens_table.php create mode 100644 tests/database/migrations/2021_03_18_214641_create_character_agent_research_table.php diff --git a/src/Models/Character/CharacterAgentResearch.php b/src/Models/Character/CharacterAgentResearch.php index ddca3ec7..977be7a9 100644 --- a/src/Models/Character/CharacterAgentResearch.php +++ b/src/Models/Character/CharacterAgentResearch.php @@ -37,6 +37,16 @@ class CharacterAgentResearch extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'agent_id' => 'integer', + 'points_per_day' => 'double', + 'remainder_points' => 'double', + 'skill_type_id' => 'integer', + ]; + /** * @param $value */ diff --git a/tests/Jobs/Esi/Character/AgentResearchTest.php b/tests/Jobs/Esi/Character/AgentResearchTest.php new file mode 100644 index 00000000..d66f4c42 --- /dev/null +++ b/tests/Jobs/Esi/Character/AgentResearchTest.php @@ -0,0 +1,390 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/characters/agents_research.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_agents_research.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new AgentsResearch($token); + $job->handle(); + + $agents = CharacterAgentResearch::all(); + + $data = json_encode(AgentsResearchResource::collection($agents)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/agents_research.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_agents_research.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterAgentResearch::create([ + 'character_id' => 180548812, + 'agent_id' => 3014221, + 'points_per_day' => 12.39, + 'remainder_points' => -879844.32, + 'skill_type_id' => 25003, + 'started_at' => '2016-01-10T00:39:55Z' + ]); + CharacterAgentResearch::create([ + 'character_id' => 180548812, + 'agent_id' => 3012880, + 'points_per_day' => 7.2, + 'remainder_points' => 16544678.18, + 'skill_type_id' => 17805, + 'started_at' => '2016-01-10T00:39:55Z' + ]); + CharacterAgentResearch::create([ + 'character_id' => 180548812, + 'agent_id' => 3011474, + 'points_per_day' => 0.0, + 'remainder_points' => 309.44, + 'skill_type_id' => 13654, + 'started_at' => '2016-01-10T00:39:55Z' + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new AgentsResearch($token); + $job->handle(); + + $agents = CharacterAgentResearch::all(); + + foreach ($agents as $agent) + $this->assertEquals($agent->created_at, $agent->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/characters/180548812/agents_research/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_agents_research.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterAgentResearch::create([ + 'character_id' => 180548812, + 'agent_id' => 3014221, + 'points_per_day' => 12.39, + 'remainder_points' => -879844.32, + 'skill_type_id' => 25003, + 'started_at' => '2016-01-10T00:39:55Z' + ]); + CharacterAgentResearch::create([ + 'character_id' => 180548812, + 'agent_id' => 3012880, + 'points_per_day' => 7.2, + 'remainder_points' => 16544678.18, + 'skill_type_id' => 17805, + 'started_at' => '2016-01-10T00:39:55Z' + ]); + CharacterAgentResearch::create([ + 'character_id' => 180548812, + 'agent_id' => 3011474, + 'points_per_day' => 0.0, + 'remainder_points' => 309.44, + 'skill_type_id' => 13654, + 'started_at' => '2016-01-10T00:39:55Z' + ]); + + $agents = CharacterAgentResearch::all(); + $data = json_encode(AgentsResearchResource::collection($agents)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/agents_research.json', $data); + + $job = new AgentsResearch($token); + $job->handle(); + + $agents = CharacterAgentResearch::all(); + $data = json_encode(AgentsResearchResource::collection($agents)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/agents_research.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_agents_research.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new AgentsResearch($token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_agents_research.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new AgentsResearch($token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_agents_research.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new AgentsResearch($token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_agents_research.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new AgentsResearch($token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_agents_research.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new AgentsResearch($token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_agents_research.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new AgentsResearch($token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new AgentsResearch($token); + $job->handle(); + } +} diff --git a/tests/Mocks/Esi/EsiMockFetcher.php b/tests/Mocks/Esi/EsiMockFetcher.php index 243a329d..2d9c1bc2 100644 --- a/tests/Mocks/Esi/EsiMockFetcher.php +++ b/tests/Mocks/Esi/EsiMockFetcher.php @@ -40,7 +40,7 @@ public function __construct(EsiAuthentication $authentication = null) $this->scopes = ['public']; if (! is_null($authentication)) - $this->scopes = empty($authentication->scopes) ? ['public'] : $authentication->scopes; + $this->scopes = empty($authentication->offsetGet('scopes')) ? ['public'] : $authentication->offsetGet('scopes'); } /** diff --git a/tests/Resources/Esi/Character/AgentsResearchResource.php b/tests/Resources/Esi/Character/AgentsResearchResource.php new file mode 100644 index 00000000..32756d2b --- /dev/null +++ b/tests/Resources/Esi/Character/AgentsResearchResource.php @@ -0,0 +1,47 @@ + $this->agent_id, + 'points_per_day' => $this->points_per_day, + 'remainder_points' => $this->remainder_points, + 'skill_type_id' => $this->skill_type_id, + 'started_at' => carbon($this->started_at)->toIso8601ZuluString(), + ]; + } +} diff --git a/tests/artifacts/characters/agents_research.json b/tests/artifacts/characters/agents_research.json new file mode 100644 index 00000000..d3e32183 --- /dev/null +++ b/tests/artifacts/characters/agents_research.json @@ -0,0 +1,23 @@ +[ + { + "agent_id": 3014221, + "points_per_day": 31.25, + "remainder_points": 76877.06, + "skill_type_id": 11445, + "started_at": "2016-01-10T00:39:55Z" + }, + { + "agent_id": 3012880, + "points_per_day": 21.93, + "remainder_points": -12950.18, + "skill_type_id": 11450, + "started_at": "2015-06-04T05:41:09Z" + }, + { + "agent_id": 3011474, + "points_per_day": 12.78, + "remainder_points": 35.10, + "skill_type_id": 11446, + "started_at": "2019-04-22T12:25:28Z" + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_03_18_213141_create_refresh_tokens_table.php b/tests/database/migrations/2021_03_18_213141_create_refresh_tokens_table.php new file mode 100644 index 00000000..00fd7080 --- /dev/null +++ b/tests/database/migrations/2021_03_18_213141_create_refresh_tokens_table.php @@ -0,0 +1,66 @@ +bigInteger('character_id')->primary(); + $table->smallInteger('version'); + $table->integer('user_id'); + $table->mediumText('refresh_token'); + $table->longText('scopes'); + $table->dateTime('expires_on'); + $table->text('token'); + $table->string('character_owner_hash'); + + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('refresh_tokens'); + } +} diff --git a/tests/database/migrations/2021_03_18_214641_create_character_agent_research_table.php b/tests/database/migrations/2021_03_18_214641_create_character_agent_research_table.php new file mode 100644 index 00000000..631d4f05 --- /dev/null +++ b/tests/database/migrations/2021_03_18_214641_create_character_agent_research_table.php @@ -0,0 +1,68 @@ +bigIncrements('id'); + $table->bigInteger('character_id'); + $table->integer('agent_id'); + $table->integer('skill_type_id'); + $table->dateTime('started_at'); + $table->double('points_per_day'); + $table->double('remainder_points'); + + $table->unique(['character_id', 'agent_id']); + $table->index(['character_id']); + $table->index(['agent_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_agent_research'); + } +} From e4911b819316b68b1340eb9e33b5e1dc3c12634e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Thu, 18 Mar 2021 22:32:28 +0100 Subject: [PATCH 05/42] chore: update licence header --- tests/Jobs/Esi/Character/AffiliationTest.php | 22 ++++++++++++++++- .../Jobs/Esi/Character/AgentResearchTest.php | 2 +- tests/Jobs/Esi/Character/InfoTest.php | 21 +++++++++++++++- tests/Jobs/Esi/JobEsiTestCase.php | 19 +++++++++++++++ tests/Mocks/Esi/EsiInMemoryCache.php | 22 +++++++++++++++-- tests/Mocks/Esi/EsiMockFetcher.php | 21 +++++++++++++++- .../Esi/Character/AffiliationResource.php | 24 ++++++++++++++++++- .../Esi/Character/AgentsResearchResource.php | 2 +- .../Resources/Esi/Character/InfoResource.php | 21 +++++++++++++++- ...17_225733_create_character_infos_table.php | 4 ++-- ...08_create_character_affiliations_table.php | 4 ++-- ..._18_213141_create_refresh_tokens_table.php | 2 +- ..._create_character_agent_research_table.php | 2 +- 13 files changed, 151 insertions(+), 15 deletions(-) diff --git a/tests/Jobs/Esi/Character/AffiliationTest.php b/tests/Jobs/Esi/Character/AffiliationTest.php index 13378858..b92d8a20 100644 --- a/tests/Jobs/Esi/Character/AffiliationTest.php +++ b/tests/Jobs/Esi/Character/AffiliationTest.php @@ -1,5 +1,25 @@ Date: Thu, 18 Mar 2021 22:33:55 +0100 Subject: [PATCH 06/42] ci: add travis setup --- .travis.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..53d045e5 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +language: php +php: + - 7.3 +before_script: + - pecl install -o -f redis <<<"" + - composer update + - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter + - chmod +x ./cc-test-reporter + - ./cc-test-reporter before-build +script: + - vendor/bin/phpunit -c phpunit.xml +after_script: + - ./cc-test-reporter after-build \ No newline at end of file From 40a4b5ba23b3776e288d13939b8bd2aacc5f3060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Thu, 18 Mar 2021 22:47:41 +0100 Subject: [PATCH 07/42] ci: enable code coverage --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 53d045e5..d4feed4f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,7 @@ language: php +env: + global: + - XDEBUG_MODE=coverage php: - 7.3 before_script: From 2ec3307de4a687ea11ff1a5a72b845b174d26cb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Thu, 18 Mar 2021 23:33:37 +0100 Subject: [PATCH 08/42] test(jobs): add character blueprints coverage --- src/Models/Character/CharacterBlueprint.php | 9 + tests/Jobs/Esi/Character/BlueprintsTest.php | 366 ++++++++++++++++++ .../Esi/Character/BlueprintResource.php | 50 +++ tests/artifacts/characters/blueprints.json | 12 + ...1342_create_character_blueprints_table.php | 69 ++++ 5 files changed, 506 insertions(+) create mode 100644 tests/Jobs/Esi/Character/BlueprintsTest.php create mode 100644 tests/Resources/Esi/Character/BlueprintResource.php create mode 100644 tests/artifacts/characters/blueprints.json create mode 100644 tests/database/migrations/2021_03_18_231342_create_character_blueprints_table.php diff --git a/src/Models/Character/CharacterBlueprint.php b/src/Models/Character/CharacterBlueprint.php index 238cadfa..5fb16aae 100644 --- a/src/Models/Character/CharacterBlueprint.php +++ b/src/Models/Character/CharacterBlueprint.php @@ -47,6 +47,15 @@ class CharacterBlueprint extends Model */ protected $primaryKey = 'item_id'; + protected $casts = [ + 'location_id' => 'integer', + 'material_efficiency' => 'integer', + 'quantity' => 'integer', + 'runs' => 'integer', + 'time_efficiency' => 'integer', + 'type_id' => 'integer' + ]; + /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ diff --git a/tests/Jobs/Esi/Character/BlueprintsTest.php b/tests/Jobs/Esi/Character/BlueprintsTest.php new file mode 100644 index 00000000..ef4e8ee1 --- /dev/null +++ b/tests/Jobs/Esi/Character/BlueprintsTest.php @@ -0,0 +1,366 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + 'X-Pages' => 1, + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/characters/blueprints.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + 'X-Pages' => 1, + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Blueprints($token); + $job->handle(); + + $agents = CharacterBlueprint::all(); + + $data = json_encode(BlueprintResource::collection($agents)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/blueprints.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterBlueprint::create([ + 'character_id' => 180548812, + 'item_id' => 1000000010495, + 'location_flag' => 'Hangar', + 'location_id' => 60014719, + 'material_efficiency' => 0, + 'quantity' => 1, + 'runs' => -1, + 'time_efficiency' => 0, + 'type_id' => 691 + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Blueprints($token); + $job->handle(); + + $blueprints = CharacterBlueprint::all(); + + foreach ($blueprints as $blueprint) + $this->assertEquals($blueprint->created_at, $blueprint->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v2/characters/180548812/blueprints/', 'datasource=tranquility&page=1'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterBlueprint::create([ + 'character_id' => 180548812, + 'item_id' => 1000000010495, + 'location_flag' => 'RigSlot2', + 'location_id' => 1654676464, + 'material_efficiency' => 7, + 'quantity' => 1, + 'runs' => -1, + 'time_efficiency' => 3, + 'type_id' => 730 + ]); + + $blueprints = CharacterBlueprint::all(); + $data = json_encode(BlueprintResource::collection($blueprints)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/blueprints.json', $data); + + $job = new Blueprints($token); + $job->handle(); + + $blueprints = CharacterBlueprint::all(); + $data = json_encode(BlueprintResource::collection($blueprints)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/blueprints.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Blueprints($token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Blueprints($token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Blueprints($token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Blueprints($token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Blueprints($token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Blueprints($token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Blueprints($token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Character/BlueprintResource.php b/tests/Resources/Esi/Character/BlueprintResource.php new file mode 100644 index 00000000..3625c1af --- /dev/null +++ b/tests/Resources/Esi/Character/BlueprintResource.php @@ -0,0 +1,50 @@ + $this->item_id, + 'location_flag' => $this->location_flag, + 'location_id' => $this->location_id, + 'material_efficiency' => $this->material_efficiency, + 'quantity' => $this->quantity, + 'runs' => $this->runs, + 'time_efficiency' => $this->time_efficiency, + 'type_id' => $this->type_id, + ]; + } +} diff --git a/tests/artifacts/characters/blueprints.json b/tests/artifacts/characters/blueprints.json new file mode 100644 index 00000000..a03ff8c3 --- /dev/null +++ b/tests/artifacts/characters/blueprints.json @@ -0,0 +1,12 @@ +[ + { + "item_id": 1000000010495, + "location_flag": "Hangar", + "location_id": 60014719, + "material_efficiency": 0, + "quantity": 1, + "runs": -1, + "time_efficiency": 0, + "type_id": 691 + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_03_18_231342_create_character_blueprints_table.php b/tests/database/migrations/2021_03_18_231342_create_character_blueprints_table.php new file mode 100644 index 00000000..016721d3 --- /dev/null +++ b/tests/database/migrations/2021_03_18_231342_create_character_blueprints_table.php @@ -0,0 +1,69 @@ +bigInteger('item_id')->primary(); + $table->bigInteger('character_id'); + $table->integer('type_id'); + $table->string('location_flag'); + $table->bigInteger('location_id'); + $table->integer('quantity'); + $table->integer('time_efficiency'); + $table->integer('material_efficiency'); + $table->integer('runs'); + + $table->index(['character_id']); + $table->index(['type_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_blueprints'); + } +} From fe4dcec6e78c93b49d0556264b433c09857b2fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sat, 20 Mar 2021 17:58:38 +0100 Subject: [PATCH 09/42] test(jobs): add more character coverage --- .../Character/CharacterCorporationHistory.php | 2 + src/Models/Character/CharacterMedal.php | 9 + .../Character/CharacterNotification.php | 4 +- tests/Jobs/Esi/Character/BlueprintsTest.php | 4 +- .../Esi/Character/CorporationHistoryTest.php | 196 ++++++++ tests/Jobs/Esi/Character/FatigueTest.php | 355 ++++++++++++++ tests/Jobs/Esi/Character/MedalsTest.php | 418 ++++++++++++++++ .../Jobs/Esi/Character/NotificationsTest.php | 380 +++++++++++++++ tests/Jobs/Esi/Character/RolesTest.php | 445 ++++++++++++++++++ .../Character/CorporationHistoryResource.php | 46 ++ .../Esi/Character/FatigueResource.php | 45 ++ .../Resources/Esi/Character/MedalResource.php | 51 ++ .../Esi/Character/NotificationResource.php | 49 ++ .../Resources/Esi/Character/RoleResource.php | 46 ++ .../characters/corporation_history.json | 23 + tests/artifacts/characters/fatigue.json | 5 + tests/artifacts/characters/medals.json | 170 +++++++ tests/artifacts/characters/notifications.json | 20 + tests/artifacts/characters/roles.json | 15 + ..._character_corporation_histories_table.php | 66 +++ ...131213_create_character_fatigues_table.php | 61 +++ ...0_162022_create_character_medals_table.php | 71 +++ ...8_create_character_notifications_table.php | 69 +++ ...20_172715_create_character_roles_table.php | 64 +++ 24 files changed, 2611 insertions(+), 3 deletions(-) create mode 100644 tests/Jobs/Esi/Character/CorporationHistoryTest.php create mode 100644 tests/Jobs/Esi/Character/FatigueTest.php create mode 100644 tests/Jobs/Esi/Character/MedalsTest.php create mode 100644 tests/Jobs/Esi/Character/NotificationsTest.php create mode 100644 tests/Jobs/Esi/Character/RolesTest.php create mode 100644 tests/Resources/Esi/Character/CorporationHistoryResource.php create mode 100644 tests/Resources/Esi/Character/FatigueResource.php create mode 100644 tests/Resources/Esi/Character/MedalResource.php create mode 100644 tests/Resources/Esi/Character/NotificationResource.php create mode 100644 tests/Resources/Esi/Character/RoleResource.php create mode 100644 tests/artifacts/characters/corporation_history.json create mode 100644 tests/artifacts/characters/fatigue.json create mode 100644 tests/artifacts/characters/medals.json create mode 100644 tests/artifacts/characters/notifications.json create mode 100644 tests/artifacts/characters/roles.json create mode 100644 tests/database/migrations/2021_03_20_105237_create_character_corporation_histories_table.php create mode 100644 tests/database/migrations/2021_03_20_131213_create_character_fatigues_table.php create mode 100644 tests/database/migrations/2021_03_20_162022_create_character_medals_table.php create mode 100644 tests/database/migrations/2021_03_20_170438_create_character_notifications_table.php create mode 100644 tests/database/migrations/2021_03_20_172715_create_character_roles_table.php diff --git a/src/Models/Character/CharacterCorporationHistory.php b/src/Models/Character/CharacterCorporationHistory.php index d1a7193e..63b1112b 100644 --- a/src/Models/Character/CharacterCorporationHistory.php +++ b/src/Models/Character/CharacterCorporationHistory.php @@ -72,6 +72,8 @@ class CharacterCorporationHistory extends Model * @var array */ protected $casts = [ + 'corporation_id' => 'integer', + 'record_id' => 'integer', 'is_deleted' => 'boolean', ]; diff --git a/src/Models/Character/CharacterMedal.php b/src/Models/Character/CharacterMedal.php index 207e71fa..0a2fa54f 100644 --- a/src/Models/Character/CharacterMedal.php +++ b/src/Models/Character/CharacterMedal.php @@ -36,6 +36,15 @@ class CharacterMedal extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'corporation_id' => 'integer', + 'issuer_id' => 'integer', + 'medal_id' => 'integer', + ]; + /** * @param $value */ diff --git a/src/Models/Character/CharacterNotification.php b/src/Models/Character/CharacterNotification.php index e2c6cdee..2e7bb5e8 100644 --- a/src/Models/Character/CharacterNotification.php +++ b/src/Models/Character/CharacterNotification.php @@ -101,7 +101,9 @@ class CharacterNotification extends Model * @var array */ protected $casts = [ - 'is_read' => 'boolean', + 'notification_id' => 'integer', + 'sender_id' => 'integer', + 'is_read' => 'boolean', ]; /** diff --git a/tests/Jobs/Esi/Character/BlueprintsTest.php b/tests/Jobs/Esi/Character/BlueprintsTest.php index ef4e8ee1..406d6ca3 100644 --- a/tests/Jobs/Esi/Character/BlueprintsTest.php +++ b/tests/Jobs/Esi/Character/BlueprintsTest.php @@ -115,9 +115,9 @@ public function testHandleSuccess() $job = new Blueprints($token); $job->handle(); - $agents = CharacterBlueprint::all(); + $blueprints = CharacterBlueprint::all(); - $data = json_encode(BlueprintResource::collection($agents)); + $data = json_encode(BlueprintResource::collection($blueprints)); $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/blueprints.json', $data); } diff --git a/tests/Jobs/Esi/Character/CorporationHistoryTest.php b/tests/Jobs/Esi/Character/CorporationHistoryTest.php new file mode 100644 index 00000000..61508e4f --- /dev/null +++ b/tests/Jobs/Esi/Character/CorporationHistoryTest.php @@ -0,0 +1,196 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $job = new CorporationHistory(90795931); + $job->handle(); + + $corporations = CharacterCorporationHistory::all(); + + $data = json_encode(CorporationHistoryResource::collection($corporations)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/corporation_history.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + CharacterCorporationHistory::create([ + 'character_id' => 90795931, + 'corporation_id' => 98413060, + 'record_id' => 303, + 'is_deleted' => false, + 'start_date' => '2018-08-24T17:42:00Z', + ]); + + CharacterCorporationHistory::create([ + 'character_id' => 90795931, + 'corporation_id' => 98456198, + 'record_id' => 1009, + 'is_deleted' => false, + 'start_date' => '2017-02-01T20:50:00Z', + ]); + + CharacterCorporationHistory::create([ + 'character_id' => 90795931, + 'corporation_id' => 1000014, + 'record_id' => 198797, + 'is_deleted' => false, + 'start_date' => '2017-02-01T20:50:00Z', + ]); + + CharacterCorporationHistory::create([ + 'character_id' => 90795931, + 'corporation_id' => 98451304, + 'record_id' => 917, + 'is_deleted' => true, + 'start_date' => '2016-08-07T13:45:00Z', + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new CorporationHistory(90795931); + $job->handle(); + + $corporations = CharacterCorporationHistory::all(); + + foreach ($corporations as $corporation) + $this->assertEquals($corporation->created_at, $corporation->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $job = new CorporationHistory(404); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $job = new CorporationHistory(420); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $job = new CorporationHistory(500); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $job = new CorporationHistory(503); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $job = new CorporationHistory(504); + $job->handle(); + } +} diff --git a/tests/Jobs/Esi/Character/FatigueTest.php b/tests/Jobs/Esi/Character/FatigueTest.php new file mode 100644 index 00000000..60b4bf21 --- /dev/null +++ b/tests/Jobs/Esi/Character/FatigueTest.php @@ -0,0 +1,355 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/characters/fatigue.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_fatigue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Fatigue($token); + $job->handle(); + + $fatigue = CharacterFatigue::find(180548812); + + $data = json_encode(new FatigueResource($fatigue)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/fatigue.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_fatigue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $fatigue = new CharacterFatigue([ + 'character_id' => 180548812, + 'jump_fatigue_expire_date' => '2015-03-23T11:37:00Z', + 'last_jump_date' => '2015-03-24T10:37:00Z', + 'last_update_date' => '2015-03-24T11:37:00Z', + ]); + $fatigue->save(); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Fatigue($token); + $job->handle(); + + $fatigue = CharacterFatigue::find(180548812); + + $this->assertEquals($fatigue->created_at, $fatigue->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/characters/180548812/fatigue/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_fatigue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $fatigue = new CharacterFatigue([ + 'character_id' => 180548812, + 'jump_fatigue_expire_date' => '2015-03-23T11:37:00Z', + 'last_jump_date' => '2015-03-24T10:37:00Z', + 'last_update_date' => '2015-03-24T11:37:00Z', + ]); + $fatigue->save(); + + $data = json_encode(new FatigueResource($fatigue)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/fatigue.json', $data); + + $job = new Fatigue($token); + $job->handle(); + + $fatigue = CharacterFatigue::find(180548812); + + $data = json_encode(new FatigueResource($fatigue)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/fatigue.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_fatigue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Fatigue($token); + $job->handle(); + } + + /** + * @depends testHandleUpdated + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_fatigue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Fatigue($token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_fatigue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Fatigue($token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_fatigue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Fatigue($token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_fatigue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Fatigue($token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_fatigue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Fatigue($token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Fatigue($token); + $job->handle(); + } +} diff --git a/tests/Jobs/Esi/Character/MedalsTest.php b/tests/Jobs/Esi/Character/MedalsTest.php new file mode 100644 index 00000000..f3507269 --- /dev/null +++ b/tests/Jobs/Esi/Character/MedalsTest.php @@ -0,0 +1,418 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/characters/medals.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 90795931, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Medals($token); + $job->handle(); + + $medals = CharacterMedal::all(); + + $data = json_encode(MedalResource::collection($medals)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/medals.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 90795931, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterMedal::create([ + 'character_id' => 90795931, + 'medal_id' => 24460, + 'title' => 'Medaille des 1 an de services', + 'description' => 'Dédiée aux vieux.....', + 'corporation_id' => 144275616, + 'issuer_id' => 341025466, + 'date' => '2018-07-01T19:37:39Z', + 'reason' => 'Old Man', + 'status' => 'private', + 'graphics' => json_encode('[{"color": -1,"graphic": "Caldari.01_01","layer": 0,"part": 1},{"color": -15132388,"graphic": "Caldari.3_1","layer": 1,"part": 1},{"color": -8847360,"graphic": "Caldari.2_4","layer": 2,"part": 1},{"color": -596431,"graphic": "Caldari.01_02","layer": 3,"part": 1},{"color": -1,"graphic": "elements.13_1","layer": 0,"part": 2},{"color": -1,"graphic": "star.2_2","layer": 1,"part": 2}]'), + ]); + + CharacterMedal::create([ + 'character_id' => 90795931, + 'medal_id' => 44753, + 'title' => 'Médaille des 2 ans de services', + 'description' => 'Dédiée aux plus vieux que les vieux', + 'corporation_id' => 144275616, + 'issuer_id' => 341025466, + 'date' => '2019-07-01 19:37:53', + 'reason' => 'Very Old Man', + 'status' => 'private', + 'graphics' => json_encode('[{"color":-1,"graphic":"Caldari.01_01","layer":0,"part":1},{"color":-8847360,"graphic":"Caldari.2_4","layer":1,"part":1},{"color":-15132388,"graphic":"Caldari.3_1","layer":2,"part":1},{"color":-596431,"graphic":"Caldari.01_02","layer":3,"part":1},{"color":-1,"graphic":"elements.21_1","layer":0,"part":2},{"color":-1,"graphic":"elements.13_1","layer":1,"part":2},{"color":-1,"graphic":"star.2_2","layer":2,"part":2}]'), + ]); + + CharacterMedal::create([ + 'character_id' => 90795931, + 'medal_id' => 71835, + 'title' => 'Médaille du gentlemen', + 'description' => 'Décoration attribuée pour services rendus durant la guerre qui nous opposa aux gentlemens durant les premiers jours de juillets.
Surcouf en son temps résuma très bien ce genre de combats entre les français et les anglais:
Alors que Surcouf (corsaire français) avait capturé un navire anglais, son capitaine, attaché sur son propre navire s\'addresse à lui en ces termes: "Vous les français, vous vous battez pour l\'argent, tandis que nous, anglais, nous nous battons pour l\'honneur". Ce à quoi Surcouf, dans un anglais parfait, répondit "Nous nous battons toujours pour ce que nous n\'avons pas..."

', + 'corporation_id' => 144275616, + 'issuer_id' => 412492115, + 'date' => '2014-07-10 22:44:43', + 'reason' => 'Pour un scoot redoutable et une présence incroyable', + 'status' => 'private', + 'graphics' => json_encode('[{"color":-1,"graphic":"Caldari.1_1","layer":0,"part":1},{"color":-8847360,"graphic":"Caldari.2_4","layer":1,"part":1},{"color":-4254186,"graphic":"Caldari.2_1","layer":2,"part":1},{"color":-15191726,"graphic":"Caldari.3_1","layer":3,"part":1},{"color":-330271,"graphic":"Caldari.1_2","layer":4,"part":1},{"color":-1,"graphic":"elements.24_2","layer":0,"part":2},{"color":-1,"graphic":"elements.13_2","layer":1,"part":2},{"color":-1,"graphic":"elements.17_2","layer":2,"part":2},{"color":-1,"graphic":"star.3_2","layer":3,"part":2}]'), + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Medals($token); + $job->handle(); + + $medals = CharacterMedal::all(); + + foreach ($medals as $medal) + $this->assertEquals($medal->created_at, $medal->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/characters/90795931/medals/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 90795931, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterMedal::create([ + 'character_id' => 90795931, + 'medal_id' => 24460, + 'title' => 'Medaille des 1 an de services', + 'description' => 'Dédiée aux vieux.....', + 'corporation_id' => 144275616, + 'issuer_id' => 341025466, + 'date' => '2018-07-01T19:37:39Z', + 'reason' => 'Old Man', + 'status' => 'private', + 'graphics' => json_encode('[{"color": -1,"graphic": "Caldari.01_01","layer": 0,"part": 1},{"color": -15132388,"graphic": "Caldari.3_1","layer": 1,"part": 1},{"color": -8847360,"graphic": "Caldari.2_4","layer": 2,"part": 1},{"color": -596431,"graphic": "Caldari.01_02","layer": 3,"part": 1},{"color": -1,"graphic": "elements.13_1","layer": 0,"part": 2},{"color": -1,"graphic": "star.2_2","layer": 1,"part": 2}]'), + ]); + + CharacterMedal::create([ + 'character_id' => 90795931, + 'medal_id' => 44753, + 'title' => 'Médaille des 2 ans de services', + 'description' => 'Dédiée aux plus vieux que les vieux', + 'corporation_id' => 144275616, + 'issuer_id' => 341025466, + 'date' => '2019-07-01 19:37:53', + 'reason' => 'Very Old Man', + 'status' => 'private', + 'graphics' => json_encode('[{"color":-1,"graphic":"Caldari.01_01","layer":0,"part":1},{"color":-8847360,"graphic":"Caldari.2_4","layer":1,"part":1},{"color":-15132388,"graphic":"Caldari.3_1","layer":2,"part":1},{"color":-596431,"graphic":"Caldari.01_02","layer":3,"part":1},{"color":-1,"graphic":"elements.21_1","layer":0,"part":2},{"color":-1,"graphic":"elements.13_1","layer":1,"part":2},{"color":-1,"graphic":"star.2_2","layer":2,"part":2}]'), + ]); + + CharacterMedal::create([ + 'character_id' => 90795931, + 'medal_id' => 71835, + 'title' => 'Médaille du gentlemen', + 'description' => 'Décoration attribuée pour services rendus durant la guerre qui nous opposa aux gentlemens durant les premiers jours de juillets.
Surcouf en son temps résuma très bien ce genre de combats entre les français et les anglais:
Alors que Surcouf (corsaire français) avait capturé un navire anglais, son capitaine, attaché sur son propre navire s\'addresse à lui en ces termes: "Vous les français, vous vous battez pour l\'argent, tandis que nous, anglais, nous nous battons pour l\'honneur". Ce à quoi Surcouf, dans un anglais parfait, répondit "Nous nous battons toujours pour ce que nous n\'avons pas..."

', + 'corporation_id' => 144275616, + 'issuer_id' => 412492115, + 'date' => '2014-07-10 22:44:43', + 'reason' => 'Pour un scoot redoutable et une présence incroyable', + 'status' => 'private', + 'graphics' => json_encode('[{"color":-1,"graphic":"Caldari.1_1","layer":0,"part":1},{"color":-8847360,"graphic":"Caldari.2_4","layer":1,"part":1},{"color":-4254186,"graphic":"Caldari.2_1","layer":2,"part":1},{"color":-15191726,"graphic":"Caldari.3_1","layer":3,"part":1},{"color":-330271,"graphic":"Caldari.1_2","layer":4,"part":1},{"color":-1,"graphic":"elements.24_2","layer":0,"part":2},{"color":-1,"graphic":"elements.13_2","layer":1,"part":2},{"color":-1,"graphic":"elements.17_2","layer":2,"part":2},{"color":-1,"graphic":"star.3_2","layer":3,"part":2}]'), + ]); + + $medals = CharacterMedal::all(); + $data = json_encode(MedalResource::collection($medals)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/medals.json', $data); + + $job = new Medals($token); + $job->handle(); + + $medals = CharacterMedal::all(); + $data = json_encode(MedalResource::collection($medals)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/medals.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Medals($token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Medals($token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Medals($token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Medals($token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Medals($token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Medals($token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Medals($token); + $job->handle(); + } +} diff --git a/tests/Jobs/Esi/Character/NotificationsTest.php b/tests/Jobs/Esi/Character/NotificationsTest.php new file mode 100644 index 00000000..fd34a8a9 --- /dev/null +++ b/tests/Jobs/Esi/Character/NotificationsTest.php @@ -0,0 +1,380 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/characters/notifications.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_notifications.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Notifications($token); + $job->handle(); + + $notifications = CharacterNotification::all(); + + $data = json_encode(NotificationResource::collection($notifications)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/notifications.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_notifications.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterNotification::create([ + 'character_id' => 180548812, + 'notification_id' => 1, + 'sender_id' => 1000120, + 'sender_type' => 'character', + 'text' => 'amount: 103.6006\\nitemID: 1024881021663\\npayout: 1\\n', + 'timestamp' => '2019-08-16T10:08:00Z', + 'type' => 'CorpFriendlyFireEnableTimerStarted', + ]); + + CharacterNotification::create([ + 'character_id' => 180548812, + 'notification_id' => 809110712, + 'sender_id' => 654564, + 'sender_type' => 'character', + 'text' => 'dummy text', + 'timestamp' => '2019-08-16T10:08:00Z', + 'type' => 'BountyClaimMsg', + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Notifications($token); + $job->handle(); + + $notifications = CharacterNotification::all(); + + foreach ($notifications as $notification) + $this->assertEquals($notification->created_at, $notification->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v5/characters/180548812/notifications/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_notifications.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterNotification::create([ + 'character_id' => 180548812, + 'notification_id' => 1, + 'sender_id' => 1000120, + 'sender_type' => 'character', + 'text' => 'amount: 103.6006\nitemID: 1024881021663\npayout: 1\n', + 'timestamp' => '2019-08-16T10:08:00Z', + 'type' => 'CorpFriendlyFireEnableTimerStarted', + ]); + + CharacterNotification::create([ + 'character_id' => 180548812, + 'notification_id' => 809110712, + 'sender_id' => 654564, + 'sender_type' => 'corporation', + 'text' => 'charID: 1636344400\nlistOfTypesAndQty:\n- - 1\n - 3297\nsolarsystemID: 30004787\nstructureID: &id001 1022892578773\nstructureShowInfoData:\n- showinfo\n- 35827\n- *id001\nstructureTypeID: 35827\n', + 'timestamp' => '2018-04-27 18:39:00Z', + 'type' => 'StructureItemsDelivered', + ]); + + $notifications = CharacterNotification::all(); + $data = json_encode(NotificationResource::collection($notifications)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/notifications.json', $data); + + $job = new Notifications($token); + $job->handle(); + + $notifications = CharacterNotification::all(); + $data = json_encode(NotificationResource::collection($notifications)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/notifications.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_notifications.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Notifications($token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_notifications.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Notifications($token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_notifications.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Notifications($token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_notifications.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Notifications($token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_notifications.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Notifications($token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_notifications.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Notifications($token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Notifications($token); + $job->handle(); + } +} diff --git a/tests/Jobs/Esi/Character/RolesTest.php b/tests/Jobs/Esi/Character/RolesTest.php new file mode 100644 index 00000000..3ecba998 --- /dev/null +++ b/tests/Jobs/Esi/Character/RolesTest.php @@ -0,0 +1,445 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/characters/roles.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 90795931, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_corporation_roles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $character = CharacterInfo::create([ + 'character_id' => 90795931, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + + $job = new Roles($token); + $job->handle(); + + $data = json_encode(RoleResource::make($character)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/roles.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 90795931, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_corporation_roles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterRole::create([ + 'character_id' => 90795931, + 'role' => 'Directory', + 'scope' => 'roles', + ]); + + CharacterRole::create([ + 'character_id' => 90795931, + 'role' => 'Station_Manager', + 'scope' => 'roles', + ]); + + CharacterRole::create([ + 'character_id' => 90795931, + 'role' => 'roles_at_hq', + 'scope' => 'Hangar_Query_3', + ]); + + CharacterRole::create([ + 'character_id' => 90795931, + 'role' => 'roles_at_hq', + 'scope' => 'Hangar_Query_5', + ]); + + CharacterRole::create([ + 'character_id' => 90795931, + 'role' => 'roles_at_other', + 'scope' => 'Hangar_Take_5', + ]); + + CharacterRole::create([ + 'character_id' => 90795931, + 'role' => 'roles_at_other', + 'scope' => 'Hangar_Query_5', + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Roles($token); + $job->handle(); + + $roles = CharacterRole::all(); + + foreach ($roles as $role) + $this->assertEquals($role->created_at, $role->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v2/characters/90795931/roles/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 90795931, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_corporation_roles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $character = CharacterInfo::create([ + 'character_id' => 90795931, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + + CharacterRole::create([ + 'character_id' => 90795931, + 'role' => 'Directory', + 'scope' => 'roles', + ]); + + CharacterRole::create([ + 'character_id' => 90795931, + 'role' => 'Station_Manager', + 'scope' => 'roles', + ]); + + CharacterRole::create([ + 'character_id' => 90795931, + 'role' => 'roles_at_hq', + 'scope' => 'Hangar_Query_3', + ]); + + CharacterRole::create([ + 'character_id' => 90795931, + 'role' => 'roles_at_hq', + 'scope' => 'Hangar_Query_5', + ]); + + CharacterRole::create([ + 'character_id' => 90795931, + 'role' => 'roles_at_base', + 'scope' => 'Hangar_Take_5', + ]); + + CharacterRole::create([ + 'character_id' => 90795931, + 'role' => 'roles_at_base', + 'scope' => 'Hangar_Query_5', + ]); + + CharacterRole::create([ + 'character_id' => 90795931, + 'role' => 'roles_at_other', + 'scope' => 'Hangar_Take_5', + ]); + + CharacterRole::create([ + 'character_id' => 90795931, + 'role' => 'roles_at_other', + 'scope' => 'Hangar_Query_5', + ]); + + $data = json_encode(RoleResource::make($character)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/roles.json', $data); + + $job = new Roles($token); + $job->handle(); + + $character->load('corporation_roles'); + + $data = json_encode(RoleResource::make($character)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/roles.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_corporation_roles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Roles($token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_corporation_roles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Roles($token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_corporation_roles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Roles($token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_corporation_roles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Roles($token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_corporation_roles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Roles($token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_corporation_roles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Roles($token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Roles($token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Character/CorporationHistoryResource.php b/tests/Resources/Esi/Character/CorporationHistoryResource.php new file mode 100644 index 00000000..b70af6d3 --- /dev/null +++ b/tests/Resources/Esi/Character/CorporationHistoryResource.php @@ -0,0 +1,46 @@ + $this->corporation_id, + 'is_deleted' => $this->when($this->is_deleted, $this->is_deleted), + 'record_id' => $this->record_id, + 'start_date' => carbon($this->start_date)->toIso8601ZuluString(), + ]; + } +} diff --git a/tests/Resources/Esi/Character/FatigueResource.php b/tests/Resources/Esi/Character/FatigueResource.php new file mode 100644 index 00000000..e7319b8c --- /dev/null +++ b/tests/Resources/Esi/Character/FatigueResource.php @@ -0,0 +1,45 @@ + $this->when(! is_null($this->jump_fatigue_expire_date), carbon($this->jump_fatigue_expire_date)->toIso8601ZuluString()), + 'last_jump_date' => $this->when(! is_null($this->last_jump_date), carbon($this->last_jump_date)->toIso8601ZuluString()), + 'last_update_date' => $this->when(! is_null($this->last_update_date), carbon($this->last_update_date)->toIso8601ZuluString()), + ]; + } +} diff --git a/tests/Resources/Esi/Character/MedalResource.php b/tests/Resources/Esi/Character/MedalResource.php new file mode 100644 index 00000000..1980bccb --- /dev/null +++ b/tests/Resources/Esi/Character/MedalResource.php @@ -0,0 +1,51 @@ + $this->corporation_id, + 'date' => carbon($this->date)->toIso8601ZuluString(), + 'description' => $this->description, + 'graphics' => json_decode($this->graphics), + 'issuer_id' => $this->issuer_id, + 'medal_id' => $this->medal_id, + 'reason' => $this->reason, + 'status' => $this->status, + 'title' => $this->title, + ]; + } +} diff --git a/tests/Resources/Esi/Character/NotificationResource.php b/tests/Resources/Esi/Character/NotificationResource.php new file mode 100644 index 00000000..8598febc --- /dev/null +++ b/tests/Resources/Esi/Character/NotificationResource.php @@ -0,0 +1,49 @@ + $this->when($this->is_read, $this->is_read), + 'notification_id' => $this->notification_id, + 'sender_id' => $this->sender_id, + 'sender_type' => $this->sender_type, + 'text' => $this->when(! is_null($this->getOriginal('text')), $this->getOriginal('text')), + 'timestamp' => carbon($this->timestamp)->toIso8601ZuluString(), + 'type' => $this->type, + ]; + } +} diff --git a/tests/Resources/Esi/Character/RoleResource.php b/tests/Resources/Esi/Character/RoleResource.php new file mode 100644 index 00000000..e559e8e3 --- /dev/null +++ b/tests/Resources/Esi/Character/RoleResource.php @@ -0,0 +1,46 @@ + $this->corporation_roles->where('scope', 'roles')->sortBy('role')->pluck('role'), + 'roles_at_base' => $this->corporation_roles->where('scope', 'roles_at_base')->sortBy('role')->pluck('role'), + 'roles_at_hq' => $this->corporation_roles->where('scope', 'roles_at_hq')->sortBy('role')->pluck('role'), + 'roles_at_other' => $this->corporation_roles->where('scope', 'roles_at_other')->sortBy('role')->pluck('role'), + ]; + } +} diff --git a/tests/artifacts/characters/corporation_history.json b/tests/artifacts/characters/corporation_history.json new file mode 100644 index 00000000..4b450ae9 --- /dev/null +++ b/tests/artifacts/characters/corporation_history.json @@ -0,0 +1,23 @@ +[ + { + "corporation_id": 98413060, + "record_id": 48289010, + "start_date": "2018-08-24T17:42:00Z" + }, + { + "corporation_id": 98456198, + "record_id": 44157795, + "start_date": "2017-02-01T20:50:00Z" + }, + { + "corporation_id": 1000014, + "record_id": 44157792, + "start_date": "2017-02-01T20:50:00Z" + }, + { + "corporation_id": 98451304, + "is_deleted": true, + "record_id": 42479868, + "start_date": "2016-08-07T13:45:00Z" + } +] \ No newline at end of file diff --git a/tests/artifacts/characters/fatigue.json b/tests/artifacts/characters/fatigue.json new file mode 100644 index 00000000..26f678ad --- /dev/null +++ b/tests/artifacts/characters/fatigue.json @@ -0,0 +1,5 @@ +{ + "jump_fatigue_expire_date": "2017-07-06T15:47:00Z", + "last_jump_date": "2017-07-05T15:47:00Z", + "last_update_date": "2017-07-05T15:42:00Z" +} \ No newline at end of file diff --git a/tests/artifacts/characters/medals.json b/tests/artifacts/characters/medals.json new file mode 100644 index 00000000..cf2fe482 --- /dev/null +++ b/tests/artifacts/characters/medals.json @@ -0,0 +1,170 @@ +[ + { + "corporation_id": 144275616, + "date": "2013-07-01T19:37:39Z", + "description": "Dédiée aux vieux.....", + "graphics": [ + { + "color": -1, + "graphic": "Caldari.01_01", + "layer": 0, + "part": 1 + }, + { + "color": -15132388, + "graphic": "Caldari.3_1", + "layer": 1, + "part": 1 + }, + { + "color": -8847360, + "graphic": "Caldari.2_4", + "layer": 2, + "part": 1 + }, + { + "color": -596431, + "graphic": "Caldari.01_02", + "layer": 3, + "part": 1 + }, + { + "color": -1, + "graphic": "elements.13_1", + "layer": 0, + "part": 2 + }, + { + "color": -1, + "graphic": "star.2_2", + "layer": 1, + "part": 2 + } + ], + "issuer_id": 341025466, + "medal_id": 24460, + "reason": "Vieux", + "status": "public", + "title": "Medaille des 1 an de services" + }, + { + "corporation_id": 144275616, + "date": "2013-07-01T19:37:53Z", + "description": "Dédiée aux plus vieux que les vieux", + "graphics": [ + { + "color": -1, + "graphic": "Caldari.01_01", + "layer": 0, + "part": 1 + }, + { + "color": -8847360, + "graphic": "Caldari.2_4", + "layer": 1, + "part": 1 + }, + { + "color": -15132388, + "graphic": "Caldari.3_1", + "layer": 2, + "part": 1 + }, + { + "color": -596431, + "graphic": "Caldari.01_02", + "layer": 3, + "part": 1 + }, + { + "color": -1, + "graphic": "elements.21_1", + "layer": 0, + "part": 2 + }, + { + "color": -1, + "graphic": "elements.13_1", + "layer": 1, + "part": 2 + }, + { + "color": -1, + "graphic": "star.2_2", + "layer": 2, + "part": 2 + } + ], + "issuer_id": 341025466, + "medal_id": 44753, + "reason": "encore plus vieux", + "status": "public", + "title": "Médaille des 2 ans de services" + }, + { + "corporation_id": 144275616, + "date": "2011-07-10T22:44:43Z", + "description": "Décoration attribuée pour services rendus durant la guerre qui nous opposa aux gentlemens durant les premiers jours de juillets.
Surcouf en son temps résuma très bien ce genre de combats entre les français et les anglais:
Alors que Surcouf (corsaire français) avait capturé un navire anglais, son capitaine, attaché sur son propre navire s'addresse à lui en ces termes: \"Vous les français, vous vous battez pour l'argent, tandis que nous, anglais, nous nous battons pour l'honneur\". Ce à quoi Surcouf, dans un anglais parfait, répondit \"Nous nous battons toujours pour ce que nous n'avons pas...\"

", + "graphics": [ + { + "color": -1, + "graphic": "Caldari.1_1", + "layer": 0, + "part": 1 + }, + { + "color": -8847360, + "graphic": "Caldari.2_4", + "layer": 1, + "part": 1 + }, + { + "color": -4254186, + "graphic": "Caldari.2_1", + "layer": 2, + "part": 1 + }, + { + "color": -15191726, + "graphic": "Caldari.3_1", + "layer": 3, + "part": 1 + }, + { + "color": -330271, + "graphic": "Caldari.1_2", + "layer": 4, + "part": 1 + }, + { + "color": -1, + "graphic": "elements.24_2", + "layer": 0, + "part": 2 + }, + { + "color": -1, + "graphic": "elements.13_2", + "layer": 1, + "part": 2 + }, + { + "color": -1, + "graphic": "elements.17_2", + "layer": 2, + "part": 2 + }, + { + "color": -1, + "graphic": "star.3_2", + "layer": 3, + "part": 2 + } + ], + "issuer_id": 412492115, + "medal_id": 71835, + "reason": "Pour un scoot redoutable et une présence incroyable", + "status": "public", + "title": "Médaille du gentlemen" + } +] \ No newline at end of file diff --git a/tests/artifacts/characters/notifications.json b/tests/artifacts/characters/notifications.json new file mode 100644 index 00000000..2d73e0cf --- /dev/null +++ b/tests/artifacts/characters/notifications.json @@ -0,0 +1,20 @@ +[ + { + "is_read": true, + "notification_id": 1, + "sender_id": 1000132, + "sender_type": "corporation", + "text": "amount: 3731016.4000000004\nitemID: 1024881021663\npayout: 1\n", + "timestamp": "2017-08-16T10:08:00Z", + "type": "InsurancePayoutMsg" + }, + { + "is_read": true, + "notification_id": 809110712, + "sender_id": 1000137, + "sender_type": "corporation", + "text": "charID: 1636344400\nlistOfTypesAndQty:\n- - 1\n - 3297\nsolarsystemID: 30004787\nstructureID: &id001 1022892578773\nstructureShowInfoData:\n- showinfo\n- 35827\n- *id001\nstructureTypeID: 35827\n", + "timestamp": "2018-04-27T18:39:00Z", + "type": "StructureItemsDelivered" + } +] \ No newline at end of file diff --git a/tests/artifacts/characters/roles.json b/tests/artifacts/characters/roles.json new file mode 100644 index 00000000..3444ce1f --- /dev/null +++ b/tests/artifacts/characters/roles.json @@ -0,0 +1,15 @@ +{ + "roles": [ + "Director", + "Station_Manager" + ], + "roles_at_base": [], + "roles_at_hq": [ + "Hangar_Query_3", + "Hangar_Query_5" + ], + "roles_at_other": [ + "Hangar_Query_5", + "Hangar_Take_5" + ] +} \ No newline at end of file diff --git a/tests/database/migrations/2021_03_20_105237_create_character_corporation_histories_table.php b/tests/database/migrations/2021_03_20_105237_create_character_corporation_histories_table.php new file mode 100644 index 00000000..0da39db2 --- /dev/null +++ b/tests/database/migrations/2021_03_20_105237_create_character_corporation_histories_table.php @@ -0,0 +1,66 @@ +bigIncrements('id'); + $table->bigInteger('character_id'); + $table->dateTime('start_date'); + $table->bigInteger('corporation_id'); + $table->boolean('is_deleted'); + $table->integer('record_id'); + + $table->index(['character_id']); + $table->unique(['character_id', 'record_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_corporation_histories'); + } +} diff --git a/tests/database/migrations/2021_03_20_131213_create_character_fatigues_table.php b/tests/database/migrations/2021_03_20_131213_create_character_fatigues_table.php new file mode 100644 index 00000000..68d85d8d --- /dev/null +++ b/tests/database/migrations/2021_03_20_131213_create_character_fatigues_table.php @@ -0,0 +1,61 @@ +bigInteger('character_id')->primary(); + $table->dateTime('last_jump_date')->nullable(); + $table->dateTime('jump_fatigue_expire_date')->nullable(); + $table->dateTime('last_update_date')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_fatigues'); + } +} diff --git a/tests/database/migrations/2021_03_20_162022_create_character_medals_table.php b/tests/database/migrations/2021_03_20_162022_create_character_medals_table.php new file mode 100644 index 00000000..4d86d89d --- /dev/null +++ b/tests/database/migrations/2021_03_20_162022_create_character_medals_table.php @@ -0,0 +1,71 @@ +bigIncrements('id'); + $table->bigInteger('character_id'); + $table->integer('medal_id'); + $table->string('title'); + $table->text('description'); + $table->bigInteger('corporation_id'); + $table->bigInteger('issuer_id'); + $table->dateTime('date'); + $table->text('reason'); + $table->string('status'); + $table->json('graphics'); + + $table->index(['character_id']); + $table->index(['corporation_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_medals'); + } +} diff --git a/tests/database/migrations/2021_03_20_170438_create_character_notifications_table.php b/tests/database/migrations/2021_03_20_170438_create_character_notifications_table.php new file mode 100644 index 00000000..bb3995b8 --- /dev/null +++ b/tests/database/migrations/2021_03_20_170438_create_character_notifications_table.php @@ -0,0 +1,69 @@ +increments('id'); + $table->bigInteger('character_id'); + $table->bigInteger('notification_id'); + $table->string('type'); + $table->bigInteger('sender_id'); + $table->string('sender_type'); + $table->dateTime('timestamp'); + $table->boolean('is_read')->default(false); + $table->text('text')->nullable(); + + $table->index(['character_id']); + $table->index(['notification_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_notifications'); + } +} diff --git a/tests/database/migrations/2021_03_20_172715_create_character_roles_table.php b/tests/database/migrations/2021_03_20_172715_create_character_roles_table.php new file mode 100644 index 00000000..834ad550 --- /dev/null +++ b/tests/database/migrations/2021_03_20_172715_create_character_roles_table.php @@ -0,0 +1,64 @@ +bigIncrements('id'); + $table->bigInteger('character_id'); + $table->string('role'); + $table->string('scope'); + + $table->index(['character_id']); + $table->index(['role']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_roles'); + } +} From 3123bd0c7b613a0c5cbf6665251954584dd8016f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sat, 20 Mar 2021 18:15:03 +0100 Subject: [PATCH 10/42] refactor: remove unneeded constructor --- src/Commands/Esi/Meta/Ping.php | 11 ----------- src/Commands/Eve/Update/Sde.php | 10 ---------- src/Commands/Seat/Cache/Clear.php | 11 ----------- src/Commands/Seat/Tokens/Upgrade.php | 11 ----------- 4 files changed, 43 deletions(-) diff --git a/src/Commands/Esi/Meta/Ping.php b/src/Commands/Esi/Meta/Ping.php index c4fc0ebe..0870eb87 100644 --- a/src/Commands/Esi/Meta/Ping.php +++ b/src/Commands/Esi/Meta/Ping.php @@ -48,17 +48,6 @@ class Ping extends Command */ protected $description = 'Perform an ESI status check'; - /** - * Create a new command instance. - * - * @return void - */ - public function __construct() - { - - parent::__construct(); - } - /** * Execute the console command. * diff --git a/src/Commands/Eve/Update/Sde.php b/src/Commands/Eve/Update/Sde.php index bd9df17c..0aca0efa 100644 --- a/src/Commands/Eve/Update/Sde.php +++ b/src/Commands/Eve/Update/Sde.php @@ -78,16 +78,6 @@ class Sde extends Command */ protected $storage_path; - /** - * Create a new command instance. - */ - public function __construct() - { - - parent::__construct(); - - } - /** * Query the eveseat/resources repository for SDE * related information. diff --git a/src/Commands/Seat/Cache/Clear.php b/src/Commands/Seat/Cache/Clear.php index 3197752c..991f94ba 100644 --- a/src/Commands/Seat/Cache/Clear.php +++ b/src/Commands/Seat/Cache/Clear.php @@ -49,17 +49,6 @@ class Clear extends Command */ protected $description = 'Clear caches used by SeAT.'; - /** - * Create a new command instance. - * - * @return void - */ - public function __construct() - { - - parent::__construct(); - } - /** * Execute the console command. */ diff --git a/src/Commands/Seat/Tokens/Upgrade.php b/src/Commands/Seat/Tokens/Upgrade.php index 76ea22cc..3cb26546 100644 --- a/src/Commands/Seat/Tokens/Upgrade.php +++ b/src/Commands/Seat/Tokens/Upgrade.php @@ -48,17 +48,6 @@ class Upgrade extends Command */ protected $description = 'Upgrade all tokens to latest sso version'; - /** - * Create a new command instance. - * - * @return void - */ - public function __construct() - { - - parent::__construct(); - } - /** * Execute the console command. */ From b7cf9fb3168a8cbc2881b6fcdde558264f70320a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sat, 27 Mar 2021 10:47:11 +0100 Subject: [PATCH 11/42] test(jobs): add standing coverage --- src/Models/Character/CharacterStanding.php | 5 + tests/Jobs/Esi/Character/StandingsTest.php | 372 ++++++++++++++++++ .../Esi/Character/StandingResource.php | 45 +++ tests/artifacts/characters/standings.json | 17 + ...92159_create_character_standings_table.php | 65 +++ 5 files changed, 504 insertions(+) create mode 100644 tests/Jobs/Esi/Character/StandingsTest.php create mode 100644 tests/Resources/Esi/Character/StandingResource.php create mode 100644 tests/artifacts/characters/standings.json create mode 100644 tests/database/migrations/2021_03_21_192159_create_character_standings_table.php diff --git a/src/Models/Character/CharacterStanding.php b/src/Models/Character/CharacterStanding.php index 2cbeb044..a96e50c2 100644 --- a/src/Models/Character/CharacterStanding.php +++ b/src/Models/Character/CharacterStanding.php @@ -36,6 +36,11 @@ class CharacterStanding extends Model */ protected static $unguarded = true; + protected $casts = [ + 'from_id' => 'integer', + 'standing' => 'float', + ]; + /** * @return \Illuminate\Database\Eloquent\Relations\HasOne */ diff --git a/tests/Jobs/Esi/Character/StandingsTest.php b/tests/Jobs/Esi/Character/StandingsTest.php new file mode 100644 index 00000000..80353a8a --- /dev/null +++ b/tests/Jobs/Esi/Character/StandingsTest.php @@ -0,0 +1,372 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/characters/standings.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_standings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Standings($token); + $job->handle(); + + $standings = CharacterStanding::all(); + + $data = json_encode(StandingResource::collection($standings)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/standings.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_standings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterStanding::create([ + 'character_id' => 180548812, + 'from_id' => 3009841, + 'from_type' => 'agent', + 'standing' => 0.1, + ]); + CharacterStanding::create([ + 'character_id' => 180548812, + 'from_id' => 1000061, + 'from_type' => 'npc_corp', + 'standing' => 0, + ]); + CharacterStanding::create([ + 'character_id' => 180548812, + 'from_id' => 500003, + 'from_type' => 'faction', + 'standing' => -1, + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Standings($token); + $job->handle(); + + $standings = CharacterStanding::all(); + + foreach ($standings as $standing) + $this->assertEquals($standing->created_at, $standing->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/characters/180548812/standings/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_standings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterStanding::create([ + 'character_id' => 180548812, + 'from_id' => 3009841, + 'from_type' => 'agent', + 'standing' => -0.23, + ]); + CharacterStanding::create([ + 'character_id' => 180548812, + 'from_id' => 1000061, + 'from_type' => 'npc_corp', + 'standing' => 0.3, + ]); + + $standings = CharacterStanding::all(); + $data = json_encode(StandingResource::collection($standings)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/standings.json', $data); + + $job = new Standings($token); + $job->handle(); + + $standings = CharacterStanding::all(); + $data = json_encode(StandingResource::collection($standings)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/standings.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_standings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Standings($token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_standings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Standings($token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_standings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Standings($token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_standings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Standings($token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_standings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Standings($token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_standings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Standings($token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Standings($token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Character/StandingResource.php b/tests/Resources/Esi/Character/StandingResource.php new file mode 100644 index 00000000..748410f6 --- /dev/null +++ b/tests/Resources/Esi/Character/StandingResource.php @@ -0,0 +1,45 @@ + $this->from_id, + 'from_type' => $this->from_type, + 'standing' => $this->standing, + ]; + } +} diff --git a/tests/artifacts/characters/standings.json b/tests/artifacts/characters/standings.json new file mode 100644 index 00000000..46d22253 --- /dev/null +++ b/tests/artifacts/characters/standings.json @@ -0,0 +1,17 @@ +[ + { + "from_id": 3009841, + "from_type": "agent", + "standing": 0.1 + }, + { + "from_id": 1000061, + "from_type": "npc_corp", + "standing": 0 + }, + { + "from_id": 500003, + "from_type": "faction", + "standing": -1 + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_03_21_192159_create_character_standings_table.php b/tests/database/migrations/2021_03_21_192159_create_character_standings_table.php new file mode 100644 index 00000000..f04d6408 --- /dev/null +++ b/tests/database/migrations/2021_03_21_192159_create_character_standings_table.php @@ -0,0 +1,65 @@ +increments('id'); + $table->bigInteger('character_id'); + $table->integer('from_id'); + $table->enum('from_type', ['agent','npc_corp','faction']); + $table->double('standing'); + + $table->index(['character_id']); + $table->index(['from_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_standings'); + } +} From e47d66855ae682b0f1f99dc3662485472594c2c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sat, 27 Mar 2021 11:19:11 +0100 Subject: [PATCH 12/42] test(jobs): add character titles coverage --- src/Models/Corporation/CorporationTitle.php | 4 + tests/Jobs/Esi/Character/TitlesTest.php | 415 ++++++++++++++++++ .../Resources/Esi/Character/TitleResource.php | 44 ++ tests/artifacts/characters/titles.json | 14 + ...110506_create_corporation_titles_table.php | 65 +++ ...character_info_corporation_title_table.php | 61 +++ 6 files changed, 603 insertions(+) create mode 100644 tests/Jobs/Esi/Character/TitlesTest.php create mode 100644 tests/Resources/Esi/Character/TitleResource.php create mode 100644 tests/artifacts/characters/titles.json create mode 100644 tests/database/migrations/2021_03_27_110506_create_corporation_titles_table.php create mode 100644 tests/database/migrations/2021_03_27_110941_create_character_info_corporation_title_table.php diff --git a/src/Models/Corporation/CorporationTitle.php b/src/Models/Corporation/CorporationTitle.php index 83ef4e9e..e8d2b050 100644 --- a/src/Models/Corporation/CorporationTitle.php +++ b/src/Models/Corporation/CorporationTitle.php @@ -37,6 +37,10 @@ class CorporationTitle extends Model */ protected static $unguarded = true; + protected $casts = [ + 'title_id' => 'integer', + ]; + /** * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ diff --git a/tests/Jobs/Esi/Character/TitlesTest.php b/tests/Jobs/Esi/Character/TitlesTest.php new file mode 100644 index 00000000..92beb590 --- /dev/null +++ b/tests/Jobs/Esi/Character/TitlesTest.php @@ -0,0 +1,415 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/characters/titles.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_titles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $character = CharacterInfo::create([ + 'character_id' => 180548812, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + + $character->affiliation()->create([ + 'corporation_id' => 109299958, + ]); + + $job = new Titles($token); + $job->handle(); + + $titles = $character->titles; + + $data = json_encode(TitleResource::collection($titles)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/titles.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_titles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $character = CharacterInfo::create([ + 'character_id' => 180548812, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + + $character->affiliation()->create([ + 'corporation_id' => 109299958, + ]); + + $title = CorporationTitle::create([ + 'corporation_id' => 109299958, + 'title_id' => 1, + 'name' => 'Awesome Title', + ]); + $character->titles()->attach($title); + + $title = CorporationTitle::create([ + 'corporation_id' => 109299958, + 'title_id' => 2, + 'name' => 'Special Title', + ]); + $character->titles()->attach($title); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Titles($token); + $job->handle(); + + $titles = CharacterInfo::find(180548812)->titles; + + $this->assertEquals(2, $titles->count()); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/characters/180548812/titles/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_titles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $character = CharacterInfo::create([ + 'character_id' => 180548812, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + + $character->affiliation()->create([ + 'corporation_id' => 109299958, + ]); + + $title = CorporationTitle::create([ + 'corporation_id' => 109299958, + 'title_id' => 1, + 'name' => 'Awesome Title', + ]); + $character->titles()->attach($title); + + $title = CorporationTitle::create([ + 'corporation_id' => 109299958, + 'title_id' => 2, + 'name' => 'Special Title', + ]); + $character->titles()->attach($title); + + $titles = $character->titles; + $data = json_encode(TitleResource::collection($titles)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/titles.json', $data); + + $job = new Titles($token); + $job->handle(); + + $character->load('titles'); + + $titles = $character->titles; + $data = json_encode(TitleResource::collection($titles)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/titles.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_titles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Titles($token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_titles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Titles($token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_titles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Titles($token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_titles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Titles($token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_titles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Titles($token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_titles.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Titles($token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Titles($token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Character/TitleResource.php b/tests/Resources/Esi/Character/TitleResource.php new file mode 100644 index 00000000..63d20ce7 --- /dev/null +++ b/tests/Resources/Esi/Character/TitleResource.php @@ -0,0 +1,44 @@ + $this->name, + 'title_id' => $this->title_id, + ]; + } +} diff --git a/tests/artifacts/characters/titles.json b/tests/artifacts/characters/titles.json new file mode 100644 index 00000000..6c7a7471 --- /dev/null +++ b/tests/artifacts/characters/titles.json @@ -0,0 +1,14 @@ +[ + { + "name": "Awesome Title", + "title_id": 1 + }, + { + "name": "Special Title", + "title_id": 2 + }, + { + "name": "Secret Title", + "title_id": 10 + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_03_27_110506_create_corporation_titles_table.php b/tests/database/migrations/2021_03_27_110506_create_corporation_titles_table.php new file mode 100644 index 00000000..dd94bdec --- /dev/null +++ b/tests/database/migrations/2021_03_27_110506_create_corporation_titles_table.php @@ -0,0 +1,65 @@ +increments('id'); + $table->bigInteger('corporation_id'); + $table->integer('title_id'); + $table->string('name'); + + $table->unique(['corporation_id', 'title_id']); + $table->index(['corporation_id']); + $table->index(['title_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('corporation_titles'); + } +} diff --git a/tests/database/migrations/2021_03_27_110941_create_character_info_corporation_title_table.php b/tests/database/migrations/2021_03_27_110941_create_character_info_corporation_title_table.php new file mode 100644 index 00000000..8943f0d0 --- /dev/null +++ b/tests/database/migrations/2021_03_27_110941_create_character_info_corporation_title_table.php @@ -0,0 +1,61 @@ +bigInteger('character_info_character_id'); + $table->integer('corporation_title_id'); + + $table->unique(['character_info_character_id', 'corporation_title_id']); + $table->index(['character_info_character_id']); + $table->index(['corporation_title_id']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_info_corporation_title'); + } +} From f49da218f46f1518ec5d5fab6fb3336afc8f250f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sat, 27 Mar 2021 15:21:03 +0100 Subject: [PATCH 13/42] refactor: switch character artifact directory to singular --- src/Mapping/Corporations/InfoMapping.php | 1 + src/Models/Corporation/CorporationInfo.php | 12 ++++++++++++ tests/Jobs/Esi/Character/AffiliationTest.php | 8 ++++---- tests/Jobs/Esi/Character/AgentResearchTest.php | 10 +++++----- tests/Jobs/Esi/Character/BlueprintsTest.php | 10 +++++----- tests/Jobs/Esi/Character/CorporationHistoryTest.php | 4 ++-- tests/Jobs/Esi/Character/FatigueTest.php | 10 +++++----- tests/Jobs/Esi/Character/InfoTest.php | 10 +++++----- tests/Jobs/Esi/Character/MedalsTest.php | 10 +++++----- tests/Jobs/Esi/Character/NotificationsTest.php | 10 +++++----- tests/Jobs/Esi/Character/RolesTest.php | 10 +++++----- tests/Jobs/Esi/Character/StandingsTest.php | 10 +++++----- tests/Jobs/Esi/Character/TitlesTest.php | 10 +++++----- .../{characters => character}/affiliation.json | 0 .../{characters => character}/agents_research.json | 0 .../{characters => character}/blueprints.json | 0 .../corporation_history.json | 0 .../artifacts/{characters => character}/fatigue.json | 0 tests/artifacts/{characters => character}/info.json | 0 .../artifacts/{characters => character}/medals.json | 0 .../{characters => character}/notifications.json | 0 tests/artifacts/{characters => character}/roles.json | 0 .../{characters => character}/standings.json | 0 .../artifacts/{characters => character}/titles.json | 0 24 files changed, 64 insertions(+), 51 deletions(-) rename tests/artifacts/{characters => character}/affiliation.json (100%) rename tests/artifacts/{characters => character}/agents_research.json (100%) rename tests/artifacts/{characters => character}/blueprints.json (100%) rename tests/artifacts/{characters => character}/corporation_history.json (100%) rename tests/artifacts/{characters => character}/fatigue.json (100%) rename tests/artifacts/{characters => character}/info.json (100%) rename tests/artifacts/{characters => character}/medals.json (100%) rename tests/artifacts/{characters => character}/notifications.json (100%) rename tests/artifacts/{characters => character}/roles.json (100%) rename tests/artifacts/{characters => character}/standings.json (100%) rename tests/artifacts/{characters => character}/titles.json (100%) diff --git a/src/Mapping/Corporations/InfoMapping.php b/src/Mapping/Corporations/InfoMapping.php index ba719dd0..8490f21b 100644 --- a/src/Mapping/Corporations/InfoMapping.php +++ b/src/Mapping/Corporations/InfoMapping.php @@ -47,5 +47,6 @@ class InfoMapping extends DataMapping 'faction_id' => 'faction_id', 'home_station_id' => 'home_station_id', 'shares' => 'shares', + 'war_eligible' => 'war_eligible', ]; } diff --git a/src/Models/Corporation/CorporationInfo.php b/src/Models/Corporation/CorporationInfo.php index e3f14e66..f2f1c6e6 100644 --- a/src/Models/Corporation/CorporationInfo.php +++ b/src/Models/Corporation/CorporationInfo.php @@ -149,6 +149,18 @@ class CorporationInfo extends Model */ protected $primaryKey = 'corporation_id'; + /** + * @var string[] + */ + protected $casts = [ + 'alliance_id' => 'integer', + 'ceo_id' => 'integer', + 'creator_id' => 'integer', + 'member_count' => 'integer', + 'tax_rate' => 'float', + 'war_eligible' => 'boolean', + ]; + /** * @param $value */ diff --git a/tests/Jobs/Esi/Character/AffiliationTest.php b/tests/Jobs/Esi/Character/AffiliationTest.php index b92d8a20..b46dd4ef 100644 --- a/tests/Jobs/Esi/Character/AffiliationTest.php +++ b/tests/Jobs/Esi/Character/AffiliationTest.php @@ -44,7 +44,7 @@ public static function setUpBeforeClass(): void // prepare dummy responses $response_success = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/affiliation.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/affiliation.json'), [ 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), ], @@ -76,7 +76,7 @@ public function testHandleSuccess() $affiliation = CharacterAffiliation::all(); $data = json_encode(AffiliationResource::collection($affiliation)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/affiliation.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/affiliation.json', $data); } /** @@ -91,7 +91,7 @@ public function testHandleUpdated() $affiliation->save(); $data = json_encode($affiliation); - $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/affiliation.json', $data); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/character/affiliation.json', $data); $job = new Affiliation([90795931]); $job->handle(); @@ -99,7 +99,7 @@ public function testHandleUpdated() $affiliation = CharacterAffiliation::all(); $data = json_encode(AffiliationResource::collection($affiliation)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/affiliation.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/affiliation.json', $data); } /** diff --git a/tests/Jobs/Esi/Character/AgentResearchTest.php b/tests/Jobs/Esi/Character/AgentResearchTest.php index c959aecf..0a0b95bd 100644 --- a/tests/Jobs/Esi/Character/AgentResearchTest.php +++ b/tests/Jobs/Esi/Character/AgentResearchTest.php @@ -48,7 +48,7 @@ public static function setUpBeforeClass(): void // prepare dummy responses $response_success = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/agents_research.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/agents_research.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -68,7 +68,7 @@ public static function setUpBeforeClass(): void ); $response_success_bis = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/agents_research.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/agents_research.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -116,7 +116,7 @@ public function testHandleSuccess() $agents = CharacterAgentResearch::all(); $data = json_encode(AgentsResearchResource::collection($agents)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/agents_research.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/agents_research.json', $data); } /** @@ -220,14 +220,14 @@ public function testHandleUpdated() $agents = CharacterAgentResearch::all(); $data = json_encode(AgentsResearchResource::collection($agents)); - $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/agents_research.json', $data); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/character/agents_research.json', $data); $job = new AgentsResearch($token); $job->handle(); $agents = CharacterAgentResearch::all(); $data = json_encode(AgentsResearchResource::collection($agents)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/agents_research.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/agents_research.json', $data); } /** diff --git a/tests/Jobs/Esi/Character/BlueprintsTest.php b/tests/Jobs/Esi/Character/BlueprintsTest.php index 406d6ca3..9305a566 100644 --- a/tests/Jobs/Esi/Character/BlueprintsTest.php +++ b/tests/Jobs/Esi/Character/BlueprintsTest.php @@ -48,7 +48,7 @@ public static function setUpBeforeClass(): void // prepare dummy responses $response_success = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/blueprints.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/blueprints.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -69,7 +69,7 @@ public static function setUpBeforeClass(): void ); $response_success_bis = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/blueprints.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/blueprints.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -118,7 +118,7 @@ public function testHandleSuccess() $blueprints = CharacterBlueprint::all(); $data = json_encode(BlueprintResource::collection($blueprints)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/blueprints.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/blueprints.json', $data); } /** @@ -196,14 +196,14 @@ public function testHandleUpdated() $blueprints = CharacterBlueprint::all(); $data = json_encode(BlueprintResource::collection($blueprints)); - $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/blueprints.json', $data); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/character/blueprints.json', $data); $job = new Blueprints($token); $job->handle(); $blueprints = CharacterBlueprint::all(); $data = json_encode(BlueprintResource::collection($blueprints)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/blueprints.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/blueprints.json', $data); } /** diff --git a/tests/Jobs/Esi/Character/CorporationHistoryTest.php b/tests/Jobs/Esi/Character/CorporationHistoryTest.php index 61508e4f..60146578 100644 --- a/tests/Jobs/Esi/Character/CorporationHistoryTest.php +++ b/tests/Jobs/Esi/Character/CorporationHistoryTest.php @@ -44,7 +44,7 @@ public static function setUpBeforeClass(): void // prepare dummy responses $response_success = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/corporation_history.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/corporation_history.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -87,7 +87,7 @@ public function testHandleSuccess() $corporations = CharacterCorporationHistory::all(); $data = json_encode(CorporationHistoryResource::collection($corporations)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/corporation_history.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/corporation_history.json', $data); } /** diff --git a/tests/Jobs/Esi/Character/FatigueTest.php b/tests/Jobs/Esi/Character/FatigueTest.php index 60b4bf21..fd3ad4aa 100644 --- a/tests/Jobs/Esi/Character/FatigueTest.php +++ b/tests/Jobs/Esi/Character/FatigueTest.php @@ -48,7 +48,7 @@ public static function setUpBeforeClass(): void // prepare dummy responses $response_success = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/fatigue.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/fatigue.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -68,7 +68,7 @@ public static function setUpBeforeClass(): void ); $response_success_bis = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/fatigue.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/fatigue.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -116,7 +116,7 @@ public function testHandleSuccess() $fatigue = CharacterFatigue::find(180548812); $data = json_encode(new FatigueResource($fatigue)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/fatigue.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/fatigue.json', $data); } /** @@ -184,7 +184,7 @@ public function testHandleUpdated() $fatigue->save(); $data = json_encode(new FatigueResource($fatigue)); - $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/fatigue.json', $data); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/character/fatigue.json', $data); $job = new Fatigue($token); $job->handle(); @@ -192,7 +192,7 @@ public function testHandleUpdated() $fatigue = CharacterFatigue::find(180548812); $data = json_encode(new FatigueResource($fatigue)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/fatigue.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/fatigue.json', $data); } /** diff --git a/tests/Jobs/Esi/Character/InfoTest.php b/tests/Jobs/Esi/Character/InfoTest.php index d5dfc488..c06152c8 100644 --- a/tests/Jobs/Esi/Character/InfoTest.php +++ b/tests/Jobs/Esi/Character/InfoTest.php @@ -45,7 +45,7 @@ public static function setUpBeforeClass(): void // prepare dummy responses $response_success = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/info.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/info.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -65,7 +65,7 @@ public static function setUpBeforeClass(): void ); $response_success_bis = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/info.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/info.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -102,7 +102,7 @@ public function testHandleSuccess() $character->corporation_id = 109299958; $data = json_encode(new InfoResource($character)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/info.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/info.json', $data); } /** @@ -154,7 +154,7 @@ public function testHandleUpdated() $character->save(); $data = json_encode(new InfoResource($character)); - $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/info.json', $data); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/character/info.json', $data); $job = new Info(180548812); $job->handle(); @@ -165,7 +165,7 @@ public function testHandleUpdated() $character->corporation_id = 109299958; $data = json_encode(new InfoResource($character)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/info.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/info.json', $data); } /** diff --git a/tests/Jobs/Esi/Character/MedalsTest.php b/tests/Jobs/Esi/Character/MedalsTest.php index f3507269..d36eb1e3 100644 --- a/tests/Jobs/Esi/Character/MedalsTest.php +++ b/tests/Jobs/Esi/Character/MedalsTest.php @@ -48,7 +48,7 @@ public static function setUpBeforeClass(): void // prepare dummy responses $response_success = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/medals.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/medals.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -68,7 +68,7 @@ public static function setUpBeforeClass(): void ); $response_success_bis = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/medals.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/medals.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -116,7 +116,7 @@ public function testHandleSuccess() $medals = CharacterMedal::all(); $data = json_encode(MedalResource::collection($medals)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/medals.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/medals.json', $data); } /** @@ -248,14 +248,14 @@ public function testHandleUpdated() $medals = CharacterMedal::all(); $data = json_encode(MedalResource::collection($medals)); - $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/medals.json', $data); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/character/medals.json', $data); $job = new Medals($token); $job->handle(); $medals = CharacterMedal::all(); $data = json_encode(MedalResource::collection($medals)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/medals.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/medals.json', $data); } /** diff --git a/tests/Jobs/Esi/Character/NotificationsTest.php b/tests/Jobs/Esi/Character/NotificationsTest.php index fd34a8a9..c838904f 100644 --- a/tests/Jobs/Esi/Character/NotificationsTest.php +++ b/tests/Jobs/Esi/Character/NotificationsTest.php @@ -48,7 +48,7 @@ public static function setUpBeforeClass(): void // prepare dummy responses $response_success = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/notifications.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/notifications.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -68,7 +68,7 @@ public static function setUpBeforeClass(): void ); $response_success_bis = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/notifications.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/notifications.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -116,7 +116,7 @@ public function testHandleSuccess() $notifications = CharacterNotification::all(); $data = json_encode(NotificationResource::collection($notifications)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/notifications.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/notifications.json', $data); } /** @@ -210,14 +210,14 @@ public function testHandleUpdated() $notifications = CharacterNotification::all(); $data = json_encode(NotificationResource::collection($notifications)); - $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/notifications.json', $data); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/character/notifications.json', $data); $job = new Notifications($token); $job->handle(); $notifications = CharacterNotification::all(); $data = json_encode(NotificationResource::collection($notifications)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/notifications.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/notifications.json', $data); } /** diff --git a/tests/Jobs/Esi/Character/RolesTest.php b/tests/Jobs/Esi/Character/RolesTest.php index 3ecba998..2c890550 100644 --- a/tests/Jobs/Esi/Character/RolesTest.php +++ b/tests/Jobs/Esi/Character/RolesTest.php @@ -49,7 +49,7 @@ public static function setUpBeforeClass(): void // prepare dummy responses $response_success = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/roles.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/roles.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -69,7 +69,7 @@ public static function setUpBeforeClass(): void ); $response_success_bis = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/roles.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/roles.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -126,7 +126,7 @@ public function testHandleSuccess() $job->handle(); $data = json_encode(RoleResource::make($character)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/roles.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/roles.json', $data); } /** @@ -274,7 +274,7 @@ public function testHandleUpdated() ]); $data = json_encode(RoleResource::make($character)); - $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/roles.json', $data); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/character/roles.json', $data); $job = new Roles($token); $job->handle(); @@ -282,7 +282,7 @@ public function testHandleUpdated() $character->load('corporation_roles'); $data = json_encode(RoleResource::make($character)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/roles.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/roles.json', $data); } /** diff --git a/tests/Jobs/Esi/Character/StandingsTest.php b/tests/Jobs/Esi/Character/StandingsTest.php index 80353a8a..3b227d0c 100644 --- a/tests/Jobs/Esi/Character/StandingsTest.php +++ b/tests/Jobs/Esi/Character/StandingsTest.php @@ -48,7 +48,7 @@ public static function setUpBeforeClass(): void // prepare dummy responses $response_success = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/standings.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/standings.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -68,7 +68,7 @@ public static function setUpBeforeClass(): void ); $response_success_bis = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/standings.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/standings.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -116,7 +116,7 @@ public function testHandleSuccess() $standings = CharacterStanding::all(); $data = json_encode(StandingResource::collection($standings)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/standings.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/standings.json', $data); } /** @@ -202,14 +202,14 @@ public function testHandleUpdated() $standings = CharacterStanding::all(); $data = json_encode(StandingResource::collection($standings)); - $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/standings.json', $data); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/character/standings.json', $data); $job = new Standings($token); $job->handle(); $standings = CharacterStanding::all(); $data = json_encode(StandingResource::collection($standings)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/standings.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/standings.json', $data); } /** diff --git a/tests/Jobs/Esi/Character/TitlesTest.php b/tests/Jobs/Esi/Character/TitlesTest.php index 92beb590..8ebe2457 100644 --- a/tests/Jobs/Esi/Character/TitlesTest.php +++ b/tests/Jobs/Esi/Character/TitlesTest.php @@ -49,7 +49,7 @@ public static function setUpBeforeClass(): void // prepare dummy responses $response_success = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/titles.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/titles.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -69,7 +69,7 @@ public static function setUpBeforeClass(): void ); $response_success_bis = new EsiResponse( - file_get_contents(__DIR__ . '/../../../artifacts/characters/titles.json'), + file_get_contents(__DIR__ . '/../../../artifacts/character/titles.json'), [ 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), @@ -132,7 +132,7 @@ public function testHandleSuccess() $titles = $character->titles; $data = json_encode(TitleResource::collection($titles)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/titles.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/titles.json', $data); } /** @@ -243,7 +243,7 @@ public function testHandleUpdated() $titles = $character->titles; $data = json_encode(TitleResource::collection($titles)); - $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/titles.json', $data); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/character/titles.json', $data); $job = new Titles($token); $job->handle(); @@ -252,7 +252,7 @@ public function testHandleUpdated() $titles = $character->titles; $data = json_encode(TitleResource::collection($titles)); - $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/characters/titles.json', $data); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/character/titles.json', $data); } /** diff --git a/tests/artifacts/characters/affiliation.json b/tests/artifacts/character/affiliation.json similarity index 100% rename from tests/artifacts/characters/affiliation.json rename to tests/artifacts/character/affiliation.json diff --git a/tests/artifacts/characters/agents_research.json b/tests/artifacts/character/agents_research.json similarity index 100% rename from tests/artifacts/characters/agents_research.json rename to tests/artifacts/character/agents_research.json diff --git a/tests/artifacts/characters/blueprints.json b/tests/artifacts/character/blueprints.json similarity index 100% rename from tests/artifacts/characters/blueprints.json rename to tests/artifacts/character/blueprints.json diff --git a/tests/artifacts/characters/corporation_history.json b/tests/artifacts/character/corporation_history.json similarity index 100% rename from tests/artifacts/characters/corporation_history.json rename to tests/artifacts/character/corporation_history.json diff --git a/tests/artifacts/characters/fatigue.json b/tests/artifacts/character/fatigue.json similarity index 100% rename from tests/artifacts/characters/fatigue.json rename to tests/artifacts/character/fatigue.json diff --git a/tests/artifacts/characters/info.json b/tests/artifacts/character/info.json similarity index 100% rename from tests/artifacts/characters/info.json rename to tests/artifacts/character/info.json diff --git a/tests/artifacts/characters/medals.json b/tests/artifacts/character/medals.json similarity index 100% rename from tests/artifacts/characters/medals.json rename to tests/artifacts/character/medals.json diff --git a/tests/artifacts/characters/notifications.json b/tests/artifacts/character/notifications.json similarity index 100% rename from tests/artifacts/characters/notifications.json rename to tests/artifacts/character/notifications.json diff --git a/tests/artifacts/characters/roles.json b/tests/artifacts/character/roles.json similarity index 100% rename from tests/artifacts/characters/roles.json rename to tests/artifacts/character/roles.json diff --git a/tests/artifacts/characters/standings.json b/tests/artifacts/character/standings.json similarity index 100% rename from tests/artifacts/characters/standings.json rename to tests/artifacts/character/standings.json diff --git a/tests/artifacts/characters/titles.json b/tests/artifacts/character/titles.json similarity index 100% rename from tests/artifacts/characters/titles.json rename to tests/artifacts/character/titles.json From 9387e7960b2f48bbfc79c2ccff7bf430560f275f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sat, 27 Mar 2021 15:21:24 +0100 Subject: [PATCH 14/42] test(jobs): add corporation info coverage --- ...ar_eligible_to_corporation_infos_table.php | 55 +++++ tests/Jobs/Esi/Corporation/InfoTest.php | 233 ++++++++++++++++++ .../Esi/Corporation/InfoResource.php | 55 +++++ tests/artifacts/corporation/info.json | 12 + ...7_132618_create_corporation_info_table.php | 79 ++++++ 5 files changed, 434 insertions(+) create mode 100644 src/database/migrations/2021_03_27_151339_add_war_eligible_to_corporation_infos_table.php create mode 100644 tests/Jobs/Esi/Corporation/InfoTest.php create mode 100644 tests/Resources/Esi/Corporation/InfoResource.php create mode 100644 tests/artifacts/corporation/info.json create mode 100644 tests/database/migrations/2021_03_27_132618_create_corporation_info_table.php diff --git a/src/database/migrations/2021_03_27_151339_add_war_eligible_to_corporation_infos_table.php b/src/database/migrations/2021_03_27_151339_add_war_eligible_to_corporation_infos_table.php new file mode 100644 index 00000000..b26a43c2 --- /dev/null +++ b/src/database/migrations/2021_03_27_151339_add_war_eligible_to_corporation_infos_table.php @@ -0,0 +1,55 @@ +boolean('war_eligible')->nullable()->after('url'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('corporation_infos', function (Blueprint $table) { + $table->dropColumn('war_eligible'); + }); + } +} diff --git a/tests/Jobs/Esi/Corporation/InfoTest.php b/tests/Jobs/Esi/Corporation/InfoTest.php new file mode 100644 index 00000000..1d2f6f6e --- /dev/null +++ b/tests/Jobs/Esi/Corporation/InfoTest.php @@ -0,0 +1,233 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/corporation/info.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $job = new Info(109299958); + $job->handle(); + + $character = CorporationInfo::find(109299958); + + $data = json_encode(new InfoResource($character)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/info.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $character = new CorporationInfo([ + 'corporation_id' => 109299958, + 'alliance_id' => 434243723, + 'ceo_id' => 180548812, + 'creator_id' => 180548812, + 'date_founded' => '2020-03-27T13:23:59Z', + 'description' => 'Lorem Ipsum Dolor Est', + 'faction_id' => 100006, + 'home_station_id' => 646541246, + 'member_count' => 3, + 'name' => 'Corporation Name', + 'shares' => 123, + 'tax_rate' => 3.1, + 'ticker' => 'SeAT', + 'url' => 'https://github.com/eveseat/seat/', + 'war_eligible' => true, + ]); + $character->save(); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Info(109299958); + $job->handle(); + + $character = CorporationInfo::find(109299958); + + $this->assertEquals($character->created_at, $character->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v4/corporations/109299958/', 'datasource=tranquility'); + + $character = new CorporationInfo([ + 'corporation_id' => 109299958, + 'alliance_id' => 434243723, + 'ceo_id' => 180548812, + 'creator_id' => 180548812, + 'date_founded' => '2020-03-27T13:23:59Z', + 'description' => 'Lorem Ipsum Dolor Est', + 'faction_id' => 100006, + 'home_station_id' => 646541246, + 'member_count' => 3, + 'name' => 'Corporation Name', + 'shares' => 123, + 'tax_rate' => 3.1, + 'ticker' => 'SeAT', + 'url' => 'https://github.com/eveseat/seat/', + 'war_eligible' => true, + ]); + $character->save(); + + $data = json_encode(new InfoResource($character)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/info.json', $data); + + $job = new Info(109299958); + $job->handle(); + + $character = CorporationInfo::find(109299958); + + $data = json_encode(new InfoResource($character)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/info.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $job = new Info(404); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $job = new Info(420); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $job = new Info(500); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $job = new Info(503); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $job = new Info(504); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Corporation/InfoResource.php b/tests/Resources/Esi/Corporation/InfoResource.php new file mode 100644 index 00000000..76660b0a --- /dev/null +++ b/tests/Resources/Esi/Corporation/InfoResource.php @@ -0,0 +1,55 @@ + $this->when(! is_null($this->alliance_id), $this->alliance_id), + 'ceo_id' => $this->ceo_id, + 'creator_id' => $this->creator_id, + 'date_founded' => $this->when(! is_null($this->date_founded), carbon($this->date_founded)->toIso8601ZuluString()), + 'description' => $this->when(! is_null($this->description), $this->description), + 'faction_id' => $this->when(! is_null($this->faction_id), $this->faction_id), + 'home_station_id' => $this->when(! is_null($this->home_station_id), $this->home_station_id), + 'member_count' => $this->member_count, + 'name' => $this->name, + 'shares' => $this->when(! is_null($this->shares), $this->shares), + 'tax_rate' => $this->tax_rate, + 'ticker' => $this->ticker, + 'url' => $this->when(! is_null($this->url), $this->url), + 'war_eligible' => $this->when($this->war_eligible, $this->war_eligible), + ]; + } +} diff --git a/tests/artifacts/corporation/info.json b/tests/artifacts/corporation/info.json new file mode 100644 index 00000000..a50d732a --- /dev/null +++ b/tests/artifacts/corporation/info.json @@ -0,0 +1,12 @@ +{ + "alliance_id": 434243723, + "ceo_id": 180548812, + "creator_id": 180548812, + "date_founded": "2004-11-28T16:42:51Z", + "description": "This is a corporation description, it's basically just a string", + "member_count": 656, + "name": "C C P", + "tax_rate": 0.256, + "ticker": "-CCP-", + "url": "http://www.eveonline.com" +} \ No newline at end of file diff --git a/tests/database/migrations/2021_03_27_132618_create_corporation_info_table.php b/tests/database/migrations/2021_03_27_132618_create_corporation_info_table.php new file mode 100644 index 00000000..fe8ce8dc --- /dev/null +++ b/tests/database/migrations/2021_03_27_132618_create_corporation_info_table.php @@ -0,0 +1,79 @@ +bigInteger('corporation_id')->primary(); + $table->string('name'); + $table->string('ticker'); + $table->integer('member_count'); + $table->bigInteger('ceo_id'); + $table->integer('alliance_id')->nullable(); + $table->text('description')->nullable(); + $table->float('tax_rate'); + $table->dateTime('date_founded')->nullable(); + $table->bigInteger('creator_id'); + $table->string('url')->nullable(); + $table->boolean('war_eligible')->nullable(); + $table->integer('faction_id')->nullable(); + $table->integer('home_station_id')->nullable(); + $table->bigInteger('shares')->nullable(); + + $table->index(['ticker']); + $table->index(['ceo_id']); + $table->index(['alliance_id']); + $table->index(['creator_id']); + $table->index(['faction_id']); + $table->index(['home_station_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('corporation_infos'); + } +} From 4ee6ccb4f5f3f5e1706a07712de12b62f4020686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sat, 27 Mar 2021 15:47:00 +0100 Subject: [PATCH 15/42] test(jobs): add corporation alliance history coverage --- .../CorporationAllianceHistory.php | 7 +- .../Esi/Corporation/AllianceHistoryTest.php | 226 ++++++++++++++++++ .../Corporation/AllianceHistoryResource.php | 43 ++++ .../corporation/alliance_history.json | 12 + ...e_corporation_alliance_histories_table.php | 65 +++++ 5 files changed, 352 insertions(+), 1 deletion(-) create mode 100644 tests/Jobs/Esi/Corporation/AllianceHistoryTest.php create mode 100644 tests/Resources/Esi/Corporation/AllianceHistoryResource.php create mode 100644 tests/artifacts/corporation/alliance_history.json create mode 100644 tests/database/migrations/2021_03_27_153951_create_corporation_alliance_histories_table.php diff --git a/src/Models/Corporation/CorporationAllianceHistory.php b/src/Models/Corporation/CorporationAllianceHistory.php index c35b13a3..ec54f6d2 100644 --- a/src/Models/Corporation/CorporationAllianceHistory.php +++ b/src/Models/Corporation/CorporationAllianceHistory.php @@ -38,9 +38,14 @@ class CorporationAllianceHistory extends Model */ protected static $unguarded = true; + protected $casts = [ + 'alliance_id' => 'integer', + 'is_deleted' => 'boolean', + 'record_id' => 'integer', + ]; + /** * @var array */ protected $primaryKey = ['corporation_id', 'record_id']; - } diff --git a/tests/Jobs/Esi/Corporation/AllianceHistoryTest.php b/tests/Jobs/Esi/Corporation/AllianceHistoryTest.php new file mode 100644 index 00000000..56f07df8 --- /dev/null +++ b/tests/Jobs/Esi/Corporation/AllianceHistoryTest.php @@ -0,0 +1,226 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/corporation/alliance_history.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $job = new AllianceHistory(109299958); + $job->handle(); + + $alliance_history = CorporationAllianceHistory::all(); + + $data = json_encode(AllianceHistoryResource::collection($alliance_history)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/alliance_history.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + CorporationAllianceHistory::create([ + 'corporation_id' => 109299958, + 'alliance_id' => 99000006, + 'is_deleted' => false, + 'record_id' => 23, + 'start_date' => '2016-10-25T14:46:00Z', + ]); + + CorporationAllianceHistory::create([ + 'corporation_id' => 109299958, + 'record_id' => 1, + 'start_date' => '2015-07-06T20:00:00Z', + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new AllianceHistory(109299958); + $job->handle(); + + $alliances_history = CorporationAllianceHistory::all(); + + foreach ($alliances_history as $alliance_history) + $this->assertEquals($alliance_history->created_at, $alliance_history->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v2/corporations/109299958/alliancehistory/', 'datasource=tranquility'); + + CorporationAllianceHistory::create([ + 'corporation_id' => 109299958, + 'alliance_id' => 99000006, + 'is_deleted' => false, + 'record_id' => 23, + 'start_date' => '2016-10-25T14:46:00Z', + ]); + + CorporationAllianceHistory::create([ + 'corporation_id' => 109299958, + 'record_id' => 1, + 'start_date' => '2015-07-06T20:00:00Z', + ]); + + $alliances_history = CorporationAllianceHistory::all(); + + $data = json_encode(AllianceHistoryResource::collection($alliances_history)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/alliance_history.json', $data); + + $job = new AllianceHistory(109299958); + $job->handle(); + + $alliances_history = CorporationAllianceHistory::all(); + + $data = json_encode(AllianceHistoryResource::collection($alliances_history)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/alliance_history.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $job = new AllianceHistory(404); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $job = new AllianceHistory(420); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $job = new AllianceHistory(500); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $job = new AllianceHistory(503); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $job = new AllianceHistory(504); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Corporation/AllianceHistoryResource.php b/tests/Resources/Esi/Corporation/AllianceHistoryResource.php new file mode 100644 index 00000000..454414a2 --- /dev/null +++ b/tests/Resources/Esi/Corporation/AllianceHistoryResource.php @@ -0,0 +1,43 @@ + $this->when(! is_null($this->alliance_id), $this->alliance_id), + 'is_deleted' => $this->when($this->is_deleted, $this->is_deleted), + 'record_id' => $this->record_id, + 'start_date' => carbon($this->start_date)->toIso8601ZuluString(), + ]; + } +} diff --git a/tests/artifacts/corporation/alliance_history.json b/tests/artifacts/corporation/alliance_history.json new file mode 100644 index 00000000..c00ea435 --- /dev/null +++ b/tests/artifacts/corporation/alliance_history.json @@ -0,0 +1,12 @@ +[ + { + "alliance_id": 99000006, + "is_deleted": true, + "record_id": 23, + "start_date": "2016-10-25T14:46:00Z" + }, + { + "record_id": 1, + "start_date": "2015-07-06T20:56:00Z" + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_03_27_153951_create_corporation_alliance_histories_table.php b/tests/database/migrations/2021_03_27_153951_create_corporation_alliance_histories_table.php new file mode 100644 index 00000000..52578835 --- /dev/null +++ b/tests/database/migrations/2021_03_27_153951_create_corporation_alliance_histories_table.php @@ -0,0 +1,65 @@ +bigInteger('corporation_id'); + $table->integer('record_id'); + $table->dateTime('start_date'); + $table->integer('alliance_id')->nullable(); + $table->boolean('is_deleted')->nullable(); + + $table->primary(['corporation_id', 'record_id']); + $table->index(['corporation_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('corporation_alliance_histories'); + } +} From 4b3e1ec8e31fbe35f60660f3bb6dd3460022bdb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sat, 27 Mar 2021 16:00:58 +0100 Subject: [PATCH 16/42] test(jobs): add corporation blueprints coverage --- .../Corporation/CorporationBlueprint.php | 13 + tests/Jobs/Esi/Corporation/BlueprintsTest.php | 366 ++++++++++++++++++ .../Esi/Corporation/BlueprintResource.php | 49 +++ tests/artifacts/corporation/blueprints.json | 12 + ...04_create_corporation_blueprints_table.php | 72 ++++ 5 files changed, 512 insertions(+) create mode 100644 tests/Jobs/Esi/Corporation/BlueprintsTest.php create mode 100644 tests/Resources/Esi/Corporation/BlueprintResource.php create mode 100644 tests/artifacts/corporation/blueprints.json create mode 100644 tests/database/migrations/2021_03_27_155504_create_corporation_blueprints_table.php diff --git a/src/Models/Corporation/CorporationBlueprint.php b/src/Models/Corporation/CorporationBlueprint.php index 4e5d2d1d..c867d398 100644 --- a/src/Models/Corporation/CorporationBlueprint.php +++ b/src/Models/Corporation/CorporationBlueprint.php @@ -44,6 +44,19 @@ class CorporationBlueprint extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'item_id' => 'integer', + 'location_id' => 'integer', + 'material_efficiency' => 'integer', + 'quantity' => 'integer', + 'runs' => 'integer', + 'time_efficiency' => 'integer', + 'type_id' => 'integer', + ]; + /** * @var array */ diff --git a/tests/Jobs/Esi/Corporation/BlueprintsTest.php b/tests/Jobs/Esi/Corporation/BlueprintsTest.php new file mode 100644 index 00000000..928dc228 --- /dev/null +++ b/tests/Jobs/Esi/Corporation/BlueprintsTest.php @@ -0,0 +1,366 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + 'X-Pages' => 1, + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/corporation/blueprints.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + 'X-Pages' => 1, + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Blueprints(109299958, $token); + $job->handle(); + + $blueprints = CorporationBlueprint::all(); + + $data = json_encode(BlueprintResource::collection($blueprints)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/blueprints.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationBlueprint::create([ + 'corporation_id' => 109299958, + 'item_id' => 1000000010495, + 'location_flag' => 'Hangar', + 'location_id' => 60014719, + 'material_efficiency' => 0, + 'quantity' => 1, + 'runs' => -1, + 'time_efficiency' => 0, + 'type_id' => 691 + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Blueprints(109299958, $token); + $job->handle(); + + $blueprints = CorporationBlueprint::all(); + + foreach ($blueprints as $blueprint) + $this->assertEquals($blueprint->created_at, $blueprint->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v2/corporations/109299958/blueprints/', 'datasource=tranquility&page=1'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationBlueprint::create([ + 'corporation_id' => 109299958, + 'item_id' => 1000000010495, + 'location_flag' => 'RigSlot2', + 'location_id' => 1654676464, + 'material_efficiency' => 7, + 'quantity' => 1, + 'runs' => -1, + 'time_efficiency' => 3, + 'type_id' => 730 + ]); + + $blueprints = CorporationBlueprint::all(); + $data = json_encode(BlueprintResource::collection($blueprints)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/blueprints.json', $data); + + $job = new Blueprints(109299958, $token); + $job->handle(); + + $blueprints = CorporationBlueprint::all(); + $data = json_encode(BlueprintResource::collection($blueprints)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/blueprints.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Blueprints(109299958, $token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Blueprints(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Blueprints(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Blueprints(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Blueprints(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_blueprints.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Blueprints(109299958, $token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Blueprints(109299958, $token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Corporation/BlueprintResource.php b/tests/Resources/Esi/Corporation/BlueprintResource.php new file mode 100644 index 00000000..9ec1c0fa --- /dev/null +++ b/tests/Resources/Esi/Corporation/BlueprintResource.php @@ -0,0 +1,49 @@ + $this->item_id, + 'location_flag' => $this->location_flag, + 'location_id' => $this->location_id, + 'material_efficiency' => $this->material_efficiency, + 'quantity' => $this->quantity, + 'runs' => $this->runs, + 'time_efficiency' => $this->time_efficiency, + 'type_id' => $this->type_id, + ]; + } +} diff --git a/tests/artifacts/corporation/blueprints.json b/tests/artifacts/corporation/blueprints.json new file mode 100644 index 00000000..1962e724 --- /dev/null +++ b/tests/artifacts/corporation/blueprints.json @@ -0,0 +1,12 @@ +[ + { + "item_id": 1000000010495, + "location_flag": "CorpSAG1", + "location_id": 60014719, + "material_efficiency": 0, + "quantity": 1, + "runs": -1, + "time_efficiency": 0, + "type_id": 691 + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_03_27_155504_create_corporation_blueprints_table.php b/tests/database/migrations/2021_03_27_155504_create_corporation_blueprints_table.php new file mode 100644 index 00000000..a465b1c7 --- /dev/null +++ b/tests/database/migrations/2021_03_27_155504_create_corporation_blueprints_table.php @@ -0,0 +1,72 @@ +bigInteger('corporation_id'); + $table->bigInteger('item_id'); + $table->integer('type_id'); + $table->bigInteger('location_id'); + $table->string('location_flag'); + $table->integer('quantity'); + $table->integer('time_efficiency'); + $table->integer('material_efficiency'); + $table->integer('runs'); + + $table->primary(['corporation_id', 'item_id']); + $table->index(['corporation_id']); + $table->index(['item_id']); + $table->index(['type_id']); + $table->index(['location_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('corporation_blueprints'); + } +} From 4911d9dbbc5fc4c1b92aa1c249b1d6832f1043ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sat, 27 Mar 2021 17:10:36 +0100 Subject: [PATCH 17/42] test(jobs): add corporation divisions coverage --- .../Corporation/CorporationDivision.php | 7 + tests/Jobs/Esi/Corporation/DivisionsTest.php | 368 ++++++++++++++++++ .../Esi/Corporation/DivisionResource.php | 43 ++ .../Esi/Corporation/DivisionsResource.php | 43 ++ tests/artifacts/corporation/divisions.json | 14 + ...602_create_corporation_divisions_table.php | 65 ++++ 6 files changed, 540 insertions(+) create mode 100644 tests/Jobs/Esi/Corporation/DivisionsTest.php create mode 100644 tests/Resources/Esi/Corporation/DivisionResource.php create mode 100644 tests/Resources/Esi/Corporation/DivisionsResource.php create mode 100644 tests/artifacts/corporation/divisions.json create mode 100644 tests/database/migrations/2021_03_27_170602_create_corporation_divisions_table.php diff --git a/src/Models/Corporation/CorporationDivision.php b/src/Models/Corporation/CorporationDivision.php index 9bb722ea..940f06b3 100644 --- a/src/Models/Corporation/CorporationDivision.php +++ b/src/Models/Corporation/CorporationDivision.php @@ -39,6 +39,13 @@ class CorporationDivision extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'division' => 'integer', + ]; + /** * @var array */ diff --git a/tests/Jobs/Esi/Corporation/DivisionsTest.php b/tests/Jobs/Esi/Corporation/DivisionsTest.php new file mode 100644 index 00000000..aa81629a --- /dev/null +++ b/tests/Jobs/Esi/Corporation/DivisionsTest.php @@ -0,0 +1,368 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/corporation/divisions.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_divisions.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Divisions(109299958, $token); + $job->handle(); + + $blueprints = CorporationDivision::all(); + + $data = json_encode(DivisionsResource::make($blueprints)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/divisions.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_divisions.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationDivision::create([ + 'corporation_id' => 109299958, + 'type' => 'hangar', + 'division' => 1, + 'name' => 'Test Hangar 1', + ]); + + CorporationDivision::create([ + 'corporation_id' => 109299958, + 'type' => 'wallet', + 'division' => 1, + 'name' => 'Test Wallet 1', + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Divisions(109299958, $token); + $job->handle(); + + $divisions = CorporationDivision::all(); + + foreach ($divisions as $division) + $this->assertEquals($division->created_at, $division->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/corporations/109299958/divisions/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_divisions.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationDivision::create([ + 'corporation_id' => 109299958, + 'type' => 'hangar', + 'division' => 1, + 'name' => 'Test Hangar 1', + ]); + + CorporationDivision::create([ + 'corporation_id' => 109299958, + 'type' => 'wallet', + 'division' => 1, + 'name' => 'Test Wallet 1', + ]); + + $divisions = CorporationDivision::all(); + $data = json_encode(DivisionsResource::make($divisions)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/divisions.json', $data); + + $job = new Divisions(109299958, $token); + $job->handle(); + + $divisions = CorporationDivision::all(); + $data = json_encode(DivisionsResource::make($divisions)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/divisions.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_divisions.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Divisions(109299958, $token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_divisions.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Divisions(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_divisions.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Divisions(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_divisions.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Divisions(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_divisions.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Divisions(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_divisions.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Divisions(109299958, $token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Divisions(109299958, $token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Corporation/DivisionResource.php b/tests/Resources/Esi/Corporation/DivisionResource.php new file mode 100644 index 00000000..0a070138 --- /dev/null +++ b/tests/Resources/Esi/Corporation/DivisionResource.php @@ -0,0 +1,43 @@ + $this->division, + 'name' => $this->name, + ]; + } +} diff --git a/tests/Resources/Esi/Corporation/DivisionsResource.php b/tests/Resources/Esi/Corporation/DivisionsResource.php new file mode 100644 index 00000000..b414d496 --- /dev/null +++ b/tests/Resources/Esi/Corporation/DivisionsResource.php @@ -0,0 +1,43 @@ + DivisionResource::collection($this->where('type', 'hangar')), + 'wallet' => DivisionResource::collection($this->where('type', 'wallet')), + ]; + } +} \ No newline at end of file diff --git a/tests/artifacts/corporation/divisions.json b/tests/artifacts/corporation/divisions.json new file mode 100644 index 00000000..2b9ce34e --- /dev/null +++ b/tests/artifacts/corporation/divisions.json @@ -0,0 +1,14 @@ +{ + "hangar": [ + { + "division": 1, + "name": "Awesome Hangar 1" + } + ], + "wallet": [ + { + "division": 1, + "name": "Rich Wallet 1" + } + ] +} \ No newline at end of file diff --git a/tests/database/migrations/2021_03_27_170602_create_corporation_divisions_table.php b/tests/database/migrations/2021_03_27_170602_create_corporation_divisions_table.php new file mode 100644 index 00000000..a7b9c440 --- /dev/null +++ b/tests/database/migrations/2021_03_27_170602_create_corporation_divisions_table.php @@ -0,0 +1,65 @@ +bigInteger('corporation_id'); + $table->enum('type', ['hangar', 'wallet']); + $table->integer('division'); + $table->string('name'); + + $table->primary(['corporation_id', 'type', 'division']); + $table->index(['corporation_id']); + $table->index(['type', 'division']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('corporation_divisions'); + } +} From 38e48affd2db8301c7675fee082083a50b4b9e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sat, 27 Mar 2021 17:29:38 +0100 Subject: [PATCH 18/42] test(jobs): add corporation facilities coverage --- .../Corporation/CorporationFacility.php | 9 + tests/Jobs/Esi/Corporation/FacilitiesTest.php | 361 ++++++++++++++++++ .../Esi/Corporation/FacilityResource.php | 44 +++ tests/artifacts/corporation/facilities.json | 7 + ...52_create_corporation_facilities_table.php | 67 ++++ 5 files changed, 488 insertions(+) create mode 100644 tests/Jobs/Esi/Corporation/FacilitiesTest.php create mode 100644 tests/Resources/Esi/Corporation/FacilityResource.php create mode 100644 tests/artifacts/corporation/facilities.json create mode 100644 tests/database/migrations/2021_03_27_171452_create_corporation_facilities_table.php diff --git a/src/Models/Corporation/CorporationFacility.php b/src/Models/Corporation/CorporationFacility.php index fdfce97b..1b38330c 100644 --- a/src/Models/Corporation/CorporationFacility.php +++ b/src/Models/Corporation/CorporationFacility.php @@ -38,6 +38,15 @@ class CorporationFacility extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'facility_id' => 'integer', + 'system_id' => 'integer', + 'type_id' => 'integer', + ]; + /** * @var array */ diff --git a/tests/Jobs/Esi/Corporation/FacilitiesTest.php b/tests/Jobs/Esi/Corporation/FacilitiesTest.php new file mode 100644 index 00000000..84d5c243 --- /dev/null +++ b/tests/Jobs/Esi/Corporation/FacilitiesTest.php @@ -0,0 +1,361 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/corporation/facilities.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_facilities.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Facilities(109299958, $token); + $job->handle(); + + $facilities = CorporationFacility::all(); + + $data = json_encode(FacilityResource::collection($facilities)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/facilities.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_facilities.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationFacility::create([ + 'corporation_id' => 109299958, + 'facility_id' => 123, + 'system_id' => 45678, + 'type_id' => 2502, + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Facilities(109299958, $token); + $job->handle(); + + $facilities = CorporationFacility::all(); + + foreach ($facilities as $facility) + $this->assertEquals($facility->created_at, $facility->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/corporations/109299958/facilities/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_facilities.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationFacility::create([ + 'corporation_id' => 109299958, + 'facility_id' => 123, + 'system_id' => 45678, + 'type_id' => 2502, + ]); + + CorporationFacility::create([ + 'corporation_id' => 109299958, + 'facility_id' => 456, + 'system_id' => 15446, + 'type_id' => 1548, + ]); + + $facilities = CorporationFacility::all(); + $data = json_encode(FacilityResource::collection($facilities)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/facilities.json', $data); + + $job = new Facilities(109299958, $token); + $job->handle(); + + $facilities = CorporationFacility::all(); + $data = json_encode(FacilityResource::collection($facilities)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/facilities.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_facilities.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Facilities(109299958, $token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_facilities.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Facilities(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_facilities.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Facilities(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_facilities.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Facilities(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_facilities.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Facilities(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_facilities.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Facilities(109299958, $token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Facilities(109299958, $token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Corporation/FacilityResource.php b/tests/Resources/Esi/Corporation/FacilityResource.php new file mode 100644 index 00000000..e9a968a8 --- /dev/null +++ b/tests/Resources/Esi/Corporation/FacilityResource.php @@ -0,0 +1,44 @@ + $this->facility_id, + 'system_id' => $this->system_id, + 'type_id' => $this->type_id, + ]; + } +} diff --git a/tests/artifacts/corporation/facilities.json b/tests/artifacts/corporation/facilities.json new file mode 100644 index 00000000..58e27efb --- /dev/null +++ b/tests/artifacts/corporation/facilities.json @@ -0,0 +1,7 @@ +[ + { + "facility_id": 123, + "system_id": 45678, + "type_id": 2502 + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_03_27_171452_create_corporation_facilities_table.php b/tests/database/migrations/2021_03_27_171452_create_corporation_facilities_table.php new file mode 100644 index 00000000..d7e380aa --- /dev/null +++ b/tests/database/migrations/2021_03_27_171452_create_corporation_facilities_table.php @@ -0,0 +1,67 @@ +bigInteger('corporation_id'); + $table->bigInteger('facility_id'); + $table->integer('system_id'); + $table->integer('type_id'); + + $table->primary(['corporation_id', 'facility_id']); + $table->index(['corporation_id']); + $table->index(['facility_id']); + $table->index(['system_id']); + $table->index(['type_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('corporation_facilities'); + } +} From e8187dbe5171c4bb8c10825b676827f9341fdfc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sat, 27 Mar 2021 18:51:34 +0100 Subject: [PATCH 19/42] test(jobs): add corporation medals coverage --- .../Corporation/CorporationIssuedMedal.php | 9 + src/Models/Corporation/CorporationMedal.php | 8 + .../Jobs/Esi/Corporation/IssuedMedalsTest.php | 362 ++++++++++++++++++ tests/Jobs/Esi/Corporation/MedalsTest.php | 360 +++++++++++++++++ .../Esi/Corporation/IssuedMedalResource.php | 47 +++ .../Esi/Corporation/MedalResource.php | 46 +++ .../artifacts/corporation/issued_medals.json | 10 + tests/artifacts/corporation/medals.json | 9 + ...180216_create_corporation_medals_table.php | 65 ++++ ...create_corporation_issued_medals_table.php | 70 ++++ 10 files changed, 986 insertions(+) create mode 100644 tests/Jobs/Esi/Corporation/IssuedMedalsTest.php create mode 100644 tests/Jobs/Esi/Corporation/MedalsTest.php create mode 100644 tests/Resources/Esi/Corporation/IssuedMedalResource.php create mode 100644 tests/Resources/Esi/Corporation/MedalResource.php create mode 100644 tests/artifacts/corporation/issued_medals.json create mode 100644 tests/artifacts/corporation/medals.json create mode 100644 tests/database/migrations/2021_03_27_180216_create_corporation_medals_table.php create mode 100644 tests/database/migrations/2021_03_27_183958_create_corporation_issued_medals_table.php diff --git a/src/Models/Corporation/CorporationIssuedMedal.php b/src/Models/Corporation/CorporationIssuedMedal.php index 6c7715bf..7466af89 100644 --- a/src/Models/Corporation/CorporationIssuedMedal.php +++ b/src/Models/Corporation/CorporationIssuedMedal.php @@ -38,6 +38,15 @@ class CorporationIssuedMedal extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'character_id' => 'integer', + 'issuer_id' => 'integer', + 'medal_id' => 'integer', + ]; + /** * @var array */ diff --git a/src/Models/Corporation/CorporationMedal.php b/src/Models/Corporation/CorporationMedal.php index b0176ac2..dc143a33 100644 --- a/src/Models/Corporation/CorporationMedal.php +++ b/src/Models/Corporation/CorporationMedal.php @@ -38,6 +38,14 @@ class CorporationMedal extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'creator_id' => 'integer', + 'medal_id' => 'integer', + ]; + /** * @var array */ diff --git a/tests/Jobs/Esi/Corporation/IssuedMedalsTest.php b/tests/Jobs/Esi/Corporation/IssuedMedalsTest.php new file mode 100644 index 00000000..68e783ed --- /dev/null +++ b/tests/Jobs/Esi/Corporation/IssuedMedalsTest.php @@ -0,0 +1,362 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + 'X-Pages' => 1, + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/corporation/issued_medals.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + 'X-Pages' => 1, + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new IssuedMedals(109299958, $token); + $job->handle(); + + $medals = CorporationIssuedMedal::all(); + + $data = json_encode(IssuedMedalResource::collection($medals)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/issued_medals.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationIssuedMedal::create([ + 'corporation_id' => 109299958, + 'character_id' => 45678, + 'issued_at' => carbon('2017-10-10T14:00:00Z'), + 'issuer_id' => 98765231, + 'medal_id' => 123, + 'reason' => 'Random Reason', + 'status' => 'public', + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new IssuedMedals(109299958, $token); + $job->handle(); + + $medals = CorporationIssuedMedal::all(); + + foreach ($medals as $medal) + $this->assertEquals($medal->created_at, $medal->created_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/corporations/109299958/medals/issued/', 'datasource=tranquility&page=1'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationIssuedMedal::create([ + 'corporation_id' => 109299958, + 'character_id' => 45678, + 'issued_at' => carbon('2017-10-10T14:00:00Z'), + 'issuer_id' => 98765231, + 'medal_id' => 123, + 'reason' => 'Random Reason', + 'status' => 'public', + ]); + + $medals = CorporationIssuedMedal::all(); + $data = json_encode(IssuedMedalResource::collection($medals)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/issued_medals.json', $data); + + $job = new IssuedMedals(109299958, $token); + $job->handle(); + + $medals = CorporationIssuedMedal::all(); + $data = json_encode(IssuedMedalResource::collection($medals)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/issued_medals.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new IssuedMedals(109299958, $token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new IssuedMedals(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new IssuedMedals(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new IssuedMedals(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new IssuedMedals(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new IssuedMedals(109299958, $token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new IssuedMedals(109299958, $token); + $job->handle(); + } +} diff --git a/tests/Jobs/Esi/Corporation/MedalsTest.php b/tests/Jobs/Esi/Corporation/MedalsTest.php new file mode 100644 index 00000000..38da00e2 --- /dev/null +++ b/tests/Jobs/Esi/Corporation/MedalsTest.php @@ -0,0 +1,360 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + 'X-Pages' => 1, + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/corporation/medals.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + 'X-Pages' => 1, + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Medals(109299958, $token); + $job->handle(); + + $medals = CorporationMedal::all(); + + $data = json_encode(MedalResource::collection($medals)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/medals.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationMedal::create([ + 'corporation_id' => 109299958, + 'created_at' => carbon('2017-10-10T14:00:00Z'), + 'creator_id' => 46578, + 'description' => 'A simple description', + 'medal_id' => 123, + 'title' => 'Testing Medal', + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Medals(109299958, $token); + $job->handle(); + + $medals = CorporationMedal::all(); + + foreach ($medals as $medal) + $this->assertEquals($medal->created_at, carbon('2017-10-10T14:00:00Z')); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/corporations/109299958/medals/', 'datasource=tranquility&page=1'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationMedal::create([ + 'corporation_id' => 109299958, + 'created_at' => carbon('2017-10-10T14:00:00Z'), + 'creator_id' => 46578, + 'description' => 'A simple description', + 'medal_id' => 123, + 'title' => 'Testing Medal', + ]); + + $medals = CorporationMedal::all(); + $data = json_encode(MedalResource::collection($medals)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/medals.json', $data); + + $job = new Medals(109299958, $token); + $job->handle(); + + $medals = CorporationMedal::all(); + $data = json_encode(MedalResource::collection($medals)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/medals.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Medals(109299958, $token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Medals(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Medals(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Medals(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Medals(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_medals.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Medals(109299958, $token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Medals(109299958, $token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Corporation/IssuedMedalResource.php b/tests/Resources/Esi/Corporation/IssuedMedalResource.php new file mode 100644 index 00000000..bfa1beff --- /dev/null +++ b/tests/Resources/Esi/Corporation/IssuedMedalResource.php @@ -0,0 +1,47 @@ + $this->character_id, + 'issued_at' => carbon($this->issued_at)->toIso8601ZuluString(), + 'issuer_id' => $this->issuer_id, + 'medal_id' => $this->medal_id, + 'reason' => $this->reason, + 'status' => $this->status, + ]; + } +} diff --git a/tests/Resources/Esi/Corporation/MedalResource.php b/tests/Resources/Esi/Corporation/MedalResource.php new file mode 100644 index 00000000..a6407780 --- /dev/null +++ b/tests/Resources/Esi/Corporation/MedalResource.php @@ -0,0 +1,46 @@ + carbon($this->created_at)->toIso8601ZuluString(), + 'creator_id' => $this->creator_id, + 'description' => $this->description, + 'medal_id' => $this->medal_id, + 'title' => $this->title, + ]; + } +} diff --git a/tests/artifacts/corporation/issued_medals.json b/tests/artifacts/corporation/issued_medals.json new file mode 100644 index 00000000..ebb17e73 --- /dev/null +++ b/tests/artifacts/corporation/issued_medals.json @@ -0,0 +1,10 @@ +[ + { + "character_id": 45678, + "issued_at": "2017-10-10T14:00:00Z", + "issuer_id": 67890, + "medal_id": 123, + "reason": "Awesome Reason", + "status": "private" + } +] \ No newline at end of file diff --git a/tests/artifacts/corporation/medals.json b/tests/artifacts/corporation/medals.json new file mode 100644 index 00000000..03738a99 --- /dev/null +++ b/tests/artifacts/corporation/medals.json @@ -0,0 +1,9 @@ +[ + { + "created_at": "2017-10-10T14:00:00Z", + "creator_id": 46578, + "description": "An Awesome Medal", + "medal_id": 123, + "title": "Awesome Medal" + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_03_27_180216_create_corporation_medals_table.php b/tests/database/migrations/2021_03_27_180216_create_corporation_medals_table.php new file mode 100644 index 00000000..4889c6e4 --- /dev/null +++ b/tests/database/migrations/2021_03_27_180216_create_corporation_medals_table.php @@ -0,0 +1,65 @@ +bigInteger('corporation_id')->primary(); + $table->bigInteger('creator_id'); + $table->text('description'); + $table->integer('medal_id'); + $table->string('title'); + + $table->index('medal_id'); + $table->index('creator_id'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('corporation_medals'); + } +} diff --git a/tests/database/migrations/2021_03_27_183958_create_corporation_issued_medals_table.php b/tests/database/migrations/2021_03_27_183958_create_corporation_issued_medals_table.php new file mode 100644 index 00000000..8c79da83 --- /dev/null +++ b/tests/database/migrations/2021_03_27_183958_create_corporation_issued_medals_table.php @@ -0,0 +1,70 @@ +bigInteger('corporation_id'); + $table->integer('medal_id'); + $table->bigInteger('character_id'); + $table->text('reason'); + $table->enum('status', ['public', 'private']); + $table->bigInteger('issuer_id'); + $table->dateTime('issued_at'); + + $table->primary(['corporation_id', 'medal_id', 'character_id']); + $table->index(['corporation_id']); + $table->index(['medal_id']); + $table->index(['character_id']); + $table->index(['issuer_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('corporation_issued_medals'); + } +} From 2aa505f6e51aa05b148676e57f5a0349ec0dddfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sat, 27 Mar 2021 19:04:07 +0100 Subject: [PATCH 20/42] test(jobs): add corporation members coverage --- src/Models/Corporation/CorporationMember.php | 8 + tests/Jobs/Esi/Corporation/MembersTest.php | 354 ++++++++++++++++++ tests/artifacts/corporation/members.json | 4 + ...85220_create_corporation_members_table.php | 63 ++++ 4 files changed, 429 insertions(+) create mode 100644 tests/Jobs/Esi/Corporation/MembersTest.php create mode 100644 tests/artifacts/corporation/members.json create mode 100644 tests/database/migrations/2021_03_27_185220_create_corporation_members_table.php diff --git a/src/Models/Corporation/CorporationMember.php b/src/Models/Corporation/CorporationMember.php index 637b6aee..ad263968 100644 --- a/src/Models/Corporation/CorporationMember.php +++ b/src/Models/Corporation/CorporationMember.php @@ -38,6 +38,14 @@ class CorporationMember extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'corporation_id' => 'integer', + 'character_id' => 'integer', + ]; + /** * @var array */ diff --git a/tests/Jobs/Esi/Corporation/MembersTest.php b/tests/Jobs/Esi/Corporation/MembersTest.php new file mode 100644 index 00000000..72b2b1fd --- /dev/null +++ b/tests/Jobs/Esi/Corporation/MembersTest.php @@ -0,0 +1,354 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/corporation/members.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_corporation_membership.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Members(109299958, $token); + $job->handle(); + + $members = CorporationMember::all(); + + $data = json_encode($members->pluck('character_id')->toArray()); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/members.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_corporation_membership.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationMember::create([ + 'corporation_id' => 109299958, + 'character_id' => 90000000, + ]); + + CorporationMember::create([ + 'corporation_id' => 109299958, + 'character_id' => 90000003, + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Members(109299958, $token); + $job->handle(); + + $members = CorporationMember::all(); + + foreach ($members as $member) + $this->assertEquals($member->created_at, $member->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v3/corporations/109299958/members/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_corporation_membership.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationMember::create([ + 'corporation_id' => 109299958, + 'character_id' => 90000001, + ]); + + $members = CorporationMember::all(); + $data = json_encode($members->pluck('character_id')->toArray()); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/members.json', $data); + + $job = new Members(109299958, $token); + $job->handle(); + + $members = CorporationMember::all(); + $data = json_encode($members->pluck('character_id')->toArray()); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/members.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_corporation_membership.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Members(109299958, $token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_corporation_membership.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Members(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_corporation_membership.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Members(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_corporation_membership.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Members(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_corporation_membership.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Members(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_corporation_membership.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Members(109299958, $token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Members(109299958, $token); + $job->handle(); + } +} diff --git a/tests/artifacts/corporation/members.json b/tests/artifacts/corporation/members.json new file mode 100644 index 00000000..3fb5ec38 --- /dev/null +++ b/tests/artifacts/corporation/members.json @@ -0,0 +1,4 @@ +[ + 90000001, + 90000002 +] \ No newline at end of file diff --git a/tests/database/migrations/2021_03_27_185220_create_corporation_members_table.php b/tests/database/migrations/2021_03_27_185220_create_corporation_members_table.php new file mode 100644 index 00000000..f765286e --- /dev/null +++ b/tests/database/migrations/2021_03_27_185220_create_corporation_members_table.php @@ -0,0 +1,63 @@ +bigInteger('corporation_id'); + $table->bigInteger('character_id'); + + $table->primary(['corporation_id', 'character_id']); + $table->index(['corporation_id']); + $table->index(['character_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('corporation_members'); + } +} From 1aca59d71592a35efd3c958e8136b26eacfdba89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sat, 27 Mar 2021 19:18:29 +0100 Subject: [PATCH 21/42] test(jobs): add corporation limit coverage --- .../Corporation/CorporationMemberLimits.php | 7 + tests/Jobs/Esi/Corporation/LimitTest.php | 348 ++++++++++++++++++ tests/artifacts/corporation/limit.json | 1 + ...create_corporation_member_limits_table.php | 59 +++ 4 files changed, 415 insertions(+) create mode 100644 tests/Jobs/Esi/Corporation/LimitTest.php create mode 100644 tests/artifacts/corporation/limit.json create mode 100644 tests/database/migrations/2021_03_27_190652_create_corporation_member_limits_table.php diff --git a/src/Models/Corporation/CorporationMemberLimits.php b/src/Models/Corporation/CorporationMemberLimits.php index 8990b404..8a68c536 100644 --- a/src/Models/Corporation/CorporationMemberLimits.php +++ b/src/Models/Corporation/CorporationMemberLimits.php @@ -40,6 +40,13 @@ class CorporationMemberLimits extends Model */ public $incrementing = false; + /** + * @var string[] + */ + protected $casts = [ + 'limit' => 'integer', + ]; + /** * @var string */ diff --git a/tests/Jobs/Esi/Corporation/LimitTest.php b/tests/Jobs/Esi/Corporation/LimitTest.php new file mode 100644 index 00000000..447394f2 --- /dev/null +++ b/tests/Jobs/Esi/Corporation/LimitTest.php @@ -0,0 +1,348 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/corporation/limit.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new MembersLimit(109299958, $token); + $job->handle(); + + $corporation = CorporationMemberLimits::first(); + + $data = json_encode($corporation->limit); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/limit.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationMemberLimits::create([ + 'corporation_id' => 109299958, + 'limit' => 20, + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new MembersLimit(109299958, $token); + $job->handle(); + + $corporation = CorporationMemberLimits::first(); + + $this->assertEquals($corporation->created_at, $corporation->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/corporations/109299958/members/limit/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationMemberLimits::create([ + 'corporation_id' => 109299958, + 'limit' => 20, + ]); + + $corporation = CorporationMemberLimits::first(); + $data = json_encode($corporation->limit); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/limit.json', $data); + + $job = new MembersLimit(109299958, $token); + $job->handle(); + + $corporation = CorporationMemberLimits::first(); + $data = json_encode($corporation->limit); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/limit.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new MembersLimit(109299958, $token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new MembersLimit(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new MembersLimit(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new MembersLimit(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new MembersLimit(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new MembersLimit(109299958, $token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new MembersLimit(109299958, $token); + $job->handle(); + } +} diff --git a/tests/artifacts/corporation/limit.json b/tests/artifacts/corporation/limit.json new file mode 100644 index 00000000..86ee83a4 --- /dev/null +++ b/tests/artifacts/corporation/limit.json @@ -0,0 +1 @@ +40 \ No newline at end of file diff --git a/tests/database/migrations/2021_03_27_190652_create_corporation_member_limits_table.php b/tests/database/migrations/2021_03_27_190652_create_corporation_member_limits_table.php new file mode 100644 index 00000000..866673f6 --- /dev/null +++ b/tests/database/migrations/2021_03_27_190652_create_corporation_member_limits_table.php @@ -0,0 +1,59 @@ +bigInteger('corporation_id')->primary(); + $table->integer('limit'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('corporation_member_limits'); + } +} From 87c0a3f403efe1c2756c722a5943be1a81a1861b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sat, 27 Mar 2021 19:45:01 +0100 Subject: [PATCH 22/42] test(jobs): add corporation member tracking coverage --- .../Corporation/CorporationMemberTracking.php | 9 + .../Esi/Corporation/MemberTrackingTest.php | 378 ++++++++++++++++++ .../Corporation/MemberTrackingResource.php | 48 +++ .../corporation/member_tracking.json | 18 + ...ate_corporation_member_trackings_table.php | 70 ++++ 5 files changed, 523 insertions(+) create mode 100644 tests/Jobs/Esi/Corporation/MemberTrackingTest.php create mode 100644 tests/Resources/Esi/Corporation/MemberTrackingResource.php create mode 100644 tests/artifacts/corporation/member_tracking.json create mode 100644 tests/database/migrations/2021_03_27_191916_create_corporation_member_trackings_table.php diff --git a/src/Models/Corporation/CorporationMemberTracking.php b/src/Models/Corporation/CorporationMemberTracking.php index b32475e6..0542ceb6 100644 --- a/src/Models/Corporation/CorporationMemberTracking.php +++ b/src/Models/Corporation/CorporationMemberTracking.php @@ -95,6 +95,15 @@ class CorporationMemberTracking extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'character_id' => 'integer', + 'location_id' => 'integer', + 'ship_type_id' => 'integer', + ]; + /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ diff --git a/tests/Jobs/Esi/Corporation/MemberTrackingTest.php b/tests/Jobs/Esi/Corporation/MemberTrackingTest.php new file mode 100644 index 00000000..f106d1b5 --- /dev/null +++ b/tests/Jobs/Esi/Corporation/MemberTrackingTest.php @@ -0,0 +1,378 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/corporation/member_tracking.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new MemberTracking(109299958, $token); + $job->handle(); + + $members = CorporationMemberTracking::all(); + + $data = json_encode(MemberTrackingResource::collection($members)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/member_tracking.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationMemberTracking::create([ + 'corporation_id' => 109299958, + 'character_id' => 2112000002, + 'base_id' => 123, + 'location_id' => 2502, + 'logon_date' => '2017-07-25T10:54:00Z', + 'ship_type_id' => 46588941, + ]); + + CorporationMemberTracking::create([ + 'corporation_id' => 109299958, + 'character_id' => 2112000001, + 'base_id' => 123, + 'location_id' => 2502, + 'logon_date' => '2017-07-25T10:54:00Z', + 'logoff_date' => '2018-10-13T11:23:00Z', + 'start_date' => '2017-07-25T10:54:00Z', + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new MemberTracking(109299958, $token); + $job->handle(); + + $members = CorporationMemberTracking::all(); + + foreach ($members as $member) + $this->assertEquals($member->created_at, $member->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/corporations/109299958/membertracking/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationMemberTracking::create([ + 'corporation_id' => 109299958, + 'character_id' => 2112000002, + 'base_id' => 123, + 'location_id' => 2502, + 'logon_date' => '2017-07-25T10:54:00Z', + 'ship_type_id' => 46588941, + ]); + + CorporationMemberTracking::create([ + 'corporation_id' => 109299958, + 'character_id' => 2112000001, + 'base_id' => 123, + 'location_id' => 2502, + 'logon_date' => '2017-07-25T10:54:00Z', + 'logoff_date' => '2018-10-13T11:23:00Z', + 'start_date' => '2017-07-25T10:54:00Z', + ]); + + $members = CorporationMemberTracking::all(); + $data = json_encode(MemberTrackingResource::collection($members->sortBy('character_id'))); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/member_tracking.json', $data); + + $job = new MemberTracking(109299958, $token); + $job->handle(); + + $members = CorporationMemberTracking::all(); + $data = json_encode(MemberTrackingResource::collection($members->sortBy('character_id'))); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/corporation/member_tracking.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new MemberTracking(109299958, $token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new MemberTracking(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new MemberTracking(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new MemberTracking(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new MemberTracking(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.track_members.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new MemberTracking(109299958, $token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new MemberTracking(109299958, $token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Corporation/MemberTrackingResource.php b/tests/Resources/Esi/Corporation/MemberTrackingResource.php new file mode 100644 index 00000000..5488c76a --- /dev/null +++ b/tests/Resources/Esi/Corporation/MemberTrackingResource.php @@ -0,0 +1,48 @@ + $this->when(! is_null($this->base_id), $this->base_id), + 'character_id' => $this->character_id, + 'location_id' => $this->when(! is_null($this->location_id), $this->location_id), + 'logoff_date' => $this->when(! is_null($this->logoff_date), carbon($this->logoff_date)->toIso8601ZuluString()), + 'logon_date' => $this->when(! is_null($this->logon_date), carbon($this->logon_date)->toIso8601ZuluString()), + 'ship_type_id' => $this->when(! is_null($this->ship_type_id), $this->ship_type_id), + 'start_date' => $this->when(! is_null($this->start_date), carbon($this->start_date)->toIso8601ZuluString()), + ]; + } +} diff --git a/tests/artifacts/corporation/member_tracking.json b/tests/artifacts/corporation/member_tracking.json new file mode 100644 index 00000000..1dd78b66 --- /dev/null +++ b/tests/artifacts/corporation/member_tracking.json @@ -0,0 +1,18 @@ +[ + { + "character_id": 2112000001, + "location_id": 30003657, + "logoff_date": "2017-08-03T14:31:16Z", + "logon_date": "2017-08-03T14:22:03Z", + "ship_type_id": 22464, + "start_date": "2017-07-10T14:46:00Z" + }, + { + "character_id": 2112000002, + "location_id": 30003657, + "logoff_date": "2017-07-25T11:07:40Z", + "logon_date": "2017-07-25T10:54:00Z", + "ship_type_id": 670, + "start_date": "2017-07-10T14:50:00Z" + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_03_27_191916_create_corporation_member_trackings_table.php b/tests/database/migrations/2021_03_27_191916_create_corporation_member_trackings_table.php new file mode 100644 index 00000000..4058c954 --- /dev/null +++ b/tests/database/migrations/2021_03_27_191916_create_corporation_member_trackings_table.php @@ -0,0 +1,70 @@ +bigIncrements('id'); + $table->bigInteger('corporation_id'); + $table->integer('base_id')->nullable(); + $table->bigInteger('character_id'); + $table->bigInteger('location_id')->nullable(); + $table->dateTime('logoff_date')->nullable(); + $table->dateTime('logon_date')->nullable(); + $table->integer('ship_type_id')->nullable(); + $table->dateTime('start_date')->nullable(); + + $table->unique(['corporation_id', 'character_id']); + $table->index(['corporation_id']); + $table->index(['character_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('corporation_member_trackings'); + } +} From c23ea8b7751e6fc1a1d8e000ccc248e6675094aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Fri, 2 Apr 2021 11:16:48 +0200 Subject: [PATCH 23/42] test(jobs): add fittings coverage --- src/Models/Fittings/CharacterFitting.php | 8 + src/Models/Fittings/CharacterFittingItem.php | 11 + tests/Jobs/Esi/Fittings/FittingsTest.php | 408 ++++++++++++++++++ .../Esi/Fittings/FittingResource.php | 46 ++ tests/Resources/Esi/Fittings/ItemResource.php | 44 ++ tests/artifacts/fittings/fittings.json | 15 + ...103259_create_character_fittings_table.php | 68 +++ ...6_create_character_fitting_items_table.php | 67 +++ 8 files changed, 667 insertions(+) create mode 100644 tests/Jobs/Esi/Fittings/FittingsTest.php create mode 100644 tests/Resources/Esi/Fittings/FittingResource.php create mode 100644 tests/Resources/Esi/Fittings/ItemResource.php create mode 100644 tests/artifacts/fittings/fittings.json create mode 100644 tests/database/migrations/2021_04_02_103259_create_character_fittings_table.php create mode 100644 tests/database/migrations/2021_04_02_103536_create_character_fitting_items_table.php diff --git a/src/Models/Fittings/CharacterFitting.php b/src/Models/Fittings/CharacterFitting.php index f414d7e0..366dfb11 100644 --- a/src/Models/Fittings/CharacterFitting.php +++ b/src/Models/Fittings/CharacterFitting.php @@ -36,6 +36,14 @@ class CharacterFitting extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'fitting_id' => 'integer', + 'ship_type_id' => 'integer', + ]; + /** * @return \Illuminate\Database\Eloquent\Relations\HasMany */ diff --git a/src/Models/Fittings/CharacterFittingItem.php b/src/Models/Fittings/CharacterFittingItem.php index 7c44069e..d0b7e602 100644 --- a/src/Models/Fittings/CharacterFittingItem.php +++ b/src/Models/Fittings/CharacterFittingItem.php @@ -36,6 +36,17 @@ class CharacterFittingItem extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'quantity' => 'integer', + 'type_id' => 'integer', + ]; + + /** + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ public function type() { diff --git a/tests/Jobs/Esi/Fittings/FittingsTest.php b/tests/Jobs/Esi/Fittings/FittingsTest.php new file mode 100644 index 00000000..89755490 --- /dev/null +++ b/tests/Jobs/Esi/Fittings/FittingsTest.php @@ -0,0 +1,408 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/fittings/fittings.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-fittings.read_fittings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Fittings($token); + $job->handle(); + + $fittings = CharacterFitting::all(); + + $data = json_encode(FittingResource::collection($fittings)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/fittings/fittings.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-fittings.read_fittings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterFitting::create([ + 'character_id' => 180548812, + 'fitting_id' => 1, + 'name' => 'Random fitting name', + 'description' => 'This is a long as possible description from this fitting explaining nothing and telling a lot of things.', + 'ship_type_id' => 123, + ]); + + CharacterFittingItem::create([ + 'fitting_id' => 1, + 'flag' => 'Cargo', + 'quantity' => 20, + 'type_id' => 1234, + ]); + + CharacterFitting::create([ + 'character_id' => 180548812, + 'fitting_id' => 2, + 'name' => 'Random fitting name', + 'description' => 'This is a long as possible description from this fitting explaining nothing and telling a lot of things.', + 'ship_type_id' => 123, + ]); + + CharacterFittingItem::create([ + 'fitting_id' => 2, + 'flag' => 'Cargo', + 'quantity' => 20, + 'type_id' => 1234, + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Fittings($token); + $job->handle(); + + $fittings = CharacterFitting::all(); + + foreach ($fittings as $fitting) + $this->assertEquals($fitting->created_at, $fitting->updated_at); + + $this->assertCount(2, $fittings); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v2/characters/180548812/fittings/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-fittings.read_fittings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterFitting::create([ + 'character_id' => 180548812, + 'fitting_id' => 1, + 'name' => 'Random fitting name', + 'description' => 'This is a long as possible description from this fitting explaining nothing and telling a lot of things.', + 'ship_type_id' => 123, + ]); + + CharacterFittingItem::create([ + 'fitting_id' => 1, + 'flag' => 'Cargo', + 'quantity' => 1, + 'type_id' => 1234, + ]); + + CharacterFitting::create([ + 'character_id' => 180548812, + 'fitting_id' => 2, + 'name' => 'Random fitting name', + 'description' => 'This is a long as possible description from this fitting explaining nothing and telling a lot of things.', + 'ship_type_id' => 123, + ]); + + CharacterFittingItem::create([ + 'fitting_id' => 2, + 'flag' => 'Cargo', + 'quantity' => 20, + 'type_id' => 1234, + ]); + + $fittings = CharacterFitting::all(); + $data = json_encode(FittingResource::collection($fittings)); + $this->assertCount(2, $fittings); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/fittings/fittings.json', $data); + + $job = new Fittings($token); + $job->handle(); + + $fittings = CharacterFitting::all(); + + $data = json_encode(FittingResource::collection($fittings)); + $this->assertCount(1, $fittings); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/fittings/fittings.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-fittings.read_fittings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Fittings($token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-fittings.read_fittings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Fittings($token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-fittings.read_fittings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Fittings($token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-fittings.read_fittings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Fittings($token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-fittings.read_fittings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Fittings($token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-fittings.read_fittings.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Fittings($token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Fittings($token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Fittings/FittingResource.php b/tests/Resources/Esi/Fittings/FittingResource.php new file mode 100644 index 00000000..0644ff5d --- /dev/null +++ b/tests/Resources/Esi/Fittings/FittingResource.php @@ -0,0 +1,46 @@ + $this->description, + 'fitting_id' => $this->fitting_id, + 'items' => ItemResource::collection($this->items), + 'name' => $this->name, + 'ship_type_id' => $this->ship_type_id, + ]; + } +} diff --git a/tests/Resources/Esi/Fittings/ItemResource.php b/tests/Resources/Esi/Fittings/ItemResource.php new file mode 100644 index 00000000..3f891b2b --- /dev/null +++ b/tests/Resources/Esi/Fittings/ItemResource.php @@ -0,0 +1,44 @@ + $this->flag, + 'quantity' => $this->quantity, + 'type_id' => $this->type_id, + ]; + } +} diff --git a/tests/artifacts/fittings/fittings.json b/tests/artifacts/fittings/fittings.json new file mode 100644 index 00000000..279e334a --- /dev/null +++ b/tests/artifacts/fittings/fittings.json @@ -0,0 +1,15 @@ +[ + { + "description": "Awesome Vindi fitting", + "fitting_id": 1, + "items": [ + { + "flag": "Cargo", + "quantity": 1, + "type_id": 1234 + } + ], + "name": "Best Vindicator", + "ship_type_id": 123 + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_04_02_103259_create_character_fittings_table.php b/tests/database/migrations/2021_04_02_103259_create_character_fittings_table.php new file mode 100644 index 00000000..525dd093 --- /dev/null +++ b/tests/database/migrations/2021_04_02_103259_create_character_fittings_table.php @@ -0,0 +1,68 @@ +bigIncrements('id'); + $table->bigInteger('character_id'); + $table->bigInteger('fitting_id'); + $table->string('name'); + $table->text('description'); + $table->integer('ship_type_id'); + + $table->unique(['character_id', 'fitting_id']); + $table->index(['ship_type_id']); + $table->index(['fitting_id']); + $table->index(['character_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_fittings'); + } +} diff --git a/tests/database/migrations/2021_04_02_103536_create_character_fitting_items_table.php b/tests/database/migrations/2021_04_02_103536_create_character_fitting_items_table.php new file mode 100644 index 00000000..1e8773d4 --- /dev/null +++ b/tests/database/migrations/2021_04_02_103536_create_character_fitting_items_table.php @@ -0,0 +1,67 @@ +bigIncrements('id'); + $table->bigInteger('fitting_id'); + $table->integer('type_id'); + $table->string('flag'); + $table->integer('quantity'); + + $table->unique(['fitting_id', 'type_id', 'flag']); + $table->index(['fitting_id']); + $table->index(['type_id']); + $table->index(['flag']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_fitting_items'); + } +} From 4c5e873e91f7844d5658597da4c000770b29f8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Fri, 2 Apr 2021 14:55:05 +0200 Subject: [PATCH 24/42] feat(jobs): remove old insurances during update --- src/Jobs/Fittings/Insurances.php | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/Jobs/Fittings/Insurances.php b/src/Jobs/Fittings/Insurances.php index 598ed4f4..e7d34953 100644 --- a/src/Jobs/Fittings/Insurances.php +++ b/src/Jobs/Fittings/Insurances.php @@ -22,6 +22,9 @@ namespace Seat\Eveapi\Jobs\Fittings; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Schema; use Seat\Eveapi\Jobs\EsiBase; use Seat\Eveapi\Models\Fittings\Insurance; @@ -62,19 +65,38 @@ public function handle() if ($insurances->isCachedLoad() && Insurance::count() > 0) return; + // create a temporary table - so it will be easier to handle delta between + // dropped insurances and created/not-updated ones. + + Schema::create('temp_insurances', function (Blueprint $table) { + $table->integer('id')->primary(); + $table->temporary(); + }); + collect($insurances)->each(function ($insurance) { collect($insurance->levels)->each(function ($level) use ($insurance) { - Insurance::firstOrNew([ + $model = Insurance::updateOrCreate([ 'type_id' => $insurance->type_id, 'name' => $level->name, ], [ 'cost' => $level->cost, 'payout' => $level->payout, - ])->save(); + ]); + DB::table('temp_insurances')->insert([ + 'id' => $model->id, + ]); }); }); + + // drop old insurances + DB::table('insurances') + ->leftJoin('temp_insurances', 'insurances.id', '=', 'temp_insurances.id') + ->whereNull('temp_insurances.id') + ->delete(); + + Schema::dropIfExists('temp_insurances'); } } From d51158a7e2cd717ada0d96c59af4b470ae8ec10f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Fri, 2 Apr 2021 14:55:55 +0200 Subject: [PATCH 25/42] test(jobs): add fittings insurances coverage --- src/Models/Fittings/Insurance.php | 9 + tests/Jobs/Esi/Insurance/PricesTest.php | 253 ++++++++++++++++++ .../Esi/Insurance/InsuranceResource.php | 43 +++ .../Resources/Esi/Insurance/PriceResource.php | 42 +++ tests/artifacts/insurance/prices.json | 12 + ...1_04_02_113708_create_insurances_table.php | 65 +++++ 6 files changed, 424 insertions(+) create mode 100644 tests/Jobs/Esi/Insurance/PricesTest.php create mode 100644 tests/Resources/Esi/Insurance/InsuranceResource.php create mode 100644 tests/Resources/Esi/Insurance/PriceResource.php create mode 100644 tests/artifacts/insurance/prices.json create mode 100644 tests/database/migrations/2021_04_02_113708_create_insurances_table.php diff --git a/src/Models/Fittings/Insurance.php b/src/Models/Fittings/Insurance.php index 6e3991f5..d1b8f4a5 100644 --- a/src/Models/Fittings/Insurance.php +++ b/src/Models/Fittings/Insurance.php @@ -40,4 +40,13 @@ class Insurance extends Model * @var bool */ protected static $unguarded = true; + + /** + * @var string[] + */ + protected $casts = [ + 'type_id' => 'integer', + 'cost' => 'double', + 'payout' => 'double', + ]; } diff --git a/tests/Jobs/Esi/Insurance/PricesTest.php b/tests/Jobs/Esi/Insurance/PricesTest.php new file mode 100644 index 00000000..33b91185 --- /dev/null +++ b/tests/Jobs/Esi/Insurance/PricesTest.php @@ -0,0 +1,253 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/insurance/prices.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $job = new Insurances(); + $job->handle(); + + $insurances = Insurance::all(); + + $data = json_encode(InsuranceResource::collection($insurances->groupBy('type_id'))); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/insurance/prices.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + Insurance::create([ + 'type_id' => 1, + 'name' => 'Basic', + 'cost' => 100.17, + 'payout' => 200.38, + ]); + + Insurance::create([ + 'type_id' => 1, + 'name' => 'Standard', + 'cost' => 100.17, + 'payout' => 200.38, + ]); + + Insurance::create([ + 'type_id' => 1, + 'name' => 'Bronze', + 'cost' => 100.17, + 'payout' => 200.38, + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Insurances(); + $job->handle(); + + $insurances = Insurance::all(); + + foreach ($insurances as $insurance) + $this->assertEquals($insurance->created_at, $insurance->updated_at); + + $this->assertCount(3, $insurances); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/insurance/prices/', 'datasource=tranquility'); + + Insurance::create([ + 'type_id' => 1, + 'name' => 'Basic', + 'cost' => 100.17, + 'payout' => 200.38, + ]); + + Insurance::create([ + 'type_id' => 1, + 'name' => 'Standard', + 'cost' => 100.17, + 'payout' => 200.38, + ]); + + Insurance::create([ + 'type_id' => 1, + 'name' => 'Bronze', + 'cost' => 100.17, + 'payout' => 200.38, + ]); + + $insurances = Insurance::all(); + $data = json_encode(InsuranceResource::collection($insurances->groupBy('type_id'))); + $this->assertCount(3, $insurances); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/insurance/prices.json', $data); + + $job = new Insurances(); + $job->handle(); + + $insurances = Insurance::all(); + + $data = json_encode(InsuranceResource::collection($insurances->groupBy('type_id'))); + $this->assertCount(1, $insurances); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/insurance/prices.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $job = new Insurances(); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $job = new Insurances(); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $job = new Insurances(); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $job = new Insurances(); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $job = new Insurances(); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Insurance/InsuranceResource.php b/tests/Resources/Esi/Insurance/InsuranceResource.php new file mode 100644 index 00000000..1375ce30 --- /dev/null +++ b/tests/Resources/Esi/Insurance/InsuranceResource.php @@ -0,0 +1,43 @@ + $this->first()->type_id, + 'levels' => PriceResource::collection($this), + ]; + } +} diff --git a/tests/Resources/Esi/Insurance/PriceResource.php b/tests/Resources/Esi/Insurance/PriceResource.php new file mode 100644 index 00000000..00029f34 --- /dev/null +++ b/tests/Resources/Esi/Insurance/PriceResource.php @@ -0,0 +1,42 @@ + $this->cost, + 'name' => $this->name, + 'payout' => $this->payout, + ]; + } +} diff --git a/tests/artifacts/insurance/prices.json b/tests/artifacts/insurance/prices.json new file mode 100644 index 00000000..be0011d2 --- /dev/null +++ b/tests/artifacts/insurance/prices.json @@ -0,0 +1,12 @@ +[ + { + "levels": [ + { + "cost": 10.01, + "name": "Basic", + "payout": 20.01 + } + ], + "type_id": 1 + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_04_02_113708_create_insurances_table.php b/tests/database/migrations/2021_04_02_113708_create_insurances_table.php new file mode 100644 index 00000000..d94da2eb --- /dev/null +++ b/tests/database/migrations/2021_04_02_113708_create_insurances_table.php @@ -0,0 +1,65 @@ +increments('id'); + $table->integer('type_id'); + $table->string('name'); + $table->double('cost'); + $table->double('payout'); + + $table->unique(['type_id', 'name']); + $table->index(['type_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('insurances'); + } +} From d3d9efba66cec206b14086550a104424a246ecaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Fri, 2 Apr 2021 14:56:57 +0200 Subject: [PATCH 26/42] test(jobs): add character attributes coverage --- src/Models/Skills/CharacterAttribute.php | 13 +- tests/Jobs/Esi/Skills/AttributesTest.php | 365 ++++++++++++++++++ .../Esi/Skills/AttributeResource.php | 49 +++ tests/artifacts/skills/attributes.json | 7 + ...2637_create_character_attributes_table.php | 66 ++++ 5 files changed, 499 insertions(+), 1 deletion(-) create mode 100644 tests/Jobs/Esi/Skills/AttributesTest.php create mode 100644 tests/Resources/Esi/Skills/AttributeResource.php create mode 100644 tests/artifacts/skills/attributes.json create mode 100644 tests/database/migrations/2021_04_02_132637_create_character_attributes_table.php diff --git a/src/Models/Skills/CharacterAttribute.php b/src/Models/Skills/CharacterAttribute.php index 781eb01f..3aa8f335 100644 --- a/src/Models/Skills/CharacterAttribute.php +++ b/src/Models/Skills/CharacterAttribute.php @@ -30,7 +30,6 @@ */ class CharacterAttribute extends Model { - /** * @var bool */ @@ -46,6 +45,18 @@ class CharacterAttribute extends Model */ protected $primaryKey = 'character_id'; + /** + * @var array + */ + protected $casts = [ + 'bonus_remap' => 'integer', + 'charisma' => 'integer', + 'intelligence' => 'integer', + 'memory' => 'integer', + 'perception' => 'integer', + 'willpower' => 'integer', + ]; + /** * @param $value */ diff --git a/tests/Jobs/Esi/Skills/AttributesTest.php b/tests/Jobs/Esi/Skills/AttributesTest.php new file mode 100644 index 00000000..29c3470b --- /dev/null +++ b/tests/Jobs/Esi/Skills/AttributesTest.php @@ -0,0 +1,365 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/skills/attributes.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Attributes($token); + $job->handle(); + + $attributes = CharacterAttribute::find(180548812); + + $data = json_encode(new AttributeResource($attributes)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/skills/attributes.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $attributes = new CharacterAttribute([ + 'character_id' => 180548812, + 'charisma' => 3, + 'intelligence' => 10, + 'memory' => 5, + 'perception' => 2, + 'willpower' => 7, + 'bonus_remaps' => 2, + 'accrued_remap_cooldown_date' => '2015-03-23T11:37:00Z', + 'last_remap_date' => '2015-03-24T10:37:00Z', + ]); + $attributes->save(); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Attributes($token); + $job->handle(); + + $attributes = CharacterAttribute::find(180548812); + + $this->assertEquals($attributes->created_at, $attributes->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/characters/180548812/attributes/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $attributes = new CharacterAttribute([ + 'character_id' => 180548812, + 'charisma' => 3, + 'intelligence' => 10, + 'memory' => 5, + 'perception' => 2, + 'willpower' => 7, + 'bonus_remaps' => 2, + 'accrued_remap_cooldown_date' => '2015-03-23T11:37:00Z', + 'last_remap_date' => '2015-03-24T10:37:00Z', + ]); + $attributes->save(); + + $data = json_encode(new AttributeResource($attributes)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/skills/attributes.json', $data); + + $job = new Attributes($token); + $job->handle(); + + $attributes = CharacterAttribute::find(180548812); + + $data = json_encode(new AttributeResource($attributes)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/skills/attributes.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Attributes($token); + $job->handle(); + } + + /** + * @depends testHandleUpdated + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Attributes($token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Attributes($token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Attributes($token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Attributes($token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Attributes($token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Attributes($token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Skills/AttributeResource.php b/tests/Resources/Esi/Skills/AttributeResource.php new file mode 100644 index 00000000..a6aad076 --- /dev/null +++ b/tests/Resources/Esi/Skills/AttributeResource.php @@ -0,0 +1,49 @@ + $this->when(! is_null($this->accrued_remap_cooldown_date), carbon($this->accrued_remap_cooldown_date)->toIso8601ZuluString()), + 'bonus_remaps' => $this->when(! is_null($this->bonus_remaps), $this->bonus_remaps), + 'charisma' => $this->charisma, + 'intelligence' => $this->intelligence, + 'last_remap_date' => $this->when(! is_null($this->last_remap_date), carbon($this->last_remap_date)->toIso8601ZuluString()), + 'memory' => $this->memory, + 'perception' => $this->perception, + 'willpower' => $this->willpower + ]; + } +} diff --git a/tests/artifacts/skills/attributes.json b/tests/artifacts/skills/attributes.json new file mode 100644 index 00000000..112a3789 --- /dev/null +++ b/tests/artifacts/skills/attributes.json @@ -0,0 +1,7 @@ +{ + "charisma": 20, + "intelligence": 20, + "memory": 20, + "perception": 20, + "willpower": 20 +} \ No newline at end of file diff --git a/tests/database/migrations/2021_04_02_132637_create_character_attributes_table.php b/tests/database/migrations/2021_04_02_132637_create_character_attributes_table.php new file mode 100644 index 00000000..84a31c34 --- /dev/null +++ b/tests/database/migrations/2021_04_02_132637_create_character_attributes_table.php @@ -0,0 +1,66 @@ +bigInteger('character_id')->primary(); + $table->integer('charisma'); + $table->integer('intelligence'); + $table->integer('memory'); + $table->integer('perception'); + $table->integer('willpower'); + $table->integer('bonus_remaps')->nullable(); + $table->dateTime('last_remap_date')->nullable(); + $table->dateTime('accrued_remap_cooldown_date')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_attributes'); + } +} From 7ac21e7149be55475cea35f3e09f30235801404b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Fri, 2 Apr 2021 14:58:11 +0200 Subject: [PATCH 27/42] test(jobs): add character skill queue coverage --- src/Models/Skills/CharacterSkillQueue.php | 12 + tests/Jobs/Esi/Skills/SkillQueueTest.php | 439 ++++++++++++++++++ .../Esi/Skills/SkillQueueResource.php | 49 ++ tests/artifacts/skills/skillqueue.json | 23 + ...05_create_character_skill_queues_table.php | 71 +++ 5 files changed, 594 insertions(+) create mode 100644 tests/Jobs/Esi/Skills/SkillQueueTest.php create mode 100644 tests/Resources/Esi/Skills/SkillQueueResource.php create mode 100644 tests/artifacts/skills/skillqueue.json create mode 100644 tests/database/migrations/2021_04_02_134805_create_character_skill_queues_table.php diff --git a/src/Models/Skills/CharacterSkillQueue.php b/src/Models/Skills/CharacterSkillQueue.php index f90ff463..752cb6ed 100644 --- a/src/Models/Skills/CharacterSkillQueue.php +++ b/src/Models/Skills/CharacterSkillQueue.php @@ -96,6 +96,18 @@ class CharacterSkillQueue extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'finished_level' => 'integer', + 'level_end_sp' => 'integer', + 'level_start_sp' => 'integer', + 'queue_position' => 'integer', + 'skill_id' => 'integer', + 'training_start_sp' => 'integer', + ]; + /** * @param $value */ diff --git a/tests/Jobs/Esi/Skills/SkillQueueTest.php b/tests/Jobs/Esi/Skills/SkillQueueTest.php new file mode 100644 index 00000000..91870534 --- /dev/null +++ b/tests/Jobs/Esi/Skills/SkillQueueTest.php @@ -0,0 +1,439 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/skills/skillqueue.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skillqueue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Queue($token); + $job->handle(); + + $skill_queue = CharacterSkillQueue::all(); + + $data = json_encode(SkillQueueResource::collection($skill_queue)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/skills/skillqueue.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skillqueue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterSkillQueue::create([ + 'character_id' => 180548812, + 'finish_date' => '2018-07-01T19:37:39Z', + 'finished_level' => 3, + 'level_end_sp' => 3254654, + 'level_start_sp' => 56465, + 'queue_position' => 0, + 'skill_id' => 1, + 'start_date' => '2018-07-01T19:37:39Z', + 'training_start_sp' => 127, + ]); + + CharacterSkillQueue::create([ + 'character_id' => 180548812, + 'finish_date' => '2018-07-01T19:37:39Z', + 'finished_level' => 4, + 'level_end_sp' => 1248, + 'level_start_sp' => 215, + 'queue_position' => 1, + 'skill_id' => 1, + 'start_date' => '2018-07-01T19:37:39Z', + 'training_start_sp' => 127, + ]); + + CharacterSkillQueue::create([ + 'character_id' => 180548812, + 'finish_date' => '2018-07-01T19:37:39Z', + 'finished_level' => 2, + 'level_end_sp' => 6464564, + 'level_start_sp' => 5487, + 'queue_position' => 2, + 'skill_id' => 2, + 'start_date' => '2018-07-01T19:37:39Z', + 'training_start_sp' => 127, + ]); + + CharacterSkillQueue::create([ + 'character_id' => 180548812, + 'finish_date' => '2018-07-01T19:37:39Z', + 'finished_level' => 3, + 'level_end_sp' => 2112026549, + 'level_start_sp' => 6974981, + 'queue_position' => 3, + 'skill_id' => 2, + 'start_date' => '2018-07-01T19:37:39Z', + 'training_start_sp' => 68741, + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Queue($token); + $job->handle(); + + $skill_queue = CharacterSkillQueue::all(); + + foreach ($skill_queue as $queue) + $this->assertEquals($queue->created_at, $queue->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v2/characters/180548812/skillqueue/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skillqueue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterSkillQueue::create([ + 'character_id' => 180548812, + 'finish_date' => '2018-07-01T19:37:39Z', + 'finished_level' => 3, + 'level_end_sp' => 3254654, + 'level_start_sp' => 56465, + 'queue_position' => 0, + 'skill_id' => 1, + 'start_date' => '2018-07-01T19:37:39Z', + 'training_start_sp' => 127, + ]); + + CharacterSkillQueue::create([ + 'character_id' => 180548812, + 'finish_date' => '2018-07-01T19:37:39Z', + 'finished_level' => 4, + 'level_end_sp' => 1248, + 'level_start_sp' => 215, + 'queue_position' => 1, + 'skill_id' => 1, + 'start_date' => '2018-07-01T19:37:39Z', + 'training_start_sp' => 127, + ]); + + CharacterSkillQueue::create([ + 'character_id' => 180548812, + 'finish_date' => '2018-07-01T19:37:39Z', + 'finished_level' => 2, + 'level_end_sp' => 6464564, + 'level_start_sp' => 5487, + 'queue_position' => 2, + 'skill_id' => 2, + 'start_date' => '2018-07-01T19:37:39Z', + 'training_start_sp' => 127, + ]); + + CharacterSkillQueue::create([ + 'character_id' => 180548812, + 'finish_date' => '2018-07-01T19:37:39Z', + 'finished_level' => 3, + 'level_end_sp' => 2112026549, + 'level_start_sp' => 6974981, + 'queue_position' => 3, + 'skill_id' => 2, + 'start_date' => '2018-07-01T19:37:39Z', + 'training_start_sp' => 68741, + ]); + + $skill_queue = CharacterSkillQueue::all(); + $data = json_encode(SkillQueueResource::collection($skill_queue)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/skills/skillqueue.json', $data); + + $job = new Queue($token); + $job->handle(); + + $skill_queue = CharacterSkillQueue::all(); + $data = json_encode(SkillQueueResource::collection($skill_queue)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/skills/skillqueue.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skillqueue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Queue($token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skillqueue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Queue($token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skillqueue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Queue($token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skillqueue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Queue($token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skillqueue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Queue($token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skillqueue.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Queue($token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Queue($token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Skills/SkillQueueResource.php b/tests/Resources/Esi/Skills/SkillQueueResource.php new file mode 100644 index 00000000..f897af69 --- /dev/null +++ b/tests/Resources/Esi/Skills/SkillQueueResource.php @@ -0,0 +1,49 @@ + $this->when(! is_null($this->finish_date), carbon($this->finish_date)->toIso8601ZuluString()), + 'finished_level' => $this->finished_level, + 'level_end_sp' => $this->when(! is_null($this->level_end_sp), $this->level_end_sp), + 'level_start_sp' => $this->when(! is_null($this->level_start_sp), $this->level_start_sp), + 'queue_position' => $this->queue_position, + 'skill_id' => $this->skill_id, + 'start_date' => $this->when(! is_null($this->start_date), carbon($this->start_date)->toIso8601ZuluString()), + 'training_start_sp' => $this->when(! is_null($this->training_start_sp), $this->training_start_sp), + ]; + } +} diff --git a/tests/artifacts/skills/skillqueue.json b/tests/artifacts/skills/skillqueue.json new file mode 100644 index 00000000..7e70c140 --- /dev/null +++ b/tests/artifacts/skills/skillqueue.json @@ -0,0 +1,23 @@ +[ + { + "finish_date": "2016-06-29T10:47:00Z", + "finished_level": 3, + "queue_position": 0, + "skill_id": 1, + "start_date": "2016-06-29T10:46:00Z" + }, + { + "finish_date": "2016-07-15T10:47:00Z", + "finished_level": 4, + "queue_position": 1, + "skill_id": 1, + "start_date": "2016-06-29T10:47:00Z" + }, + { + "finish_date": "2016-08-30T10:47:00Z", + "finished_level": 2, + "queue_position": 2, + "skill_id": 2, + "start_date": "2016-07-15T10:47:00Z" + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_04_02_134805_create_character_skill_queues_table.php b/tests/database/migrations/2021_04_02_134805_create_character_skill_queues_table.php new file mode 100644 index 00000000..ac76fee9 --- /dev/null +++ b/tests/database/migrations/2021_04_02_134805_create_character_skill_queues_table.php @@ -0,0 +1,71 @@ +bigIncrements('id'); + $table->bigInteger('character_id'); + $table->integer('skill_id'); + $table->dateTime('finish_date')->nullable(); + $table->dateTime('start_date')->nullable(); + $table->integer('finished_level'); + $table->integer('queue_position'); + $table->integer('training_start_sp')->nullable(); + $table->integer('level_end_sp')->nullable(); + $table->integer('level_start_sp')->nullable(); + + $table->unique(['character_id', 'queue_position']); + $table->index(['character_id']); + $table->index(['queue_position']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_skill_queues'); + } +} From efeab85917149224a2f6e95ca3bb745d929de40b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Fri, 2 Apr 2021 14:58:26 +0200 Subject: [PATCH 28/42] test(jobs): add character skills coverage --- src/Models/Character/CharacterInfoSkill.php | 8 + src/Models/Character/CharacterSkill.php | 10 + tests/Jobs/Esi/Skills/SkillsTest.php | 439 ++++++++++++++++++ tests/Resources/Esi/Skills/SkillResource.php | 45 ++ tests/Resources/Esi/Skills/SkillsResource.php | 44 ++ tests/artifacts/skills/skills.json | 17 + ...639_create_character_info_skills_table.php | 60 +++ ...2_141752_create_character_skills_table.php | 67 +++ ...21_04_02_142040_create_inv_types_table.php | 72 +++ 9 files changed, 762 insertions(+) create mode 100644 tests/Jobs/Esi/Skills/SkillsTest.php create mode 100644 tests/Resources/Esi/Skills/SkillResource.php create mode 100644 tests/Resources/Esi/Skills/SkillsResource.php create mode 100644 tests/artifacts/skills/skills.json create mode 100644 tests/database/migrations/2021_04_02_141639_create_character_info_skills_table.php create mode 100644 tests/database/migrations/2021_04_02_141752_create_character_skills_table.php create mode 100644 tests/database/migrations/2021_04_02_142040_create_inv_types_table.php diff --git a/src/Models/Character/CharacterInfoSkill.php b/src/Models/Character/CharacterInfoSkill.php index 5b4d2d2a..5cc314be 100644 --- a/src/Models/Character/CharacterInfoSkill.php +++ b/src/Models/Character/CharacterInfoSkill.php @@ -40,6 +40,14 @@ class CharacterInfoSkill extends Model */ protected $primaryKey = 'character_id'; + /** + * @var array + */ + protected $casts = [ + 'total_sp' => 'integer', + 'unallocated_sp' => 'integer', + ]; + /** * @var bool */ diff --git a/src/Models/Character/CharacterSkill.php b/src/Models/Character/CharacterSkill.php index 419928a6..b18f959c 100644 --- a/src/Models/Character/CharacterSkill.php +++ b/src/Models/Character/CharacterSkill.php @@ -71,6 +71,16 @@ class CharacterSkill extends Model */ protected static $unguarded = true; + /** + * @var array + */ + protected $casts = [ + 'active_skill_level' => 'integer', + 'skill_id' => 'integer', + 'skillpoints_in_skill' => 'integer', + 'trained_skill_level' => 'integer', + ]; + /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ diff --git a/tests/Jobs/Esi/Skills/SkillsTest.php b/tests/Jobs/Esi/Skills/SkillsTest.php new file mode 100644 index 00000000..b96a7c96 --- /dev/null +++ b/tests/Jobs/Esi/Skills/SkillsTest.php @@ -0,0 +1,439 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/skills/skills.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $character = CharacterInfo::create([ + 'character_id' => 180548812, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + + $job = new Skills($token); + $job->handle(); + + $data = json_encode(SkillsResource::make($character)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/skills/skills.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterInfo::create([ + 'character_id' => 180548812, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + + CharacterInfoSkill::create([ + 'character_id' => 180548812, + 'total_sp' => 15465444, + 'unallocated_sp' => 900, + ]); + + CharacterSkill::create([ + 'character_id' => 180548812, + 'active_skill_level' => 1, + 'skill_id' => 1, + 'skillpoints_in_skill' => 165498, + 'trained_skill_level' => 1, + ]); + + CharacterSkill::create([ + 'character_id' => 180548812, + 'active_skill_level' => 1, + 'skill_id' => 2, + 'skillpoints_in_skill' => 10000, + 'trained_skill_level' => 1, + ]); + + CharacterSkill::create([ + 'character_id' => 180548812, + 'active_skill_level' => 4, + 'skill_id' => 3, + 'skillpoints_in_skill' => 574874941, + 'trained_skill_level' => 3, + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Skills($token); + $job->handle(); + + $skills = CharacterSkill::all(); + $this->assertCount(3, $skills); + + foreach ($skills as $skill) + $this->assertEquals($skill->created_at, $skill->updated_at); + + $info = CharacterInfoSkill::find(180548812); + $this->assertEquals($info->created_at, $info->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v4/characters/180548812/skills/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $character = CharacterInfo::create([ + 'character_id' => 180548812, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + + CharacterInfoSkill::create([ + 'character_id' => 180548812, + 'total_sp' => 15465444, + 'unallocated_sp' => 900, + ]); + + CharacterSkill::create([ + 'character_id' => 180548812, + 'active_skill_level' => 1, + 'skill_id' => 1, + 'skillpoints_in_skill' => 165498, + 'trained_skill_level' => 1, + ]); + + CharacterSkill::create([ + 'character_id' => 180548812, + 'active_skill_level' => 1, + 'skill_id' => 2, + 'skillpoints_in_skill' => 10000, + 'trained_skill_level' => 1, + ]); + + CharacterSkill::create([ + 'character_id' => 180548812, + 'active_skill_level' => 4, + 'skill_id' => 3, + 'skillpoints_in_skill' => 574874941, + 'trained_skill_level' => 3, + ]); + + $data = json_encode(SkillsResource::make($character)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/skills/skills.json', $data); + + $job = new Skills($token); + $job->handle(); + + $character->load('skills', 'skillpoints'); + $data = json_encode(SkillsResource::make($character)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/skills/skills.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Skills($token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Skills($token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Skills($token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Skills($token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Skills($token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-skills.read_skills.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Skills($token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Skills($token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Skills/SkillResource.php b/tests/Resources/Esi/Skills/SkillResource.php new file mode 100644 index 00000000..69741510 --- /dev/null +++ b/tests/Resources/Esi/Skills/SkillResource.php @@ -0,0 +1,45 @@ + $this->active_skill_level, + 'skill_id' => $this->skill_id, + 'skillpoints_in_skill' => $this->skillpoints_in_skill, + 'trained_skill_level' => $this->trained_skill_level, + ]; + } +} diff --git a/tests/Resources/Esi/Skills/SkillsResource.php b/tests/Resources/Esi/Skills/SkillsResource.php new file mode 100644 index 00000000..fed5844b --- /dev/null +++ b/tests/Resources/Esi/Skills/SkillsResource.php @@ -0,0 +1,44 @@ + SkillResource::collection($this->skills), + 'total_sp' => $this->skillpoints->total_sp, + 'unallocated_sp' => $this->when($this->skillpoints->unallocated_sp, $this->skillpoints->unallocated_sp), + ]; + } +} diff --git a/tests/artifacts/skills/skills.json b/tests/artifacts/skills/skills.json new file mode 100644 index 00000000..25375fbc --- /dev/null +++ b/tests/artifacts/skills/skills.json @@ -0,0 +1,17 @@ +{ + "skills": [ + { + "active_skill_level": 3, + "skill_id": 1, + "skillpoints_in_skill": 10000, + "trained_skill_level": 4 + }, + { + "active_skill_level": 1, + "skill_id": 2, + "skillpoints_in_skill": 10000, + "trained_skill_level": 1 + } + ], + "total_sp": 20000 +} \ No newline at end of file diff --git a/tests/database/migrations/2021_04_02_141639_create_character_info_skills_table.php b/tests/database/migrations/2021_04_02_141639_create_character_info_skills_table.php new file mode 100644 index 00000000..3914de46 --- /dev/null +++ b/tests/database/migrations/2021_04_02_141639_create_character_info_skills_table.php @@ -0,0 +1,60 @@ +bigInteger('character_id')->primary(); + $table->bigInteger('total_sp'); + $table->bigInteger('unallocated_sp')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_info_skills'); + } +} diff --git a/tests/database/migrations/2021_04_02_141752_create_character_skills_table.php b/tests/database/migrations/2021_04_02_141752_create_character_skills_table.php new file mode 100644 index 00000000..364962f5 --- /dev/null +++ b/tests/database/migrations/2021_04_02_141752_create_character_skills_table.php @@ -0,0 +1,67 @@ +bigIncrements('id'); + $table->bigInteger('character_id'); + $table->integer('skill_id'); + $table->integer('active_skill_level'); + $table->bigInteger('skillpoints_in_skill'); + $table->integer('trained_skill_level'); + + $table->unique(['character_id', 'skill_id']); + $table->index(['character_id']); + $table->index(['skill_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_skills'); + } +} diff --git a/tests/database/migrations/2021_04_02_142040_create_inv_types_table.php b/tests/database/migrations/2021_04_02_142040_create_inv_types_table.php new file mode 100644 index 00000000..edcdec6d --- /dev/null +++ b/tests/database/migrations/2021_04_02_142040_create_inv_types_table.php @@ -0,0 +1,72 @@ +integer('typeID')->primary(); + $table->integer('groupID')->nullable(); + $table->string('typeName')->nullable(); + $table->text('description')->nullable(); + $table->double('mass')->nullable(); + $table->double('volume')->nullable(); + $table->double('capacity')->nullable(); + $table->integer('portionSize')->nullable(); + $table->integer('raceID')->nullable(); + $table->decimal('basePrice')->nullable(); + $table->boolean('published')->nullable(); + $table->integer('marketGroupID')->nullable(); + $table->integer('iconID')->nullable(); + $table->integer('soundID')->nullable(); + $table->integer('graphicID')->nullable(); + + $table->index(['groupID']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('invTypes'); + } +} From f639fea6af975b45661f5ac64fffd5c5c037283f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Fri, 2 Apr 2021 15:22:06 +0200 Subject: [PATCH 29/42] style: add missing semicolon on casts attribute --- src/Models/Character/CharacterBlueprint.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Models/Character/CharacterBlueprint.php b/src/Models/Character/CharacterBlueprint.php index 5fb16aae..17cd6ed9 100644 --- a/src/Models/Character/CharacterBlueprint.php +++ b/src/Models/Character/CharacterBlueprint.php @@ -47,13 +47,16 @@ class CharacterBlueprint extends Model */ protected $primaryKey = 'item_id'; + /** + * @var string[] + */ protected $casts = [ 'location_id' => 'integer', 'material_efficiency' => 'integer', 'quantity' => 'integer', 'runs' => 'integer', 'time_efficiency' => 'integer', - 'type_id' => 'integer' + 'type_id' => 'integer', ]; /** From 1c8ecda3172e585220b641761fafc4f7539e0a35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Fri, 2 Apr 2021 15:24:14 +0200 Subject: [PATCH 30/42] revert: restore posix dependency --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index a8f8e64e..686f739c 100644 --- a/composer.json +++ b/composer.json @@ -29,6 +29,7 @@ "doctrine/dbal": "^2.9", "softcreatr/jsonpath": "^0.7", "ext-json": "*", + "ext-posix": "*", "ext-redis": "*" }, "require-dev": { From 4c1b997153d161c9ab3c4f663a436aaeae45cdf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sun, 4 Apr 2021 19:20:08 +0200 Subject: [PATCH 31/42] test: add clones coverage --- src/Jobs/Character/Stats.php | 94 ---- src/Models/Clones/CharacterClone.php | 7 + src/Models/Clones/CharacterImplant.php | 7 + src/Models/Clones/CharacterJumpClone.php | 2 + tests/Jobs/Esi/Clones/ClonesTest.php | 427 ++++++++++++++++++ tests/Jobs/Esi/Clones/ImplantsTest.php | 406 +++++++++++++++++ tests/Resources/Esi/Clones/CloneResource.php | 49 ++ .../Esi/Clones/JumpCloneResource.php | 46 ++ tests/artifacts/clones/clones.json | 16 + tests/artifacts/clones/implants.json | 5 + ...4_184448_create_character_clones_table.php | 62 +++ ...801_create_character_jump_clones_table.php | 68 +++ ...191129_create_character_implants_table.php | 63 +++ 13 files changed, 1158 insertions(+), 94 deletions(-) delete mode 100644 src/Jobs/Character/Stats.php create mode 100644 tests/Jobs/Esi/Clones/ClonesTest.php create mode 100644 tests/Jobs/Esi/Clones/ImplantsTest.php create mode 100644 tests/Resources/Esi/Clones/CloneResource.php create mode 100644 tests/Resources/Esi/Clones/JumpCloneResource.php create mode 100644 tests/artifacts/clones/clones.json create mode 100644 tests/artifacts/clones/implants.json create mode 100644 tests/database/migrations/2021_04_04_184448_create_character_clones_table.php create mode 100644 tests/database/migrations/2021_04_04_184801_create_character_jump_clones_table.php create mode 100644 tests/database/migrations/2021_04_04_191129_create_character_implants_table.php diff --git a/src/Jobs/Character/Stats.php b/src/Jobs/Character/Stats.php deleted file mode 100644 index 41e8ea76..00000000 --- a/src/Jobs/Character/Stats.php +++ /dev/null @@ -1,94 +0,0 @@ -retrieve([ - 'character_id' => $this->getCharacterId(), - ]); - - if ($stats->isCachedLoad() && - CharacterStats::where('character_id', $this->getCharacterId())->count() > 0) - return; - - // Process each years aggregate - collect($stats)->each(function ($aggregate) { - - // Separate stats by categories - foreach (['character', 'combat', 'industry', 'inventory', 'isk', 'market', - 'mining', 'module', 'orbital', 'pve', 'social', 'travel', ] as $category) { - - CharacterStats::firstOrCreate([ - 'character_id' => $this->getCharacterId(), - 'year' => $aggregate->year, - 'category' => $category, - 'stats' => isset($aggregate->$category) ? - json_encode($aggregate->$category) : null, - ]); - } - }); - } -} diff --git a/src/Models/Clones/CharacterClone.php b/src/Models/Clones/CharacterClone.php index 00414c28..d7009710 100644 --- a/src/Models/Clones/CharacterClone.php +++ b/src/Models/Clones/CharacterClone.php @@ -44,4 +44,11 @@ class CharacterClone extends Model * @var string */ protected $primaryKey = 'character_id'; + + /** + * @var string[] + */ + protected $casts = [ + 'home_location_id', + ]; } diff --git a/src/Models/Clones/CharacterImplant.php b/src/Models/Clones/CharacterImplant.php index 446b9d32..585c8496 100644 --- a/src/Models/Clones/CharacterImplant.php +++ b/src/Models/Clones/CharacterImplant.php @@ -36,6 +36,13 @@ class CharacterImplant extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'type_id' => 'integer', + ]; + /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ diff --git a/src/Models/Clones/CharacterJumpClone.php b/src/Models/Clones/CharacterJumpClone.php index 3e76705b..5d974121 100644 --- a/src/Models/Clones/CharacterJumpClone.php +++ b/src/Models/Clones/CharacterJumpClone.php @@ -87,6 +87,8 @@ class CharacterJumpClone extends Model */ protected $casts = [ 'implants' => 'array', + 'jump_clone_id' => 'integer', + 'location_id' => 'integer', ]; /** diff --git a/tests/Jobs/Esi/Clones/ClonesTest.php b/tests/Jobs/Esi/Clones/ClonesTest.php new file mode 100644 index 00000000..391b1048 --- /dev/null +++ b/tests/Jobs/Esi/Clones/ClonesTest.php @@ -0,0 +1,427 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/clones/clones.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_clones.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $character = new CharacterInfo([ + 'character_id' => 180548812, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + $character->save(); + + $job = new Clones($token); + $job->handle(); + + $data = json_encode(CloneResource::make($character)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/clones/clones.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_clones.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $character = new CharacterInfo([ + 'character_id' => 180548812, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + $character->save(); + + CharacterClone::create([ + 'character_id' => 180548812, + 'home_location_type' => 'station', + 'home_location_id' => 60000064, + 'last_clone_jump_date' => '2015-03-24T11:37:00Z', + 'last_station_change_date' => '2015-03-24T11:39:00Z', + ]); + + CharacterJumpClone::create([ + 'character_id' => 180548812, + 'jump_clone_id' => 12345, + 'location_id' => 60000063, + 'location_type' => 'station', + 'implants' => [], + ]); + + CharacterJumpClone::create([ + 'character_id' => 180548812, + 'jump_clone_id' => 126789, + 'location_id' => 60000061, + 'location_type' => 'station', + 'implants' => [ + 22118, + ], + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Clones($token); + $job->handle(); + + $this->assertCount(2, $character->jump_clones); + $this->assertEquals($character->clone->created_at, $character->clone->updated_at); + foreach ($character->jump_clones as $clone) + $this->assertEquals($clone->created_at, $clone->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v3/characters/180548812/clones/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_clones.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $info = new CharacterInfo([ + 'character_id' => 180548812, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + $info->save(); + + CharacterClone::create([ + 'character_id' => 180548812, + 'home_location_type' => 'station', + 'home_location_id' => 60000064, + 'last_clone_jump_date' => '2015-03-24T11:37:00Z', + 'last_station_change_date' => '2015-03-24T11:39:00Z', + ]); + + CharacterJumpClone::create([ + 'character_id' => 180548812, + 'jump_clone_id' => 12345, + 'location_id' => 60000063, + 'location_type' => 'station', + 'implants' => [], + ]); + + CharacterJumpClone::create([ + 'character_id' => 180548812, + 'jump_clone_id' => 126789, + 'location_id' => 60000061, + 'location_type' => 'station', + 'implants' => [ + 22118, + ], + ]); + + $data = json_encode(CloneResource::make($info)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/clones/clones.json', $data); + + $job = new Clones($token); + $job->handle(); + + $info->load('clone', 'jump_clones'); + $data = json_encode(CloneResource::make($info)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/clones/clones.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_clones.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Clones($token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_clones.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Clones($token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_clones.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Clones($token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_clones.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Clones($token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_clones.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Clones($token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_clones.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Clones($token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Clones($token); + $job->handle(); + } +} diff --git a/tests/Jobs/Esi/Clones/ImplantsTest.php b/tests/Jobs/Esi/Clones/ImplantsTest.php new file mode 100644 index 00000000..f8c95ea6 --- /dev/null +++ b/tests/Jobs/Esi/Clones/ImplantsTest.php @@ -0,0 +1,406 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/clones/implants.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_implants.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $info = new CharacterInfo([ + 'character_id' => 180548812, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + $info->save(); + + $job = new Implants($token); + $job->handle(); + + $data = json_encode($info->implants->pluck('type_id')->toArray()); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/clones/implants.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_implants.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $info = new CharacterInfo([ + 'character_id' => 180548812, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + $info->save(); + + CharacterImplant::create([ + 'character_id' => 180548812, + 'type_id' => 65465, + ]); + CharacterImplant::create([ + 'character_id' => 180548812, + 'type_id' => 21587, + ]); + CharacterImplant::create([ + 'character_id' => 180548812, + 'type_id' => 126357, + ]); + CharacterImplant::create([ + 'character_id' => 180548812, + 'type_id' => 45646, + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Implants($token); + $job->handle(); + + $this->assertCount(4, $info->implants); + foreach ($info->implants as $implant) + $this->assertEquals($implant->created_at, $implant->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/characters/180548812/implants/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_implants.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $info = new CharacterInfo([ + 'character_id' => 180548812, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + $info->save(); + + CharacterImplant::create([ + 'character_id' => 180548812, + 'type_id' => 65465, + ]); + CharacterImplant::create([ + 'character_id' => 180548812, + 'type_id' => 21587, + ]); + CharacterImplant::create([ + 'character_id' => 180548812, + 'type_id' => 126357, + ]); + CharacterImplant::create([ + 'character_id' => 180548812, + 'type_id' => 45646, + ]); + + $data = json_encode($info->implants->pluck('type_id')->toArray()); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/clones/implants.json', $data); + + $job = new Implants($token); + $job->handle(); + + $info->load('implants'); + $data = json_encode($info->implants->pluck('type_id')->toArray()); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/clones/implants.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_implants.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Implants($token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_implants.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Implants($token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_implants.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Implants($token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_implants.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Implants($token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_implants.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Implants($token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-clones.read_implants.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Implants($token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Implants($token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Clones/CloneResource.php b/tests/Resources/Esi/Clones/CloneResource.php new file mode 100644 index 00000000..990e4583 --- /dev/null +++ b/tests/Resources/Esi/Clones/CloneResource.php @@ -0,0 +1,49 @@ + $this->when($this->clone, [ + 'location_id' => $this->when($this->clone->home_location_id, (int) $this->clone->home_location_id), + 'location_type' => $this->when($this->clone->home_location_type, $this->clone->home_location_type), + ]), + 'jump_clones' => JumpCloneResource::collection($this->jump_clones), + 'last_clone_jump_date' => $this->when($this->clone->last_clone_jump_date, $this->clone->last_clone_jump_date), + 'last_station_change_date' => $this->when($this->clone->last_station_change_date, $this->clone->last_station_change_date), + ]; + } +} diff --git a/tests/Resources/Esi/Clones/JumpCloneResource.php b/tests/Resources/Esi/Clones/JumpCloneResource.php new file mode 100644 index 00000000..528ffa34 --- /dev/null +++ b/tests/Resources/Esi/Clones/JumpCloneResource.php @@ -0,0 +1,46 @@ + $this->implants, + 'jump_clone_id' => $this->jump_clone_id, + 'location_id' => $this->location_id, + 'location_type' => $this->location_type, + 'name' => $this->when($this->name, $this->name), + ]; + } +} diff --git a/tests/artifacts/clones/clones.json b/tests/artifacts/clones/clones.json new file mode 100644 index 00000000..125faa56 --- /dev/null +++ b/tests/artifacts/clones/clones.json @@ -0,0 +1,16 @@ +{ + "home_location": { + "location_id": 1021348135816, + "location_type": "structure" + }, + "jump_clones": [ + { + "implants": [ + 22118 + ], + "jump_clone_id": 12345, + "location_id": 60003463, + "location_type": "station" + } + ] +} \ No newline at end of file diff --git a/tests/artifacts/clones/implants.json b/tests/artifacts/clones/implants.json new file mode 100644 index 00000000..d9303093 --- /dev/null +++ b/tests/artifacts/clones/implants.json @@ -0,0 +1,5 @@ +[ + 1, + 2, + 3 +] \ No newline at end of file diff --git a/tests/database/migrations/2021_04_04_184448_create_character_clones_table.php b/tests/database/migrations/2021_04_04_184448_create_character_clones_table.php new file mode 100644 index 00000000..c9e17493 --- /dev/null +++ b/tests/database/migrations/2021_04_04_184448_create_character_clones_table.php @@ -0,0 +1,62 @@ +bigInteger('character_id'); + $table->string('home_location_type')->nullable(); + $table->bigInteger('home_location_id')->nullable(); + $table->dateTime('last_clone_jump_date')->nullable(); + $table->dateTime('last_station_change_date')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_clones'); + } +} diff --git a/tests/database/migrations/2021_04_04_184801_create_character_jump_clones_table.php b/tests/database/migrations/2021_04_04_184801_create_character_jump_clones_table.php new file mode 100644 index 00000000..42de0147 --- /dev/null +++ b/tests/database/migrations/2021_04_04_184801_create_character_jump_clones_table.php @@ -0,0 +1,68 @@ +bigIncrements('id'); + $table->bigInteger('character_id'); + $table->integer('jump_clone_id'); + $table->string('location_type'); + $table->bigInteger('location_id'); + $table->json('implants'); + $table->string('name')->nullable(); + + $table->unique(['character_id', 'jump_clone_id']); + $table->index(['character_id']); + $table->index(['location_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_jump_clones'); + } +} diff --git a/tests/database/migrations/2021_04_04_191129_create_character_implants_table.php b/tests/database/migrations/2021_04_04_191129_create_character_implants_table.php new file mode 100644 index 00000000..5a848d9a --- /dev/null +++ b/tests/database/migrations/2021_04_04_191129_create_character_implants_table.php @@ -0,0 +1,63 @@ +bigIncrements('id'); + $table->bigInteger('character_id'); + $table->integer('type_id'); + + $table->unique(['character_id', 'type_id']); + $table->index(['character_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_implants'); + } +} From af233ad3574979ecc4347c71aeb4df72b5755184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sun, 4 Apr 2021 21:19:54 +0200 Subject: [PATCH 32/42] test: add alliances info coverage --- src/Models/Alliances/Alliance.php | 10 + tests/Jobs/Esi/Alliances/InfoTest.php | 216 ++++++++++++++++++ .../Esi/Alliances/AllianceResource.php | 48 ++++ tests/artifacts/alliances/info.json | 8 + ...21_04_04_195120_create_alliances_table.php | 65 ++++++ 5 files changed, 347 insertions(+) create mode 100644 tests/Jobs/Esi/Alliances/InfoTest.php create mode 100644 tests/Resources/Esi/Alliances/AllianceResource.php create mode 100644 tests/artifacts/alliances/info.json create mode 100644 tests/database/migrations/2021_04_04_195120_create_alliances_table.php diff --git a/src/Models/Alliances/Alliance.php b/src/Models/Alliances/Alliance.php index 8a83e2ba..ff59d51e 100644 --- a/src/Models/Alliances/Alliance.php +++ b/src/Models/Alliances/Alliance.php @@ -50,6 +50,16 @@ class Alliance extends Model */ protected $primaryKey = 'alliance_id'; + /** + * @var array + */ + protected $casts = [ + 'creator_corporation_id' => 'integer', + 'creator_id' => 'integer', + 'executor_corporation_id' => 'integer', + 'faction_id' => 'integer', + ]; + /** * @param $value */ diff --git a/tests/Jobs/Esi/Alliances/InfoTest.php b/tests/Jobs/Esi/Alliances/InfoTest.php new file mode 100644 index 00000000..aedf4330 --- /dev/null +++ b/tests/Jobs/Esi/Alliances/InfoTest.php @@ -0,0 +1,216 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/alliances/info.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $job = new Info(99000001); + $job->handle(); + + $alliance = Alliance::find(99000001); + + $data = json_encode(AllianceResource::make($alliance)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/alliances/info.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + Alliance::create([ + 'alliance_id' => 99000001, + 'creator_corporation_id' => 45678, + 'creator_id' => 12345, + 'date_founded' => '2016-06-26T21:00:00Z', + 'name' => 'C C P Alliance', + 'ticker' => '', + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Info(99000001); + $job->handle(); + + $alliances = Alliance::all(); + + $this->assertCount(1, $alliances); + foreach ($alliances as $alliance) + $this->assertEquals($alliance->created_at, $alliance->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v3/alliances/99000001/', 'datasource=tranquility'); + + Alliance::create([ + 'alliance_id' => 99000001, + 'creator_corporation_id' => 45678, + 'creator_id' => 12345, + 'date_founded' => '2016-06-26T21:00:00Z', + 'name' => 'C C P Alliance', + 'ticker' => '', + ]); + + $alliance = Alliance::find(99000001); + + $data = json_encode(AllianceResource::make($alliance)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/alliances/info.json', $data); + + $job = new Info(99000001); + $job->handle(); + + $alliance = Alliance::find(99000001); + + $data = json_encode(AllianceResource::make($alliance)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/alliances/info.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $job = new Info(404); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $job = new Info(420); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $job = new Info(500); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $job = new Info(503); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $job = new Info(504); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Alliances/AllianceResource.php b/tests/Resources/Esi/Alliances/AllianceResource.php new file mode 100644 index 00000000..f930c520 --- /dev/null +++ b/tests/Resources/Esi/Alliances/AllianceResource.php @@ -0,0 +1,48 @@ + $this->creator_corporation_id, + 'creator_id' => $this->creator_id, + 'date_founded' => carbon($this->date_founded)->toIso8601ZuluString(), + 'executor_corporation_id' => $this->when($this->executor_corporation_id, $this->executor_corporation_id), + 'faction_id' => $this->when($this->faction_id, $this->faction_id), + 'name' => $this->name, + 'ticker' => $this->ticker, + ]; + } +} diff --git a/tests/artifacts/alliances/info.json b/tests/artifacts/alliances/info.json new file mode 100644 index 00000000..8eaefd39 --- /dev/null +++ b/tests/artifacts/alliances/info.json @@ -0,0 +1,8 @@ +{ + "creator_corporation_id": 45678, + "creator_id": 12345, + "date_founded": "2016-06-26T21:00:00Z", + "executor_corporation_id": 98356193, + "name": "C C P Alliance", + "ticker": "" +} \ No newline at end of file diff --git a/tests/database/migrations/2021_04_04_195120_create_alliances_table.php b/tests/database/migrations/2021_04_04_195120_create_alliances_table.php new file mode 100644 index 00000000..6ff44e99 --- /dev/null +++ b/tests/database/migrations/2021_04_04_195120_create_alliances_table.php @@ -0,0 +1,65 @@ +integer('alliance_id'); + $table->bigInteger('creator_corporation_id'); + $table->bigInteger('creator_id'); + $table->dateTime('date_founded'); + $table->bigInteger('executor_corporation_id')->nullable(); + $table->integer('faction_id')->nullable(); + $table->string('name'); + $table->string('ticker'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('alliances'); + } +} From 943a56dacb57b9b152b016fb6bec0578c1daa295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sun, 4 Apr 2021 21:22:37 +0200 Subject: [PATCH 33/42] refactor(relationship): use pivot table to link alliance together with corporation --- src/Commands/Esi/Update/PublicInfo.php | 64 ++++++++++++++++++- src/Jobs/Alliances/Members.php | 22 +++---- src/Jobs/Universe/Names.php | 38 ++++------- src/Models/Alliances/Alliance.php | 11 ++++ .../Alliance}/AllianceMember.php | 21 +++--- 5 files changed, 104 insertions(+), 52 deletions(-) rename src/{Models/Alliances => Pivot/Alliance}/AllianceMember.php (55%) diff --git a/src/Commands/Esi/Update/PublicInfo.php b/src/Commands/Esi/Update/PublicInfo.php index 098aef45..60741c91 100644 --- a/src/Commands/Esi/Update/PublicInfo.php +++ b/src/Commands/Esi/Update/PublicInfo.php @@ -28,6 +28,10 @@ use Seat\Eveapi\Jobs\Universe\Names; use Seat\Eveapi\Models\Character\CharacterInfo; use Seat\Eveapi\Models\Corporation\CorporationInfo; +use Seat\Eveapi\Models\Wallet\CharacterWalletJournal; +use Seat\Eveapi\Models\Wallet\CharacterWalletTransaction; +use Seat\Eveapi\Models\Wallet\CorporationWalletJournal; +use Seat\Eveapi\Models\Wallet\CorporationWalletTransaction; /** * Class PublicInfo. @@ -54,7 +58,11 @@ class PublicInfo extends Command */ public function handle() { - Names::dispatch(); + $entities_list = $this->buildUniqueEntitiesIdList(); + + $entities_list->chunk(Names::ITEMS_LIMIT)->each(function ($chunk) { + Names::dispatch($chunk); + }); CharacterInfo::doesntHave('refresh_token')->each(function ($character) { (new Character($character->character_id))->fire(); @@ -64,4 +72,58 @@ public function handle() (new Corporation($corporation->corporation_id))->fire(); }); } + + /** + * @return array + */ + private function buildUniqueEntitiesIdList() + { + $entities_id = collect(); + + // collect entries from character wallet + $entities_id->push(CharacterWalletJournal::select('first_party_id') + ->whereNotNull('first_party_id') + ->distinct() + ->get() + ->pluck('first_party_id') + ->toArray()); + + $entities_id->push(CharacterWalletJournal::select('second_party_id') + ->whereNotNull('second_party_id') + ->distinct() + ->get() + ->pluck('second_party_id') + ->toArray()); + + $entities_id->push(CharacterWalletTransaction::select('client_id') + ->whereNotNull('client_id') + ->distinct() + ->get() + ->pluck('client_id') + ->toArray()); + + // collect entities from corporation wallet + $entities_id->push(CorporationWalletJournal::select('first_party_id') + ->whereNotNull('first_party_id') + ->distinct() + ->get() + ->pluck('first_party_id') + ->toArray()); + + $entities_id->push(CorporationWalletJournal::select('second_party_id') + ->whereNotNull('second_party_id') + ->distinct() + ->get() + ->pluck('second_party_id') + ->toArray()); + + $entities_id->push(CorporationWalletTransaction::select('client_id') + ->whereNotNull('client_id') + ->distinct() + ->get() + ->pluck('client_id') + ->toArray()); + + return $entities_id->unique()->toArray(); + } } diff --git a/src/Jobs/Alliances/Members.php b/src/Jobs/Alliances/Members.php index a0ae980c..23fdf189 100644 --- a/src/Jobs/Alliances/Members.php +++ b/src/Jobs/Alliances/Members.php @@ -23,7 +23,8 @@ namespace Seat\Eveapi\Jobs\Alliances; use Seat\Eveapi\Jobs\EsiBase; -use Seat\Eveapi\Models\Alliances\AllianceMember; +use Seat\Eveapi\Jobs\Universe\Names; +use Seat\Eveapi\Models\Alliances\Alliance; /** * Class Members. @@ -78,22 +79,15 @@ public function handle() 'alliance_id' => $this->alliance_id, ]); - if ($corporations->isCachedLoad() && AllianceMember::where('alliance_id', $this->alliance_id)->count() > 0) - return; - - $corporation_ids = collect($corporations); + $alliance = Alliance::find($this->alliance_id); - $corporation_ids->each(function ($corporation_id) { + if ($corporations->isCachedLoad() && $alliance->members->count() > 0) + return; - AllianceMember::firstOrCreate([ - 'alliance_id' => $this->alliance_id, - 'corporation_id' => $corporation_id, - ]); - }); + $name_job = new Names((array) $corporations); + $name_job->handle(); - AllianceMember::where('alliance_id', $this->alliance_id) - ->whereNotIn('corporation_id', $corporation_ids->flatten()->all()) - ->delete(); + $alliance->members()->sync($corporations); } /** diff --git a/src/Jobs/Universe/Names.php b/src/Jobs/Universe/Names.php index c9e5bd4c..54e0ad1c 100644 --- a/src/Jobs/Universe/Names.php +++ b/src/Jobs/Universe/Names.php @@ -36,8 +36,10 @@ class Names extends EsiBase /** * The maximum number of entity ids we can request resolution for. + * + * @var int */ - protected $items_id_limit = 1000; + const ITEMS_LIMIT = 1000; /** * @var string @@ -69,6 +71,15 @@ class Names extends EsiBase */ protected $existing_entity_ids; + /** + * Names constructor. + * @param array $entity_ids + */ + public function __construct(array $entity_ids) + { + $this->entity_ids = collect($entity_ids); + } + /** * Execute the job. * @@ -82,30 +93,7 @@ public function handle() ->get() ->pluck('entity_id'); - $this->entity_ids = collect(); - - $this->entity_ids->push(CharacterWalletJournal::select('first_party_id') - ->whereNotNull('first_party_id') - ->distinct() - ->get() - ->pluck('first_party_id') - ->toArray()); - - $this->entity_ids->push(CharacterWalletJournal::select('second_party_id') - ->whereNotNull('second_party_id') - ->distinct() - ->get() - ->pluck('second_party_id') - ->toArray()); - - $this->entity_ids->push(CharacterWalletTransaction::select('client_id') - ->whereNotNull('client_id') - ->distinct() - ->get() - ->pluck('client_id') - ->toArray()); - - $this->entity_ids->flatten()->diff($this->existing_entity_ids)->values()->chunk($this->items_id_limit)->each(function ($chunk) { + $this->entity_ids->flatten()->diff($this->existing_entity_ids)->values()->chunk(self::ITEMS_LIMIT)->each(function ($chunk) { $this->request_body = collect($chunk->values()->all())->unique()->values()->all(); diff --git a/src/Models/Alliances/Alliance.php b/src/Models/Alliances/Alliance.php index ff59d51e..a2a37612 100644 --- a/src/Models/Alliances/Alliance.php +++ b/src/Models/Alliances/Alliance.php @@ -23,6 +23,8 @@ namespace Seat\Eveapi\Models\Alliances; use Illuminate\Database\Eloquent\Model; +use Seat\Eveapi\Models\Universe\UniverseName; +use Seat\Eveapi\Pivot\Alliance\AllianceMember; /** * Class Alliance. @@ -67,4 +69,13 @@ public function setDateFoundedAttribute($value) { $this->attributes['date_founded'] = is_null($value) ? null : carbon($value); } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany + */ + public function members() + { + return $this->belongsToMany(UniverseName::class, 'alliance_members', 'alliance_id', 'corporation_id') + ->using(AllianceMember::class); + } } diff --git a/src/Models/Alliances/AllianceMember.php b/src/Pivot/Alliance/AllianceMember.php similarity index 55% rename from src/Models/Alliances/AllianceMember.php rename to src/Pivot/Alliance/AllianceMember.php index 56f04628..bebc20ae 100644 --- a/src/Models/Alliances/AllianceMember.php +++ b/src/Pivot/Alliance/AllianceMember.php @@ -3,7 +3,7 @@ /* * This file is part of SeAT * - * Copyright (C) 2015 to 2020 Leon Jacobs + * Copyright (C) 2015 to 2021 Leon Jacobs * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,23 +15,20 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -namespace Seat\Eveapi\Models\Alliances; +namespace Seat\Eveapi\Pivot\Alliance; -use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\Pivot; /** * Class AllianceMember. - * @package Seat\Eveapi\Models\Alliances + * @package Seat\Eveapi\Pivot\Alliance */ -class AllianceMember extends Model +class AllianceMember extends Pivot { - /** - * @var bool - */ - protected static $unguarded = true; + } From 97d177597c944e343ddd480f43adc14bb3d4b90c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sun, 4 Apr 2021 21:23:03 +0200 Subject: [PATCH 34/42] test: add alliance corporations coverage --- src/Models/Universe/UniverseName.php | 7 + tests/Jobs/Esi/Alliances/CorporationsTest.php | 277 ++++++++++++++++++ tests/artifacts/alliances/corporations.json | 14 + tests/artifacts/universe/names.json | 62 ++++ ...4_201026_create_alliance_members_table.php | 64 ++++ ..._04_203647_create_universe_names_table.php | 62 ++++ 6 files changed, 486 insertions(+) create mode 100644 tests/Jobs/Esi/Alliances/CorporationsTest.php create mode 100644 tests/artifacts/alliances/corporations.json create mode 100644 tests/artifacts/universe/names.json create mode 100644 tests/database/migrations/2021_04_04_201026_create_alliance_members_table.php create mode 100644 tests/database/migrations/2021_04_04_203647_create_universe_names_table.php diff --git a/src/Models/Universe/UniverseName.php b/src/Models/Universe/UniverseName.php index 98edf607..c1c89cb4 100644 --- a/src/Models/Universe/UniverseName.php +++ b/src/Models/Universe/UniverseName.php @@ -77,6 +77,13 @@ class UniverseName extends Model */ protected $primaryKey = 'entity_id'; + /** + * @var string[] + */ + protected $casts = [ + 'entity_id' => 'integer', + ]; + /** * @return \Illuminate\Database\Eloquent\Relations\HasOne */ diff --git a/tests/Jobs/Esi/Alliances/CorporationsTest.php b/tests/Jobs/Esi/Alliances/CorporationsTest.php new file mode 100644 index 00000000..f310ca8a --- /dev/null +++ b/tests/Jobs/Esi/Alliances/CorporationsTest.php @@ -0,0 +1,277 @@ + carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_success = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/alliances/corporations.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../artifacts/alliances/corporations.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_names); + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_names); + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $alliance = Alliance::create([ + 'alliance_id' => 99000137, + 'creator_corporation_id' => 157983505, + 'creator_id' => 211292683, + 'executor_corporation_id' => 157983505, + 'date_founded' => '2010-12-16T02:35:00Z', + 'name' => 'Renaissance Federation', + 'ticker' => 'RF', + ]); + + $job = new Members(99000137); + $job->handle(); + + $alliance->load('members'); + $data = json_encode($alliance->members->sortBy('entity_id')->pluck('entity_id')->toArray()); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/alliances/corporations.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $alliance = Alliance::create([ + 'alliance_id' => 99000137, + 'creator_corporation_id' => 157983505, + 'creator_id' => 211292683, + 'executor_corporation_id' => 157983505, + 'date_founded' => '2010-12-16T02:35:00Z', + 'name' => 'Renaissance Federation', + 'ticker' => 'RF', + ]); + + $first_corporation = UniverseName::create([ + 'entity_id' => 65465464684, + 'name' => 'Test Corporation 1', + 'category' => 'corporation', + ]); + + $second_corporation = UniverseName::create([ + 'entity_id' => 5454131657, + 'name' => 'Test Corporation 2', + 'category' => 'corporation', + ]); + + $third_corporation = UniverseName::create([ + 'entity_id' => 1021546564, + 'name' => 'Test Corporation 3', + 'category' => 'corporation', + ]); + + $alliance->members()->attach([$first_corporation->entity_id, $second_corporation->entity_id, $third_corporation->entity_id]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Members(99000137); + $job->handle(); + + $alliance = Alliance::find(99000137); + + $this->assertCount(3, $alliance->members); + foreach ($alliance->members as $member) + $this->assertEquals($member->created_at, $member->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/alliances/99000137/corporations/', 'datasource=tranquility'); + + $alliance = Alliance::create([ + 'alliance_id' => 99000137, + 'creator_corporation_id' => 157983505, + 'creator_id' => 211292683, + 'executor_corporation_id' => 157983505, + 'date_founded' => '2010-12-16T02:35:00Z', + 'name' => 'Renaissance Federation', + 'ticker' => 'RF', + ]); + + $first_corporation = UniverseName::create([ + 'entity_id' => 65465464684, + 'name' => 'Test Corporation 1', + 'category' => 'corporation', + ]); + + $second_corporation = UniverseName::create([ + 'entity_id' => 5454131657, + 'name' => 'Test Corporation 2', + 'category' => 'corporation', + ]); + + $third_corporation = UniverseName::create([ + 'entity_id' => 1021546564, + 'name' => 'Test Corporation 3', + 'category' => 'corporation', + ]); + + $alliance->members()->attach([$first_corporation->entity_id, $second_corporation->entity_id, $third_corporation->entity_id]); + + $alliance = Alliance::find(99000137); + + $data = json_encode($alliance->members->sortBy('entity_id')->pluck('entity_id')->toArray()); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../artifacts/alliances/corporations.json', $data); + + $job = new Members(99000137); + $job->handle(); + + $alliance->load('members'); + $data = json_encode($alliance->members->sortBy('entity_id')->pluck('entity_id')->toArray()); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../artifacts/alliances/corporations.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $job = new Members(404); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $job = new Members(420); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $job = new Members(500); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $job = new Members(503); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $job = new Members(504); + $job->handle(); + } +} diff --git a/tests/artifacts/alliances/corporations.json b/tests/artifacts/alliances/corporations.json new file mode 100644 index 00000000..6be023a0 --- /dev/null +++ b/tests/artifacts/alliances/corporations.json @@ -0,0 +1,14 @@ +[ + 98002716, + 98031741, + 98065660, + 98283946, + 98441400, + 98442507, + 98506824, + 98551471, + 157983505, + 305649901, + 1186907118, + 1832298196 +] \ No newline at end of file diff --git a/tests/artifacts/universe/names.json b/tests/artifacts/universe/names.json new file mode 100644 index 00000000..231ae5e7 --- /dev/null +++ b/tests/artifacts/universe/names.json @@ -0,0 +1,62 @@ +[ + { + "category": "corporation", + "id": 98506824, + "name": "BM2 Beta" + }, + { + "category": "corporation", + "id": 98065660, + "name": "Virtual Pilots" + }, + { + "category": "corporation", + "id": 98283946, + "name": "Industrial Research Innovations" + }, + { + "category": "corporation", + "id": 98442507, + "name": "BM2 Project 6" + }, + { + "category": "corporation", + "id": 305649901, + "name": "BM2 Project 2" + }, + { + "category": "corporation", + "id": 1186907118, + "name": "Electric Society" + }, + { + "category": "corporation", + "id": 98551471, + "name": "Greater Eden Advanced Research Society" + }, + { + "category": "corporation", + "id": 157983505, + "name": "Blacksteel Mining and Manufacturing" + }, + { + "category": "corporation", + "id": 1832298196, + "name": "Xanth Technologies" + }, + { + "category": "corporation", + "id": 98441400, + "name": "Skye Logistics" + }, + { + "category": "corporation", + "id": 98002716, + "name": "Auriga Technology" + }, + { + "category": "corporation", + "id": 98031741, + "name": "BM2 Project 4" + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_04_04_201026_create_alliance_members_table.php b/tests/database/migrations/2021_04_04_201026_create_alliance_members_table.php new file mode 100644 index 00000000..6e2d5cc4 --- /dev/null +++ b/tests/database/migrations/2021_04_04_201026_create_alliance_members_table.php @@ -0,0 +1,64 @@ +bigIncrements('id'); + $table->integer('alliance_id'); + $table->bigInteger('corporation_id'); + + $table->unique(['alliance_id', 'corporation_id']); + $table->index(['alliance_id']); + $table->index(['corporation_id']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('alliance_members'); + } +} diff --git a/tests/database/migrations/2021_04_04_203647_create_universe_names_table.php b/tests/database/migrations/2021_04_04_203647_create_universe_names_table.php new file mode 100644 index 00000000..0cef1ac1 --- /dev/null +++ b/tests/database/migrations/2021_04_04_203647_create_universe_names_table.php @@ -0,0 +1,62 @@ +bigInteger('entity_id'); + $table->string('name'); + $table->string('category'); + + $table->index(['category']); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('universe_names'); + } +} From d917e6d98721f3521bf655465167b9d483328e8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sun, 4 Apr 2021 22:36:52 +0200 Subject: [PATCH 35/42] test: add alliance contacts coverage --- src/Models/Contacts/AllianceContact.php | 2 + .../Esi/Contacts/Alliance/ContactsTest.php | 385 ++++++++++++++++++ .../Contacts/Alliances/ContactResource.php | 45 ++ .../contacts/alliances/contacts.json | 7 + ..._214134_create_alliance_contacts_table.php | 63 +++ 5 files changed, 502 insertions(+) create mode 100644 tests/Jobs/Esi/Contacts/Alliance/ContactsTest.php create mode 100644 tests/Resources/Esi/Contacts/Alliances/ContactResource.php create mode 100644 tests/artifacts/contacts/alliances/contacts.json create mode 100644 tests/database/migrations/2021_04_04_214134_create_alliance_contacts_table.php diff --git a/src/Models/Contacts/AllianceContact.php b/src/Models/Contacts/AllianceContact.php index 6dcd02f4..baa6f217 100644 --- a/src/Models/Contacts/AllianceContact.php +++ b/src/Models/Contacts/AllianceContact.php @@ -71,6 +71,8 @@ class AllianceContact extends Model */ protected $casts = [ 'label_ids' => 'array', + 'standing' => 'float', + 'contact_id' => 'integer', ]; /** diff --git a/tests/Jobs/Esi/Contacts/Alliance/ContactsTest.php b/tests/Jobs/Esi/Contacts/Alliance/ContactsTest.php new file mode 100644 index 00000000..bdf345c2 --- /dev/null +++ b/tests/Jobs/Esi/Contacts/Alliance/ContactsTest.php @@ -0,0 +1,385 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + 'X-Pages' => 1, + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../../artifacts/contacts/alliances/contacts.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + 'X-Pages' => 1, + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts(99000001, $token); + $job->handle(); + + $contacts = AllianceContact::all(); + + $data = json_encode(ContactResource::collection($contacts)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/alliances/contacts.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + AllianceContact::create([ + 'alliance_id' => 99000001, + 'contact_id' => 2112625428, + 'contact_type' => 'character', + 'standing' => -5.0, + ]); + + AllianceContact::create([ + 'alliance_id' => 99000001, + 'contact_id' => 1012044794, + 'contact_type' => 'corporation', + 'standing' => 9.0, + ]); + + AllianceContact::create([ + 'alliance_id' => 99000001, + 'contact_id' => 46561324, + 'contact_type' => 'character', + 'standing' => 6.3, + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Contacts(99000001, $token); + $job->handle(); + + $contacts = AllianceContact::all(); + + $this->assertCount(3, $contacts); + foreach ($contacts as $contact) + $this->assertEquals($contact->created_at, $contact->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v2/alliances/99000001/contacts/', 'datasource=tranquility&page=1'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + AllianceContact::create([ + 'alliance_id' => 99000001, + 'contact_id' => 2112625428, + 'contact_type' => 'character', + 'standing' => -5.0, + ]); + + AllianceContact::create([ + 'alliance_id' => 99000001, + 'contact_id' => 1012044794, + 'contact_type' => 'corporation', + 'standing' => 9.0, + ]); + + AllianceContact::create([ + 'alliance_id' => 99000001, + 'contact_id' => 46561324, + 'contact_type' => 'character', + 'standing' => 6.3, + ]); + + $contacts = AllianceContact::all(); + $data = json_encode(ContactResource::collection($contacts)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/alliances/contacts.json', $data); + + $job = new Contacts(99000001, $token); + $job->handle(); + + $contacts = AllianceContact::all(); + $data = json_encode(ContactResource::collection($contacts)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/alliances/contacts.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts(99000001, $token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts(99000001, $token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts(99000001, $token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts(99000001, $token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts(99000001, $token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts(99000001, $token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts(99000001, $token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Contacts/Alliances/ContactResource.php b/tests/Resources/Esi/Contacts/Alliances/ContactResource.php new file mode 100644 index 00000000..a0487cc4 --- /dev/null +++ b/tests/Resources/Esi/Contacts/Alliances/ContactResource.php @@ -0,0 +1,45 @@ + $this->contact_id, + 'contact_type' => $this->contact_type, + 'label_ids' => $this->when($this->label_ids, $this->label_ids), + 'standing' => $this->standing, + ]; + } +} diff --git a/tests/artifacts/contacts/alliances/contacts.json b/tests/artifacts/contacts/alliances/contacts.json new file mode 100644 index 00000000..2d88eb64 --- /dev/null +++ b/tests/artifacts/contacts/alliances/contacts.json @@ -0,0 +1,7 @@ +[ + { + "contact_id": 2112625428, + "contact_type": "character", + "standing": 9.9 + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_04_04_214134_create_alliance_contacts_table.php b/tests/database/migrations/2021_04_04_214134_create_alliance_contacts_table.php new file mode 100644 index 00000000..c2859273 --- /dev/null +++ b/tests/database/migrations/2021_04_04_214134_create_alliance_contacts_table.php @@ -0,0 +1,63 @@ +bigIncrements('id'); + $table->integer('alliance_id'); + $table->bigInteger('contact_id'); + $table->string('contact_type'); + $table->float('standing'); + $table->json('label_ids')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('alliance_contacts'); + } +} From e2e087b9f5e183f035e31eb9cb9cb594e5909cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sun, 4 Apr 2021 22:37:32 +0200 Subject: [PATCH 36/42] test: add corporation contacts coverage --- src/Models/Contacts/CorporationContact.php | 4 +- .../Esi/Contacts/Corporation/ContactsTest.php | 385 ++++++++++++++++++ .../Contacts/Corporations/ContactResource.php | 46 +++ .../contacts/corporations/contacts.json | 8 + ...5034_create_corporation_contacts_table.php | 64 +++ 5 files changed, 506 insertions(+), 1 deletion(-) create mode 100644 tests/Jobs/Esi/Contacts/Corporation/ContactsTest.php create mode 100644 tests/Resources/Esi/Contacts/Corporations/ContactResource.php create mode 100644 tests/artifacts/contacts/corporations/contacts.json create mode 100644 tests/database/migrations/2021_04_04_215034_create_corporation_contacts_table.php diff --git a/src/Models/Contacts/CorporationContact.php b/src/Models/Contacts/CorporationContact.php index 9cb47b66..0cba7ba8 100644 --- a/src/Models/Contacts/CorporationContact.php +++ b/src/Models/Contacts/CorporationContact.php @@ -84,7 +84,9 @@ class CorporationContact extends Model protected $casts = [ 'is_watched' => 'boolean', 'is_blocked' => 'boolean', - 'label_ids' => 'array', + 'label_ids' => 'array', + 'contact_id' => 'integer', + 'standing' => 'float', ]; /** diff --git a/tests/Jobs/Esi/Contacts/Corporation/ContactsTest.php b/tests/Jobs/Esi/Contacts/Corporation/ContactsTest.php new file mode 100644 index 00000000..415190a3 --- /dev/null +++ b/tests/Jobs/Esi/Contacts/Corporation/ContactsTest.php @@ -0,0 +1,385 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + 'X-Pages' => 1, + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../../artifacts/contacts/corporations/contacts.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + 'X-Pages' => 1, + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts(109299958, $token); + $job->handle(); + + $contacts = CorporationContact::all(); + + $data = json_encode(ContactResource::collection($contacts)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/corporations/contacts.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationContact::create([ + 'corporation_id' => 109299958, + 'contact_id' => 2112625428, + 'contact_type' => 'character', + 'standing' => -5.0, + ]); + + CorporationContact::create([ + 'corporation_id' => 109299958, + 'contact_id' => 1012044794, + 'contact_type' => 'corporation', + 'standing' => 9.0, + ]); + + CorporationContact::create([ + 'corporation_id' => 109299958, + 'contact_id' => 46561324, + 'contact_type' => 'character', + 'standing' => 6.3, + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Contacts(109299958, $token); + $job->handle(); + + $contacts = CorporationContact::all(); + + $this->assertCount(3, $contacts); + foreach ($contacts as $contact) + $this->assertEquals($contact->created_at, $contact->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v2/corporations/109299958/contacts/', 'datasource=tranquility&page=1'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationContact::create([ + 'corporation_id' => 109299958, + 'contact_id' => 2112625428, + 'contact_type' => 'character', + 'standing' => -5.0, + ]); + + CorporationContact::create([ + 'corporation_id' => 109299958, + 'contact_id' => 1012044794, + 'contact_type' => 'corporation', + 'standing' => 9.0, + ]); + + CorporationContact::create([ + 'corporation_id' => 109299958, + 'contact_id' => 46561324, + 'contact_type' => 'character', + 'standing' => 6.3, + ]); + + $contacts = CorporationContact::all(); + $data = json_encode(ContactResource::collection($contacts)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/corporations/contacts.json', $data); + + $job = new Contacts(109299958, $token); + $job->handle(); + + $contacts = CorporationContact::all(); + $data = json_encode(ContactResource::collection($contacts)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/corporations/contacts.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts(109299958, $token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts(109299958, $token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts(109299958, $token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Contacts/Corporations/ContactResource.php b/tests/Resources/Esi/Contacts/Corporations/ContactResource.php new file mode 100644 index 00000000..0934006f --- /dev/null +++ b/tests/Resources/Esi/Contacts/Corporations/ContactResource.php @@ -0,0 +1,46 @@ + $this->contact_id, + 'contact_type' => $this->contact_type, + 'is_watched' => $this->when($this->is_watched, $this->is_watched), + 'label_ids' => $this->when($this->label_ids, $this->label_ids), + 'standing' => $this->standing, + ]; + } +} diff --git a/tests/artifacts/contacts/corporations/contacts.json b/tests/artifacts/contacts/corporations/contacts.json new file mode 100644 index 00000000..8cc568a7 --- /dev/null +++ b/tests/artifacts/contacts/corporations/contacts.json @@ -0,0 +1,8 @@ +[ + { + "contact_id": 123, + "contact_type": "character", + "is_watched": true, + "standing": 9.9 + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_04_04_215034_create_corporation_contacts_table.php b/tests/database/migrations/2021_04_04_215034_create_corporation_contacts_table.php new file mode 100644 index 00000000..60ec4fef --- /dev/null +++ b/tests/database/migrations/2021_04_04_215034_create_corporation_contacts_table.php @@ -0,0 +1,64 @@ +bigIncrements('id'); + $table->bigInteger('corporation_id'); + $table->bigInteger('contact_id'); + $table->string('contact_type'); + $table->float('standing'); + $table->boolean('is_watched')->nullable(); + $table->json('label_ids')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('corporation_contacts'); + } +} From e3e13800c678e8ec01850cb3e238b499ccb0ed17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sun, 4 Apr 2021 22:37:52 +0200 Subject: [PATCH 37/42] test: add character contacts coverage --- src/Models/Contacts/CharacterContact.php | 4 +- .../Esi/Contacts/Character/ContactsTest.php | 385 ++++++++++++++++++ .../Contacts/Characters/ContactResource.php | 47 +++ .../contacts/characters/contacts.json | 9 + ...215306_create_character_contacts_table.php | 65 +++ 5 files changed, 509 insertions(+), 1 deletion(-) create mode 100644 tests/Jobs/Esi/Contacts/Character/ContactsTest.php create mode 100644 tests/Resources/Esi/Contacts/Characters/ContactResource.php create mode 100644 tests/artifacts/contacts/characters/contacts.json create mode 100644 tests/database/migrations/2021_04_04_215306_create_character_contacts_table.php diff --git a/src/Models/Contacts/CharacterContact.php b/src/Models/Contacts/CharacterContact.php index 08b4ef11..008e6d71 100644 --- a/src/Models/Contacts/CharacterContact.php +++ b/src/Models/Contacts/CharacterContact.php @@ -84,7 +84,9 @@ class CharacterContact extends Model protected $casts = [ 'is_watched' => 'boolean', 'is_blocked' => 'boolean', - 'label_ids' => 'array', + 'label_ids' => 'array', + 'contact_id' => 'integer', + 'standing' => 'float', ]; /** diff --git a/tests/Jobs/Esi/Contacts/Character/ContactsTest.php b/tests/Jobs/Esi/Contacts/Character/ContactsTest.php new file mode 100644 index 00000000..bcd34695 --- /dev/null +++ b/tests/Jobs/Esi/Contacts/Character/ContactsTest.php @@ -0,0 +1,385 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + 'X-Pages' => 1, + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../../artifacts/contacts/characters/contacts.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + 'X-Pages' => 1, + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts($token); + $job->handle(); + + $contacts = CharacterContact::all(); + + $data = json_encode(ContactResource::collection($contacts)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/characters/contacts.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterContact::create([ + 'character_id' => 180548812, + 'contact_id' => 2112625428, + 'contact_type' => 'character', + 'standing' => -5.0, + ]); + + CharacterContact::create([ + 'character_id' => 180548812, + 'contact_id' => 1012044794, + 'contact_type' => 'corporation', + 'standing' => 9.0, + ]); + + CharacterContact::create([ + 'character_id' => 180548812, + 'contact_id' => 46561324, + 'contact_type' => 'character', + 'standing' => 6.3, + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Contacts($token); + $job->handle(); + + $contacts = CharacterContact::all(); + + $this->assertCount(3, $contacts); + foreach ($contacts as $contact) + $this->assertEquals($contact->created_at, $contact->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v2/characters/180548812/contacts/', 'datasource=tranquility&page=1'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterContact::create([ + 'character_id' => 180548812, + 'contact_id' => 2112625428, + 'contact_type' => 'character', + 'standing' => -5.0, + ]); + + CharacterContact::create([ + 'character_id' => 180548812, + 'contact_id' => 1012044794, + 'contact_type' => 'corporation', + 'standing' => 9.0, + ]); + + CharacterContact::create([ + 'character_id' => 180548812, + 'contact_id' => 46561324, + 'contact_type' => 'character', + 'standing' => 6.3, + ]); + + $contacts = CharacterContact::all(); + $data = json_encode(ContactResource::collection($contacts)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/characters/contacts.json', $data); + + $job = new Contacts($token); + $job->handle(); + + $contacts = CharacterContact::all(); + $data = json_encode(ContactResource::collection($contacts)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/characters/contacts.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts($token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts($token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts($token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts($token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts($token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts($token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Contacts($token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Contacts/Characters/ContactResource.php b/tests/Resources/Esi/Contacts/Characters/ContactResource.php new file mode 100644 index 00000000..218ec4cb --- /dev/null +++ b/tests/Resources/Esi/Contacts/Characters/ContactResource.php @@ -0,0 +1,47 @@ + $this->contact_id, + 'contact_type' => $this->contact_type, + 'is_watched' => $this->when($this->is_watched, $this->is_watched), + 'is_blocked' => $this->when($this->is_blocked, $this->is_blocked), + 'label_ids' => $this->when($this->label_ids, $this->label_ids), + 'standing' => $this->standing, + ]; + } +} diff --git a/tests/artifacts/contacts/characters/contacts.json b/tests/artifacts/contacts/characters/contacts.json new file mode 100644 index 00000000..383b5de5 --- /dev/null +++ b/tests/artifacts/contacts/characters/contacts.json @@ -0,0 +1,9 @@ +[ + { + "contact_id": 123, + "contact_type": "character", + "is_blocked": true, + "is_watched": true, + "standing": 9.9 + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_04_04_215306_create_character_contacts_table.php b/tests/database/migrations/2021_04_04_215306_create_character_contacts_table.php new file mode 100644 index 00000000..b6d74697 --- /dev/null +++ b/tests/database/migrations/2021_04_04_215306_create_character_contacts_table.php @@ -0,0 +1,65 @@ +bigIncrements('id'); + $table->bigInteger('character_id'); + $table->bigInteger('contact_id'); + $table->string('contact_type'); + $table->float('standing'); + $table->boolean('is_watched')->nullable(); + $table->boolean('is_blocked')->nullable(); + $table->json('label_ids')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_contacts'); + } +} From a12853ec88782812a679449cc2e3fcde1544c520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sun, 4 Apr 2021 22:38:16 +0200 Subject: [PATCH 38/42] test: add character contact labels coverage --- src/Models/Contacts/CharacterLabel.php | 7 + .../Esi/Contacts/Character/LabelsTest.php | 377 ++++++++++++++++++ .../Esi/Contacts/ContactLabelResource.php | 43 ++ .../artifacts/contacts/characters/labels.json | 6 + ...4_221557_create_character_labels_table.php | 61 +++ 5 files changed, 494 insertions(+) create mode 100644 tests/Jobs/Esi/Contacts/Character/LabelsTest.php create mode 100644 tests/Resources/Esi/Contacts/ContactLabelResource.php create mode 100644 tests/artifacts/contacts/characters/labels.json create mode 100644 tests/database/migrations/2021_04_04_221557_create_character_labels_table.php diff --git a/src/Models/Contacts/CharacterLabel.php b/src/Models/Contacts/CharacterLabel.php index f41b9855..31753d13 100644 --- a/src/Models/Contacts/CharacterLabel.php +++ b/src/Models/Contacts/CharacterLabel.php @@ -37,6 +37,13 @@ class CharacterLabel extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'label_id' => 'integer', + ]; + /** * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ diff --git a/tests/Jobs/Esi/Contacts/Character/LabelsTest.php b/tests/Jobs/Esi/Contacts/Character/LabelsTest.php new file mode 100644 index 00000000..bd604fbf --- /dev/null +++ b/tests/Jobs/Esi/Contacts/Character/LabelsTest.php @@ -0,0 +1,377 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../../artifacts/contacts/characters/labels.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels($token); + $job->handle(); + + $labels = CharacterLabel::all(); + + $data = json_encode(ContactLabelResource::collection($labels)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/characters/labels.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterLabel::create([ + 'character_id' => 180548812, + 'label_id' => 1, + 'name' => 'Character Enemies', + ]); + + CharacterLabel::create([ + 'character_id' => 180548812, + 'label_id' => 2, + 'name' => 'Character Allies', + ]); + + CharacterLabel::create([ + 'character_id' => 180548812, + 'label_id' => 3, + 'name' => 'Character Friends', + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Labels($token); + $job->handle(); + + $labels = CharacterLabel::all(); + + $this->assertCount(3, $labels); + foreach ($labels as $label) + $this->assertEquals($label->created_at, $label->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/characters/180548812/contacts/labels/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CharacterLabel::create([ + 'character_id' => 180548812, + 'label_id' => 1, + 'name' => 'Character Enemies', + ]); + + CharacterLabel::create([ + 'character_id' => 180548812, + 'label_id' => 2, + 'name' => 'Character Allies', + ]); + + CharacterLabel::create([ + 'character_id' => 180548812, + 'label_id' => 3, + 'name' => 'Character Friends', + ]); + + $labels = CharacterLabel::all(); + $data = json_encode(ContactLabelResource::collection($labels)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/characters/labels.json', $data); + + $job = new Labels($token); + $job->handle(); + + $labels = CharacterLabel::all(); + $data = json_encode(ContactLabelResource::collection($labels)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/characters/labels.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels($token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels($token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels($token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels($token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels($token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-characters.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels($token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels($token); + $job->handle(); + } +} diff --git a/tests/Resources/Esi/Contacts/ContactLabelResource.php b/tests/Resources/Esi/Contacts/ContactLabelResource.php new file mode 100644 index 00000000..82ff2fe7 --- /dev/null +++ b/tests/Resources/Esi/Contacts/ContactLabelResource.php @@ -0,0 +1,43 @@ + $this->label_id, + 'label_name' => $this->name, + ]; + } +} diff --git a/tests/artifacts/contacts/characters/labels.json b/tests/artifacts/contacts/characters/labels.json new file mode 100644 index 00000000..bd0abe08 --- /dev/null +++ b/tests/artifacts/contacts/characters/labels.json @@ -0,0 +1,6 @@ +[ + { + "label_id": 123, + "label_name": "Friends" + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_04_04_221557_create_character_labels_table.php b/tests/database/migrations/2021_04_04_221557_create_character_labels_table.php new file mode 100644 index 00000000..9f437cc3 --- /dev/null +++ b/tests/database/migrations/2021_04_04_221557_create_character_labels_table.php @@ -0,0 +1,61 @@ +bigIncrements('id'); + $table->bigInteger('character_id'); + $table->bigInteger('label_id'); + $table->string('name'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_labels'); + } +} From 3b88680144e9b4d402ade8c5d0a4ecefe99b2310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sun, 4 Apr 2021 22:38:33 +0200 Subject: [PATCH 39/42] test: add corporation contact labels coverage --- src/Models/Contacts/CorporationLabel.php | 7 + .../Esi/Contacts/Corporation/LabelsTest.php | 377 ++++++++++++++++++ .../contacts/corporations/labels.json | 6 + ...221640_create_corporation_labels_table.php | 61 +++ 4 files changed, 451 insertions(+) create mode 100644 tests/Jobs/Esi/Contacts/Corporation/LabelsTest.php create mode 100644 tests/artifacts/contacts/corporations/labels.json create mode 100644 tests/database/migrations/2021_04_04_221640_create_corporation_labels_table.php diff --git a/src/Models/Contacts/CorporationLabel.php b/src/Models/Contacts/CorporationLabel.php index 3c110d0f..c9d41abf 100644 --- a/src/Models/Contacts/CorporationLabel.php +++ b/src/Models/Contacts/CorporationLabel.php @@ -37,6 +37,13 @@ class CorporationLabel extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'label_id' => 'integer', + ]; + /** * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ diff --git a/tests/Jobs/Esi/Contacts/Corporation/LabelsTest.php b/tests/Jobs/Esi/Contacts/Corporation/LabelsTest.php new file mode 100644 index 00000000..5129813a --- /dev/null +++ b/tests/Jobs/Esi/Contacts/Corporation/LabelsTest.php @@ -0,0 +1,377 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../../artifacts/contacts/corporations/labels.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels(109299958, $token); + $job->handle(); + + $labels = CorporationLabel::all(); + + $data = json_encode(ContactLabelResource::collection($labels)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/corporations/labels.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationLabel::create([ + 'corporation_id' => 109299958, + 'label_id' => 1, + 'name' => 'Corporation Enemies', + ]); + + CorporationLabel::create([ + 'corporation_id' => 109299958, + 'label_id' => 2, + 'name' => 'Corporation Allies', + ]); + + CorporationLabel::create([ + 'corporation_id' => 109299958, + 'label_id' => 3, + 'name' => 'Corporation Fiends', + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Labels(109299958, $token); + $job->handle(); + + $labels = CorporationLabel::all(); + + $this->assertCount(3, $labels); + foreach ($labels as $label) + $this->assertEquals($label->created_at, $label->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/corporations/109299958/contacts/labels/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + CorporationLabel::create([ + 'corporation_id' => 109299958, + 'label_id' => 1, + 'name' => 'Corporation Enemies', + ]); + + CorporationLabel::create([ + 'corporation_id' => 109299958, + 'label_id' => 2, + 'name' => 'Corporation Allies', + ]); + + CorporationLabel::create([ + 'corporation_id' => 109299958, + 'label_id' => 3, + 'name' => 'Corporation Fiends', + ]); + + $labels = CorporationLabel::all(); + $data = json_encode(ContactLabelResource::collection($labels)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/corporations/labels.json', $data); + + $job = new Labels(109299958, $token); + $job->handle(); + + $labels = CorporationLabel::all(); + $data = json_encode(ContactLabelResource::collection($labels)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/corporations/labels.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels(109299958, $token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels(109299958, $token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-corporations.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels(109299958, $token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels(109299958, $token); + $job->handle(); + } +} diff --git a/tests/artifacts/contacts/corporations/labels.json b/tests/artifacts/contacts/corporations/labels.json new file mode 100644 index 00000000..7937d7b3 --- /dev/null +++ b/tests/artifacts/contacts/corporations/labels.json @@ -0,0 +1,6 @@ +[ + { + "label_id": 2, + "label_name": "Corporation Friends" + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_04_04_221640_create_corporation_labels_table.php b/tests/database/migrations/2021_04_04_221640_create_corporation_labels_table.php new file mode 100644 index 00000000..7ae53528 --- /dev/null +++ b/tests/database/migrations/2021_04_04_221640_create_corporation_labels_table.php @@ -0,0 +1,61 @@ +bigIncrements('id'); + $table->bigInteger('corporation_id'); + $table->bigInteger('label_id'); + $table->string('name'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('corporation_labels'); + } +} From 33eece9adbebb02d85b46361e1f5c45eea59336a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Sun, 4 Apr 2021 22:38:41 +0200 Subject: [PATCH 40/42] test: add alliance contact labels coverage --- src/Models/Contacts/AllianceLabel.php | 7 + .../Jobs/Esi/Contacts/Alliance/LabelsTest.php | 377 ++++++++++++++++++ .../artifacts/contacts/alliances/labels.json | 6 + ...04_221652_create_alliance_labels_table.php | 61 +++ 4 files changed, 451 insertions(+) create mode 100644 tests/Jobs/Esi/Contacts/Alliance/LabelsTest.php create mode 100644 tests/artifacts/contacts/alliances/labels.json create mode 100644 tests/database/migrations/2021_04_04_221652_create_alliance_labels_table.php diff --git a/src/Models/Contacts/AllianceLabel.php b/src/Models/Contacts/AllianceLabel.php index 9394e3b8..ba089f47 100644 --- a/src/Models/Contacts/AllianceLabel.php +++ b/src/Models/Contacts/AllianceLabel.php @@ -37,6 +37,13 @@ class AllianceLabel extends Model */ protected static $unguarded = true; + /** + * @var string[] + */ + protected $casts = [ + 'label_id' => 'integer', + ]; + /** * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ diff --git a/tests/Jobs/Esi/Contacts/Alliance/LabelsTest.php b/tests/Jobs/Esi/Contacts/Alliance/LabelsTest.php new file mode 100644 index 00000000..9b05e935 --- /dev/null +++ b/tests/Jobs/Esi/Contacts/Alliance/LabelsTest.php @@ -0,0 +1,377 @@ + '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_not_modified = new EsiResponse( + '', + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addHour()->toRfc7231String(), + ], + carbon()->addHour()->toRfc7231String(), + 304 + ); + + $response_success_bis = new EsiResponse( + file_get_contents(__DIR__ . '/../../../../artifacts/contacts/alliances/labels.json'), + [ + 'ETag' => '2b163975d331cee0273f42391831a1b9d7ca53cec57c45d6e4631cdc', + 'Expires' => carbon()->addSeconds(5)->toRfc7231String(), + ], + carbon()->addSeconds(5)->toRfc7231String(), + 200 + ); + + $response_invalid_token = new EsiResponse('{"error":"invalid_token: The refresh token is expired."}', [], carbon()->toRfc7231String(), 400); + $response_not_found = new EsiResponse('', [], carbon()->toRfc7231String(), 404); + $response_error_limited = new EsiResponse('', [], carbon()->toRfc7231String(), 420); + $response_internal_server_error = new EsiResponse('', [], carbon()->toRfc7231String(), 500); + $response_service_unavailable = new EsiResponse('{"error":"The datasource tranquility is temporarily unavailable"}', [], carbon()->toRfc7231String(), 503); + $response_gateway_timeout = new EsiResponse('{"error":"Timeout contacting tranquility"}', [], carbon()->toRfc7231String(), 504); + + // seed mock fetcher with response stack + EsiMockFetcher::add($response_gateway_timeout); // http@504 + EsiMockFetcher::add($response_service_unavailable); // http@503 + EsiMockFetcher::add($response_internal_server_error); // http@500 + EsiMockFetcher::add($response_error_limited); // http@420 + EsiMockFetcher::add($response_not_found); // http@404 + EsiMockFetcher::add($response_invalid_token); // http@400 + EsiMockFetcher::add($response_success_bis); // http@200 + EsiMockFetcher::add($response_not_modified); // http@304 + EsiMockFetcher::add($response_success); // http@200 + } + + public function testHandleSuccess() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels(99000001, $token); + $job->handle(); + + $labels = AllianceLabel::all(); + + $data = json_encode(ContactLabelResource::collection($labels)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/alliances/labels.json', $data); + } + + /** + * @depends testHandleSuccess + */ + public function testHandleNotModified() + { + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + AllianceLabel::create([ + 'alliance_id' => 99000001, + 'label_id' => 1, + 'name' => 'Alliance Enemies', + ]); + + AllianceLabel::create([ + 'alliance_id' => 99000001, + 'label_id' => 2, + 'name' => 'Alliance Allies', + ]); + + AllianceLabel::create([ + 'alliance_id' => 99000001, + 'label_id' => 3, + 'name' => 'Alliance Friends', + ]); + + // sleep for 5 seconds so we burn cache entry and move to ETag flow + sleep(5); + + $job = new Labels(99000001, $token); + $job->handle(); + + $labels = AllianceLabel::all(); + + $this->assertCount(3, $labels); + foreach ($labels as $label) + $this->assertEquals($label->created_at, $label->updated_at); + } + + /** + * @depends testHandleNotModified + */ + public function testHandleUpdated() + { + // bypass cache control to force job to be processed + EsiInMemoryCache::getInstance()->forget('/v1/alliances/99000001/contacts/labels/', 'datasource=tranquility'); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + AllianceLabel::create([ + 'alliance_id' => 99000001, + 'label_id' => 1, + 'name' => 'Alliance Enemies', + ]); + + AllianceLabel::create([ + 'alliance_id' => 99000001, + 'label_id' => 2, + 'name' => 'Alliance Allies', + ]); + + AllianceLabel::create([ + 'alliance_id' => 99000001, + 'label_id' => 3, + 'name' => 'Alliance Friends', + ]); + + $labels = AllianceLabel::all(); + $data = json_encode(ContactLabelResource::collection($labels)); + $this->assertJsonStringNotEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/alliances/labels.json', $data); + + $job = new Labels(99000001, $token); + $job->handle(); + + $labels = AllianceLabel::all(); + $data = json_encode(ContactLabelResource::collection($labels)); + $this->assertJsonStringEqualsJsonFile(__DIR__ . '/../../../../artifacts/contacts/alliances/labels.json', $data); + } + + /** + * @depends testHandleUpdated + */ + public function testInvalidToken() + { + $this->expectException(PermanentInvalidTokenException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels(99000001, $token); + $job->handle(); + } + + /** + * @depends testInvalidToken + */ + public function testHandleNotFound() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels(99000001, $token); + $job->handle(); + } + + /** + * @depends testHandleNotFound + */ + public function testHandleErrorLimited() + { + $this->expectException(RequestFailedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels(99000001, $token); + $job->handle(); + } + + /** + * @depends testHandleErrorLimited + */ + public function testHandleInternalServerError() + { + $this->expectException(TemporaryEsiOutageException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels(99000001, $token); + $job->handle(); + } + + /** + * @depends testHandleInternalServerError + */ + public function testHandleServiceUnavailable() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels(99000001, $token); + $job->handle(); + } + + /** + * @depends testHandleServiceUnavailable + */ + public function testHandleGatewayTimeout() + { + $this->expectException(UnavailableEveServersException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => ['esi-alliances.read_contacts.v1'], + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels(99000001, $token); + $job->handle(); + } + + public function testInvalidScope() + { + $this->expectException(EsiScopeAccessDeniedException::class); + + $token = new RefreshToken([ + 'character_id' => 180548812, + 'version' => RefreshToken::CURRENT_VERSION, + 'user_id' => 0, + 'refresh_token' => 'refresh', + 'scopes' => '', + 'expires_on' => carbon()->addHour(), + 'token' => 'token', + 'character_owner_hash' => '87qs9fs1df1sfd654s65d4fgf6s6d4f654q6sf4d6q4gf63qsfc143q464sf', + ]); + $token->save(); + + $job = new Labels(99000001, $token); + $job->handle(); + } +} diff --git a/tests/artifacts/contacts/alliances/labels.json b/tests/artifacts/contacts/alliances/labels.json new file mode 100644 index 00000000..05efc335 --- /dev/null +++ b/tests/artifacts/contacts/alliances/labels.json @@ -0,0 +1,6 @@ +[ + { + "label_id": 1, + "label_name": "Alliance Friends" + } +] \ No newline at end of file diff --git a/tests/database/migrations/2021_04_04_221652_create_alliance_labels_table.php b/tests/database/migrations/2021_04_04_221652_create_alliance_labels_table.php new file mode 100644 index 00000000..74c3e86b --- /dev/null +++ b/tests/database/migrations/2021_04_04_221652_create_alliance_labels_table.php @@ -0,0 +1,61 @@ +bigIncrements('id'); + $table->integer('alliance_id'); + $table->bigInteger('label_id'); + $table->string('name'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('alliance_labels'); + } +} From 443680d25e8dbaf687f82c731376af605230d970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20LEUILLIOT?= Date: Mon, 5 Apr 2021 00:11:44 +0200 Subject: [PATCH 41/42] test: add character relationship coverage --- phpunit.xml | 3 + src/Models/Character/CharacterInfo.php | 6 +- .../JobEsiTestCase.php => BaseTestCase.php} | 16 +- tests/Jobs/Esi/Alliances/CorporationsTest.php | 4 +- tests/Jobs/Esi/Alliances/InfoTest.php | 4 +- tests/Jobs/Esi/Character/AffiliationTest.php | 4 +- .../Jobs/Esi/Character/AgentResearchTest.php | 4 +- tests/Jobs/Esi/Character/BlueprintsTest.php | 4 +- .../Esi/Character/CorporationHistoryTest.php | 4 +- tests/Jobs/Esi/Character/FatigueTest.php | 4 +- tests/Jobs/Esi/Character/InfoTest.php | 4 +- tests/Jobs/Esi/Character/MedalsTest.php | 4 +- .../Jobs/Esi/Character/NotificationsTest.php | 4 +- tests/Jobs/Esi/Character/RolesTest.php | 4 +- tests/Jobs/Esi/Character/StandingsTest.php | 4 +- tests/Jobs/Esi/Character/TitlesTest.php | 4 +- tests/Jobs/Esi/Clones/ClonesTest.php | 4 +- tests/Jobs/Esi/Clones/ImplantsTest.php | 4 +- .../Esi/Contacts/Alliance/ContactsTest.php | 4 +- .../Jobs/Esi/Contacts/Alliance/LabelsTest.php | 4 +- .../Esi/Contacts/Character/ContactsTest.php | 4 +- .../Esi/Contacts/Character/LabelsTest.php | 4 +- .../Esi/Contacts/Corporation/ContactsTest.php | 4 +- .../Esi/Contacts/Corporation/LabelsTest.php | 4 +- .../Esi/Corporation/AllianceHistoryTest.php | 4 +- tests/Jobs/Esi/Corporation/BlueprintsTest.php | 4 +- tests/Jobs/Esi/Corporation/DivisionsTest.php | 4 +- tests/Jobs/Esi/Corporation/FacilitiesTest.php | 4 +- tests/Jobs/Esi/Corporation/InfoTest.php | 4 +- .../Jobs/Esi/Corporation/IssuedMedalsTest.php | 4 +- tests/Jobs/Esi/Corporation/LimitTest.php | 4 +- tests/Jobs/Esi/Corporation/MedalsTest.php | 4 +- .../Esi/Corporation/MemberTrackingTest.php | 4 +- tests/Jobs/Esi/Corporation/MembersTest.php | 4 +- tests/Jobs/Esi/Fittings/FittingsTest.php | 4 +- tests/Jobs/Esi/Insurance/PricesTest.php | 4 +- tests/Jobs/Esi/Skills/AttributesTest.php | 4 +- tests/Jobs/Esi/Skills/SkillQueueTest.php | 4 +- tests/Jobs/Esi/Skills/SkillsTest.php | 4 +- tests/Relationship/AffiliationTest.php | 139 ++++++++++ tests/Relationship/CharacterTest.php | 261 ++++++++++++++++++ ..._character_corporation_histories_table.php | 2 +- ..._create_character_wallet_balance_table.php | 59 ++++ ...35517_create_character_locations_table.php | 61 ++++ ..._235842_create_character_onlines_table.php | 62 +++++ ...05_000821_create_character_ships_table.php | 61 ++++ 46 files changed, 730 insertions(+), 84 deletions(-) rename tests/{Jobs/Esi/JobEsiTestCase.php => BaseTestCase.php} (87%) create mode 100644 tests/Relationship/AffiliationTest.php create mode 100644 tests/Relationship/CharacterTest.php create mode 100644 tests/database/migrations/2021_04_04_234242_create_character_wallet_balance_table.php create mode 100644 tests/database/migrations/2021_04_04_235517_create_character_locations_table.php create mode 100644 tests/database/migrations/2021_04_04_235842_create_character_onlines_table.php create mode 100644 tests/database/migrations/2021_04_05_000821_create_character_ships_table.php diff --git a/phpunit.xml b/phpunit.xml index fc746430..f44ccd01 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -23,6 +23,9 @@ ./tests/Jobs/Esi/ + + ./tests/Relationship/ + diff --git a/src/Models/Character/CharacterInfo.php b/src/Models/Character/CharacterInfo.php index 9bb08a58..a8042e51 100644 --- a/src/Models/Character/CharacterInfo.php +++ b/src/Models/Character/CharacterInfo.php @@ -131,13 +131,13 @@ public function assets() } /** - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + * @return \Illuminate\Database\Eloquent\Relations\HasOne */ public function balance() { - return $this->belongsTo(CharacterWalletBalance::class, - 'character_id', 'character_id'); + return $this->hasOne(CharacterWalletBalance::class, 'character_id', 'character_id') + ->withDefault(); } /** diff --git a/tests/Jobs/Esi/JobEsiTestCase.php b/tests/BaseTestCase.php similarity index 87% rename from tests/Jobs/Esi/JobEsiTestCase.php rename to tests/BaseTestCase.php index 812535a7..7158720d 100644 --- a/tests/Jobs/Esi/JobEsiTestCase.php +++ b/tests/BaseTestCase.php @@ -15,12 +15,12 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -namespace Seat\Eveapi\Tests\Jobs\Esi; +namespace Seat\Eveapi\Tests; use Illuminate\Support\Facades\Event; use Lunaweb\RedisMock\Providers\RedisMockServiceProvider; @@ -32,10 +32,10 @@ use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; /** - * Class JobEsiTestCase. - * @package Seat\Eveapi\Tests\Jobs\Esi + * Class BaseTestCase. + * @package Seat\Eveapi\Tests */ -class JobEsiTestCase extends TestCase +class BaseTestCase extends TestCase { protected function getEnvironmentSetUp($app) { @@ -86,7 +86,7 @@ protected function setUp(): void // override logs by using honey pot Configuration::getInstance()->logger = NullLogger::class; - $this->loadMigrationsFrom(realpath(__DIR__ . '/../../database/migrations')); + $this->loadMigrationsFrom(realpath(__DIR__ . '/database/migrations')); } /** diff --git a/tests/Jobs/Esi/Alliances/CorporationsTest.php b/tests/Jobs/Esi/Alliances/CorporationsTest.php index f310ca8a..7c3c7118 100644 --- a/tests/Jobs/Esi/Alliances/CorporationsTest.php +++ b/tests/Jobs/Esi/Alliances/CorporationsTest.php @@ -31,13 +31,13 @@ use Seat\Eveapi\Models\Universe\UniverseName; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; /** * Class CorporationsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Alliances */ -class CorporationsTest extends JobEsiTestCase +class CorporationsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Alliances/InfoTest.php b/tests/Jobs/Esi/Alliances/InfoTest.php index aedf4330..6ded02c6 100644 --- a/tests/Jobs/Esi/Alliances/InfoTest.php +++ b/tests/Jobs/Esi/Alliances/InfoTest.php @@ -30,14 +30,14 @@ use Seat\Eveapi\Models\Alliances\Alliance; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Alliances\AllianceResource; /** * Class InfoTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Alliances */ -class InfoTest extends JobEsiTestCase +class InfoTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Character/AffiliationTest.php b/tests/Jobs/Esi/Character/AffiliationTest.php index b46dd4ef..0ac05947 100644 --- a/tests/Jobs/Esi/Character/AffiliationTest.php +++ b/tests/Jobs/Esi/Character/AffiliationTest.php @@ -28,7 +28,7 @@ use Seat\Eveapi\Exception\UnavailableEveServersException; use Seat\Eveapi\Jobs\Character\Affiliation; use Seat\Eveapi\Models\Character\CharacterAffiliation; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; use Seat\Eveapi\Tests\Resources\Esi\Character\AffiliationResource; @@ -36,7 +36,7 @@ * Class AffiliationTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Character */ -class AffiliationTest extends JobEsiTestCase +class AffiliationTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Character/AgentResearchTest.php b/tests/Jobs/Esi/Character/AgentResearchTest.php index 0a0b95bd..467b660c 100644 --- a/tests/Jobs/Esi/Character/AgentResearchTest.php +++ b/tests/Jobs/Esi/Character/AgentResearchTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Character\AgentsResearchResource; /** * Class AgentResearchTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Character */ -class AgentResearchTest extends JobEsiTestCase +class AgentResearchTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Character/BlueprintsTest.php b/tests/Jobs/Esi/Character/BlueprintsTest.php index 9305a566..48fead0a 100644 --- a/tests/Jobs/Esi/Character/BlueprintsTest.php +++ b/tests/Jobs/Esi/Character/BlueprintsTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Character\BlueprintResource; /** * Class BlueprintsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Character */ -class BlueprintsTest extends JobEsiTestCase +class BlueprintsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Character/CorporationHistoryTest.php b/tests/Jobs/Esi/Character/CorporationHistoryTest.php index 60146578..11a84db5 100644 --- a/tests/Jobs/Esi/Character/CorporationHistoryTest.php +++ b/tests/Jobs/Esi/Character/CorporationHistoryTest.php @@ -29,14 +29,14 @@ use Seat\Eveapi\Jobs\Character\CorporationHistory; use Seat\Eveapi\Models\Character\CharacterCorporationHistory; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Character\CorporationHistoryResource; /** * Class CorporationHistoryTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Character */ -class CorporationHistoryTest extends JobEsiTestCase +class CorporationHistoryTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Character/FatigueTest.php b/tests/Jobs/Esi/Character/FatigueTest.php index fd3ad4aa..6f70fe12 100644 --- a/tests/Jobs/Esi/Character/FatigueTest.php +++ b/tests/Jobs/Esi/Character/FatigueTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Character\FatigueResource; /** * Class FatigueTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Character */ -class FatigueTest extends JobEsiTestCase +class FatigueTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Character/InfoTest.php b/tests/Jobs/Esi/Character/InfoTest.php index c06152c8..152f8b69 100644 --- a/tests/Jobs/Esi/Character/InfoTest.php +++ b/tests/Jobs/Esi/Character/InfoTest.php @@ -30,14 +30,14 @@ use Seat\Eveapi\Models\Character\CharacterInfo; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Character\InfoResource; /** * Class InfoTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Character */ -class InfoTest extends JobEsiTestCase +class InfoTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Character/MedalsTest.php b/tests/Jobs/Esi/Character/MedalsTest.php index d36eb1e3..48612f99 100644 --- a/tests/Jobs/Esi/Character/MedalsTest.php +++ b/tests/Jobs/Esi/Character/MedalsTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Character\MedalResource; /** * Class MedalsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Character */ -class MedalsTest extends JobEsiTestCase +class MedalsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Character/NotificationsTest.php b/tests/Jobs/Esi/Character/NotificationsTest.php index c838904f..6f167482 100644 --- a/tests/Jobs/Esi/Character/NotificationsTest.php +++ b/tests/Jobs/Esi/Character/NotificationsTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Character\NotificationResource; /** * Class NotificationsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Character */ -class NotificationsTest extends JobEsiTestCase +class NotificationsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Character/RolesTest.php b/tests/Jobs/Esi/Character/RolesTest.php index 2c890550..28d47e5e 100644 --- a/tests/Jobs/Esi/Character/RolesTest.php +++ b/tests/Jobs/Esi/Character/RolesTest.php @@ -34,14 +34,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Character\RoleResource; /** * Class RolesTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Character */ -class RolesTest extends JobEsiTestCase +class RolesTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Character/StandingsTest.php b/tests/Jobs/Esi/Character/StandingsTest.php index 3b227d0c..ee9dfc22 100644 --- a/tests/Jobs/Esi/Character/StandingsTest.php +++ b/tests/Jobs/Esi/Character/StandingsTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Character\StandingResource; /** * Class StandingsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Character */ -class StandingsTest extends JobEsiTestCase +class StandingsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Character/TitlesTest.php b/tests/Jobs/Esi/Character/TitlesTest.php index 8ebe2457..8daf8483 100644 --- a/tests/Jobs/Esi/Character/TitlesTest.php +++ b/tests/Jobs/Esi/Character/TitlesTest.php @@ -34,14 +34,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Character\TitleResource; /** * Class TitlesTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Character */ -class TitlesTest extends JobEsiTestCase +class TitlesTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Clones/ClonesTest.php b/tests/Jobs/Esi/Clones/ClonesTest.php index 391b1048..32c4e464 100644 --- a/tests/Jobs/Esi/Clones/ClonesTest.php +++ b/tests/Jobs/Esi/Clones/ClonesTest.php @@ -35,14 +35,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Clones\CloneResource; /** * Class ClonesTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Clones */ -class ClonesTest extends JobEsiTestCase +class ClonesTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Clones/ImplantsTest.php b/tests/Jobs/Esi/Clones/ImplantsTest.php index f8c95ea6..91c6ef0f 100644 --- a/tests/Jobs/Esi/Clones/ImplantsTest.php +++ b/tests/Jobs/Esi/Clones/ImplantsTest.php @@ -34,13 +34,13 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; /** * Class ImplantsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Clones */ -class ImplantsTest extends JobEsiTestCase +class ImplantsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Contacts/Alliance/ContactsTest.php b/tests/Jobs/Esi/Contacts/Alliance/ContactsTest.php index bdf345c2..5a8e49a8 100644 --- a/tests/Jobs/Esi/Contacts/Alliance/ContactsTest.php +++ b/tests/Jobs/Esi/Contacts/Alliance/ContactsTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Contacts\Alliances\ContactResource; /** * Class ContactsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Contacts\Alliance */ -class ContactsTest extends JobEsiTestCase +class ContactsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Contacts/Alliance/LabelsTest.php b/tests/Jobs/Esi/Contacts/Alliance/LabelsTest.php index 9b05e935..62b82956 100644 --- a/tests/Jobs/Esi/Contacts/Alliance/LabelsTest.php +++ b/tests/Jobs/Esi/Contacts/Alliance/LabelsTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Contacts\ContactLabelResource; /** * Class LabelsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Contacts\Alliance */ -class LabelsTest extends JobEsiTestCase +class LabelsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Contacts/Character/ContactsTest.php b/tests/Jobs/Esi/Contacts/Character/ContactsTest.php index bcd34695..300e0cfd 100644 --- a/tests/Jobs/Esi/Contacts/Character/ContactsTest.php +++ b/tests/Jobs/Esi/Contacts/Character/ContactsTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Contacts\Characters\ContactResource; /** * Class ContactsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Contacts\Corporation */ -class ContactsTest extends JobEsiTestCase +class ContactsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Contacts/Character/LabelsTest.php b/tests/Jobs/Esi/Contacts/Character/LabelsTest.php index bd604fbf..05cd2853 100644 --- a/tests/Jobs/Esi/Contacts/Character/LabelsTest.php +++ b/tests/Jobs/Esi/Contacts/Character/LabelsTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Contacts\ContactLabelResource; /** * Class LabelsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Contacts\Character */ -class LabelsTest extends JobEsiTestCase +class LabelsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Contacts/Corporation/ContactsTest.php b/tests/Jobs/Esi/Contacts/Corporation/ContactsTest.php index 415190a3..0235c793 100644 --- a/tests/Jobs/Esi/Contacts/Corporation/ContactsTest.php +++ b/tests/Jobs/Esi/Contacts/Corporation/ContactsTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Contacts\Corporations\ContactResource; /** * Class ContactsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Contacts\Corporation */ -class ContactsTest extends JobEsiTestCase +class ContactsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Contacts/Corporation/LabelsTest.php b/tests/Jobs/Esi/Contacts/Corporation/LabelsTest.php index 5129813a..3971cd44 100644 --- a/tests/Jobs/Esi/Contacts/Corporation/LabelsTest.php +++ b/tests/Jobs/Esi/Contacts/Corporation/LabelsTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Contacts\ContactLabelResource; /** * Class LabelsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Contacts\Corporation */ -class LabelsTest extends JobEsiTestCase +class LabelsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Corporation/AllianceHistoryTest.php b/tests/Jobs/Esi/Corporation/AllianceHistoryTest.php index 56f07df8..7ed4350e 100644 --- a/tests/Jobs/Esi/Corporation/AllianceHistoryTest.php +++ b/tests/Jobs/Esi/Corporation/AllianceHistoryTest.php @@ -30,14 +30,14 @@ use Seat\Eveapi\Models\Corporation\CorporationAllianceHistory; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Corporation\AllianceHistoryResource; /** * Class AllianceHistoryTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Corporation */ -class AllianceHistoryTest extends JobEsiTestCase +class AllianceHistoryTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Corporation/BlueprintsTest.php b/tests/Jobs/Esi/Corporation/BlueprintsTest.php index 928dc228..c8b193e1 100644 --- a/tests/Jobs/Esi/Corporation/BlueprintsTest.php +++ b/tests/Jobs/Esi/Corporation/BlueprintsTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Corporation\BlueprintResource; /** * Class BlueprintsTest * @package Seat\Eveapi\Tests\Jobs\Esi\Corporation */ -class BlueprintsTest extends JobEsiTestCase +class BlueprintsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Corporation/DivisionsTest.php b/tests/Jobs/Esi/Corporation/DivisionsTest.php index aa81629a..5dd6131e 100644 --- a/tests/Jobs/Esi/Corporation/DivisionsTest.php +++ b/tests/Jobs/Esi/Corporation/DivisionsTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Corporation\DivisionsResource; /** * Class DivisionsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Corporation */ -class DivisionsTest extends JobEsiTestCase +class DivisionsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Corporation/FacilitiesTest.php b/tests/Jobs/Esi/Corporation/FacilitiesTest.php index 84d5c243..0edbf9dc 100644 --- a/tests/Jobs/Esi/Corporation/FacilitiesTest.php +++ b/tests/Jobs/Esi/Corporation/FacilitiesTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Corporation\FacilityResource; /** * Class FacilitiesTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Corporation */ -class FacilitiesTest extends JobEsiTestCase +class FacilitiesTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Corporation/InfoTest.php b/tests/Jobs/Esi/Corporation/InfoTest.php index 1d2f6f6e..04f14cff 100644 --- a/tests/Jobs/Esi/Corporation/InfoTest.php +++ b/tests/Jobs/Esi/Corporation/InfoTest.php @@ -30,14 +30,14 @@ use Seat\Eveapi\Models\Corporation\CorporationInfo; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Corporation\InfoResource; /** * Class InfoTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Corporation */ -class InfoTest extends JobEsiTestCase +class InfoTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Corporation/IssuedMedalsTest.php b/tests/Jobs/Esi/Corporation/IssuedMedalsTest.php index 68e783ed..658ff22b 100644 --- a/tests/Jobs/Esi/Corporation/IssuedMedalsTest.php +++ b/tests/Jobs/Esi/Corporation/IssuedMedalsTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Corporation\IssuedMedalResource; /** * Class IssuedMedalsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Corporation */ -class IssuedMedalsTest extends JobEsiTestCase +class IssuedMedalsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Corporation/LimitTest.php b/tests/Jobs/Esi/Corporation/LimitTest.php index 447394f2..945b0723 100644 --- a/tests/Jobs/Esi/Corporation/LimitTest.php +++ b/tests/Jobs/Esi/Corporation/LimitTest.php @@ -33,13 +33,13 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; /** * Class LimitTest * @package Seat\Eveapi\Tests\Jobs\Esi\Corporation */ -class LimitTest extends JobEsiTestCase +class LimitTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Corporation/MedalsTest.php b/tests/Jobs/Esi/Corporation/MedalsTest.php index 38da00e2..e535b704 100644 --- a/tests/Jobs/Esi/Corporation/MedalsTest.php +++ b/tests/Jobs/Esi/Corporation/MedalsTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Corporation\MedalResource; /** * Class MedalsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Corporation */ -class MedalsTest extends JobEsiTestCase +class MedalsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Corporation/MemberTrackingTest.php b/tests/Jobs/Esi/Corporation/MemberTrackingTest.php index f106d1b5..e6f09047 100644 --- a/tests/Jobs/Esi/Corporation/MemberTrackingTest.php +++ b/tests/Jobs/Esi/Corporation/MemberTrackingTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Corporation\MemberTrackingResource; /** * Class MemberTrackingTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Corporation */ -class MemberTrackingTest extends JobEsiTestCase +class MemberTrackingTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Corporation/MembersTest.php b/tests/Jobs/Esi/Corporation/MembersTest.php index 72b2b1fd..af00a6c6 100644 --- a/tests/Jobs/Esi/Corporation/MembersTest.php +++ b/tests/Jobs/Esi/Corporation/MembersTest.php @@ -33,13 +33,13 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; /** * Class MembersTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Corporation */ -class MembersTest extends JobEsiTestCase +class MembersTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Fittings/FittingsTest.php b/tests/Jobs/Esi/Fittings/FittingsTest.php index 89755490..c609b09a 100644 --- a/tests/Jobs/Esi/Fittings/FittingsTest.php +++ b/tests/Jobs/Esi/Fittings/FittingsTest.php @@ -36,14 +36,14 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Fittings\FittingResource; /** * Class FittingsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Fittings */ -class FittingsTest extends JobEsiTestCase +class FittingsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Insurance/PricesTest.php b/tests/Jobs/Esi/Insurance/PricesTest.php index 33b91185..57f5a632 100644 --- a/tests/Jobs/Esi/Insurance/PricesTest.php +++ b/tests/Jobs/Esi/Insurance/PricesTest.php @@ -39,7 +39,7 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Fittings\FittingResource; use Seat\Eveapi\Tests\Resources\Esi\Insurance\InsuranceResource; @@ -47,7 +47,7 @@ * Class PricesTest * @package Seat\Eveapi\Tests\Jobs\Esi\Insurance */ -class PricesTest extends JobEsiTestCase +class PricesTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Skills/AttributesTest.php b/tests/Jobs/Esi/Skills/AttributesTest.php index 29c3470b..cd5328b9 100644 --- a/tests/Jobs/Esi/Skills/AttributesTest.php +++ b/tests/Jobs/Esi/Skills/AttributesTest.php @@ -33,14 +33,14 @@ use Seat\Eveapi\Models\Skills\CharacterAttribute; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Skills\AttributeResource; /** * Class AttributesTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Skills */ -class AttributesTest extends JobEsiTestCase +class AttributesTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Skills/SkillQueueTest.php b/tests/Jobs/Esi/Skills/SkillQueueTest.php index 91870534..c249f4b3 100644 --- a/tests/Jobs/Esi/Skills/SkillQueueTest.php +++ b/tests/Jobs/Esi/Skills/SkillQueueTest.php @@ -35,7 +35,7 @@ use Seat\Eveapi\Models\Skills\CharacterSkillQueue; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Character\MedalResource; use Seat\Eveapi\Tests\Resources\Esi\Skills\SkillQueueResource; @@ -43,7 +43,7 @@ * Class SkillQueueTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Skills */ -class SkillQueueTest extends JobEsiTestCase +class SkillQueueTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Jobs/Esi/Skills/SkillsTest.php b/tests/Jobs/Esi/Skills/SkillsTest.php index b96a7c96..2749a4ba 100644 --- a/tests/Jobs/Esi/Skills/SkillsTest.php +++ b/tests/Jobs/Esi/Skills/SkillsTest.php @@ -37,7 +37,7 @@ use Seat\Eveapi\Models\RefreshToken; use Seat\Eveapi\Tests\Mocks\Esi\EsiInMemoryCache; use Seat\Eveapi\Tests\Mocks\Esi\EsiMockFetcher; -use Seat\Eveapi\Tests\Jobs\Esi\JobEsiTestCase; +use Seat\Eveapi\Tests\BaseTestCase; use Seat\Eveapi\Tests\Resources\Esi\Character\MedalResource; use Seat\Eveapi\Tests\Resources\Esi\Skills\SkillsResource; @@ -45,7 +45,7 @@ * Class SkillsTest. * @package Seat\Eveapi\Tests\Jobs\Esi\Skills */ -class SkillsTest extends JobEsiTestCase +class SkillsTest extends BaseTestCase { public static function setUpBeforeClass(): void { diff --git a/tests/Relationship/AffiliationTest.php b/tests/Relationship/AffiliationTest.php new file mode 100644 index 00000000..07cb998e --- /dev/null +++ b/tests/Relationship/AffiliationTest.php @@ -0,0 +1,139 @@ + 180548812, + 'corporation_id' => 109299958, + ]); + + $entity = UniverseName::create([ + 'entity_id' => 180548812, + 'category' => 'character', + 'name' => 'CCP Hellmar', + ]); + + $this->assertEquals($entity->entity_id, $affiliation->character->entity_id); + } + + public function testHasDefaultCharacter() + { + $affiliation = CharacterAffiliation::create([ + 'character_id' => 180548812, + 'corporation_id' => 109299958, + ]); + + $this->assertNotNull($affiliation->character); + } + + public function testHasCorporation() + { + $affiliation = CharacterAffiliation::create([ + 'character_id' => 180548812, + 'corporation_id' => 109299958, + ]); + + $entity = UniverseName::create([ + 'entity_id' => 109299958, + 'category' => 'corporation', + 'name' => 'C C P', + ]); + + $this->assertEquals($entity->entity_id, $affiliation->corporation->entity_id); + } + + public function testHasDefaultCorporation() + { + $affiliation = CharacterAffiliation::create([ + 'character_id' => 180548812, + 'corporation_id' => 109299958, + ]); + + $this->assertNotNull($affiliation->corporation); + } + + public function testHasAlliance() + { + $affiliation = CharacterAffiliation::create([ + 'character_id' => 180548812, + 'corporation_id' => 109299958, + 'alliance_id' => 434243723, + ]); + + $entity = UniverseName::create([ + 'entity_id' => 434243723, + 'category' => 'alliance', + 'name' => 'C C P Alliance', + ]); + + $this->assertEquals($entity->entity_id, $affiliation->alliance->entity_id); + } + + public function testDefaultAlliance() + { + $affiliation = CharacterAffiliation::create([ + 'character_id' => 180548812, + 'corporation_id' => 109299958, + ]); + + $this->assertNotNull($affiliation->alliance); + } + + public function testHasFaction() + { + $affiliation = CharacterAffiliation::create([ + 'character_id' => 180548812, + 'corporation_id' => 109299958, + 'faction_id' => 500001, + ]); + + $entity = UniverseName::create([ + 'entity_id' => 500001, + 'category' => 'faction', + 'name' => 'Caldari State', + ]); + + $this->assertEquals($entity->entity_id, $affiliation->faction->entity_id); + } + + public function testHasDefaultFaction() + { + $affiliation = CharacterAffiliation::create([ + 'character_id' => 180548812, + 'corporation_id' => 109299958, + ]); + + $this->assertNotNull($affiliation->faction); + } +} diff --git a/tests/Relationship/CharacterTest.php b/tests/Relationship/CharacterTest.php new file mode 100644 index 00000000..fa04978f --- /dev/null +++ b/tests/Relationship/CharacterTest.php @@ -0,0 +1,261 @@ +character = CharacterInfo::create([ + 'character_id' => 180548812, + 'ancestry_id' => 19, + 'birthday' => "2015-03-24T11:37:00Z", + 'bloodline_id' => 3, + 'gender' => 'male', + 'name' => 'CCP Bartender', + 'race_id' => 2, + 'title' => 'Original title', + ]); + } + + public function testHasAffiliation() + { + $affiliation = new CharacterAffiliation([ + 'corporation_id' => 109299958, + ]); + + $this->character->affiliation()->save($affiliation); + + $this->assertEquals($affiliation->corporation_id, $this->character->affiliation->corporation_id); + } + + public function testHasDefaultAffiliation() + { + $this->assertNotNull($this->character->affiliation); + } + + public function testHasAgentResearches() + { + $this->character->agent_research()->save(new CharacterAgentResearch([ + 'agent_id'=> 3014221, + 'points_per_day'=> 31.25, + 'remainder_points'=> 76877.06, + 'skill_type_id'=> 11445, + 'started_at'=> '2016-01-10T00:39:55Z', + ])); + + $this->character->agent_research()->save(new CharacterAgentResearch([ + 'agent_id'=> 3012880, + 'points_per_day'=> 21.93, + 'remainder_points'=> -12950.18, + 'skill_type_id'=> 11450, + 'started_at'=> '2015-06-04T05:41:09Z', + ])); + + $this->character->agent_research()->save(new CharacterAgentResearch([ + 'agent_id'=> 3011474, + 'points_per_day'=> 12.78, + 'remainder_points'=> 35.10, + 'skill_type_id'=> 11446, + 'started_at'=> '2019-04-22T12:25:28Z', + ])); + + $this->assertCount(3, $this->character->agent_research); + } + + public function testHasBalance() + { + $balance = new CharacterWalletBalance([ + 'balance' => 29500.01, + ]); + + $this->character->balance()->save($balance); + + $this->assertEquals($balance->balance, $this->character->balance->balance); + } + + public function testHasBlueprints() + { + $this->character->blueprints()->save(new CharacterBlueprint([ + 'item_id' => 1000000010495, + 'location_flag' => 'Hangar', + 'location_id' => 60014719, + 'material_efficiency' => 0, + 'quantity' => 1, + 'runs' => -1, + 'time_efficiency' => 0, + 'type_id' => 691, + ])); + + $this->character->blueprints()->save(new CharacterBlueprint([ + 'item_id' => 1000000010496, + 'location_flag' => 'Hangar', + 'location_id' => 60014719, + 'material_efficiency' => 5, + 'quantity' => 1, + 'runs' => 17, + 'time_efficiency' => 3, + 'type_id' => 692, + ])); + + $this->character->blueprints()->save(new CharacterBlueprint([ + 'item_id' => 1000000010497, + 'location_flag' => 'Cargo', + 'location_id' => 60014719, + 'material_efficiency' => 1, + 'quantity' => 1, + 'runs' => 3, + 'time_efficiency' => 7, + 'type_id' => 693, + ])); + + $this->assertCount(3, $this->character->blueprints); + } + + public function testHasCorporationHistory() + { + $this->character->corporation_history()->save(new CharacterCorporationHistory([ + 'corporation_id' => 90000001, + 'is_deleted' => true, + 'record_id' => 500, + 'start_date' => '2016-06-26T20:00:00Z', + ])); + + $this->character->corporation_history()->save(new CharacterCorporationHistory([ + 'corporation_id' => 90000002, + 'record_id' => 501, + 'start_date' => '2016-07-26T20:00:00Z', + ])); + + $this->assertCount(2, $this->character->corporation_history); + } + + public function testHasFatigue() + { + $fatigue = new CharacterFatigue([ + 'jump_fatigue_expire_date' => '2017-07-05T15:42:00Z', + 'last_jump_date' => '2017-07-05T15:42:00Z', + 'last_update_date' => '2017-07-05T15:42:00Z', + ]); + + $this->character->fatigue()->save($fatigue); + + $this->assertEquals($fatigue->last_update_date, $this->character->fatigue->last_update_date); + } + + public function testHasDefaultFatigue() + { + $this->assertNotNull($this->character->fatigue); + } + + public function testHasLocation() + { + $location = new CharacterLocation([ + 'solar_system_id' => 30002505, + 'structure_id' => 1000000016989, + ]); + + $this->character->location()->save($location); + + $this->assertEquals($location->solar_system_id, $this->character->location->solar_system_id); + } + + public function testIsOnline() + { + $online = new CharacterOnline([ + 'last_login' => '2017-01-02T03:04:05Z', + 'last_logout' => '2017-01-02T04:05:06Z', + 'logins' => 9001, + 'online' => true, + ]); + + $this->character->online()->save($online); + + $this->assertEquals($online->online, $this->character->online->online); + } + + public function testHasSkillpoints() + { + $skill_info = new CharacterInfoSkill([ + 'total_sp' => 20000, + ]); + + $this->character->skillpoints()->save($skill_info); + + $this->assertEquals($skill_info->total_sp, $this->character->skillpoints->total_sp); + } + + public function testHasSkills() + { + $this->character->skills()->save(new CharacterSkill([ + 'skill_id' => 3, + 'skillpoints_in_skill' => 10000, + 'trained_skill_level' => 4, + 'active_skill_level' => 3, + ])); + + $this->character->skills()->save(new CharacterSkill([ + 'skill_id' => 2, + 'skillpoints_in_skill' => 10000, + 'trained_skill_level' => 1, + 'active_skill_level' => 1, + ])); + + $this->assertCount(2, $this->character->skills); + } + + public function testHasShip() + { + $ship = new CharacterShip([ + 'ship_item_id' => 1000000016991, + 'ship_name' => 'SPACESHIPS!!!', + 'ship_type_id' => 1233, + ]); + + $this->character->ship()->save($ship); + + $this->assertEquals($ship->ship_name, $this->character->ship->ship_name); + } +} diff --git a/tests/database/migrations/2021_03_20_105237_create_character_corporation_histories_table.php b/tests/database/migrations/2021_03_20_105237_create_character_corporation_histories_table.php index 0da39db2..c69149e5 100644 --- a/tests/database/migrations/2021_03_20_105237_create_character_corporation_histories_table.php +++ b/tests/database/migrations/2021_03_20_105237_create_character_corporation_histories_table.php @@ -43,7 +43,7 @@ public function up() $table->bigInteger('character_id'); $table->dateTime('start_date'); $table->bigInteger('corporation_id'); - $table->boolean('is_deleted'); + $table->boolean('is_deleted')->nullable(); $table->integer('record_id'); $table->index(['character_id']); diff --git a/tests/database/migrations/2021_04_04_234242_create_character_wallet_balance_table.php b/tests/database/migrations/2021_04_04_234242_create_character_wallet_balance_table.php new file mode 100644 index 00000000..e4487615 --- /dev/null +++ b/tests/database/migrations/2021_04_04_234242_create_character_wallet_balance_table.php @@ -0,0 +1,59 @@ +bigInteger('character_id'); + $table->double('balance'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_wallet_balances'); + } +} diff --git a/tests/database/migrations/2021_04_04_235517_create_character_locations_table.php b/tests/database/migrations/2021_04_04_235517_create_character_locations_table.php new file mode 100644 index 00000000..cd5d2101 --- /dev/null +++ b/tests/database/migrations/2021_04_04_235517_create_character_locations_table.php @@ -0,0 +1,61 @@ +bigInteger('character_id'); + $table->integer('solar_system_id'); + $table->integer('station_id')->nullable(); + $table->bigInteger('structure_id')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_locations'); + } +} diff --git a/tests/database/migrations/2021_04_04_235842_create_character_onlines_table.php b/tests/database/migrations/2021_04_04_235842_create_character_onlines_table.php new file mode 100644 index 00000000..46c287e4 --- /dev/null +++ b/tests/database/migrations/2021_04_04_235842_create_character_onlines_table.php @@ -0,0 +1,62 @@ +bigInteger('character_id'); + $table->dateTime('last_login')->nullable(); + $table->dateTime('last_logout')->nullable(); + $table->integer('logins')->nullable(); + $table->boolean('online'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_onlines'); + } +} diff --git a/tests/database/migrations/2021_04_05_000821_create_character_ships_table.php b/tests/database/migrations/2021_04_05_000821_create_character_ships_table.php new file mode 100644 index 00000000..aa874200 --- /dev/null +++ b/tests/database/migrations/2021_04_05_000821_create_character_ships_table.php @@ -0,0 +1,61 @@ +bigInteger('character_id'); + $table->bigInteger('ship_item_id'); + $table->string('ship_name'); + $table->integer('ship_type_id'); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + + Schema::dropIfExists('character_ships'); + } +} From 44151f801426eb786b5d5a0703cee0b4b219964d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Leuilliot?= Date: Mon, 5 Apr 2021 08:33:04 +0200 Subject: [PATCH 42/42] ci: test codecov --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d4feed4f..68e652b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,4 +13,6 @@ before_script: script: - vendor/bin/phpunit -c phpunit.xml after_script: - - ./cc-test-reporter after-build \ No newline at end of file + - ./cc-test-reporter after-build +after_success: + - bash <(curl -s https://codecov.io/bash)