From 570dabccb4d5b4b8c67e1e746b8b648e35751a96 Mon Sep 17 00:00:00 2001 From: Eric Wang <37554696+ericwang401@users.noreply.github.com> Date: Mon, 4 Mar 2024 14:53:22 -0600 Subject: [PATCH] Add ISO tests --- .../Admin/Nodes/Isos/UpdateIsoRequest.php | 3 +- .../Proxmox/Node/ProxmoxStorageRepository.php | 77 +++++------ app/Services/Isos/IsoService.php | 6 +- .../Admin/Nodes/IsoControllerTest.php | 122 ++++++++++++++++++ .../Node/Storage/DeleteIsoData.json | 4 + .../Node/Storage/DownloadIsoData.json | 4 + .../Node/Storage/QueryIsoData.json | 8 ++ 7 files changed, 184 insertions(+), 40 deletions(-) create mode 100644 tests/Feature/Controllers/Admin/Nodes/IsoControllerTest.php create mode 100644 tests/Fixtures/Repositories/Node/Storage/DeleteIsoData.json create mode 100644 tests/Fixtures/Repositories/Node/Storage/DownloadIsoData.json create mode 100644 tests/Fixtures/Repositories/Node/Storage/QueryIsoData.json diff --git a/app/Http/Requests/Admin/Nodes/Isos/UpdateIsoRequest.php b/app/Http/Requests/Admin/Nodes/Isos/UpdateIsoRequest.php index ce77d91f03c..225859c1b59 100644 --- a/app/Http/Requests/Admin/Nodes/Isos/UpdateIsoRequest.php +++ b/app/Http/Requests/Admin/Nodes/Isos/UpdateIsoRequest.php @@ -2,8 +2,8 @@ namespace Convoy\Http\Requests\Admin\Nodes\Isos; -use Convoy\Models\ISO; use Convoy\Http\Requests\BaseApiRequest; +use Convoy\Models\ISO; class UpdateIsoRequest extends BaseApiRequest { @@ -16,4 +16,5 @@ public function rules(): array 'hidden' => $rules['hidden'], ]; } + } diff --git a/app/Repositories/Proxmox/Node/ProxmoxStorageRepository.php b/app/Repositories/Proxmox/Node/ProxmoxStorageRepository.php index 98acad01fc0..a9887166d0b 100644 --- a/app/Repositories/Proxmox/Node/ProxmoxStorageRepository.php +++ b/app/Repositories/Proxmox/Node/ProxmoxStorageRepository.php @@ -2,20 +2,25 @@ namespace Convoy\Repositories\Proxmox\Node; -use Convoy\Models\Node; use Carbon\CarbonImmutable; -use Illuminate\Support\Arr; -use Webmozart\Assert\Assert; use Convoy\Data\Helpers\ChecksumData; -use Convoy\Data\Node\Storage\IsoData; use Convoy\Data\Node\Storage\FileMetaData; +use Convoy\Data\Node\Storage\IsoData; use Convoy\Enums\Node\Storage\ContentType; -use Convoy\Repositories\Proxmox\ProxmoxRepository; use Convoy\Exceptions\Service\Node\IsoLibrary\InvalidIsoLinkException; +use Convoy\Models\Node; +use Convoy\Repositories\Proxmox\ProxmoxRepository; +use Illuminate\Support\Arr; +use Spatie\LaravelData\DataCollection; +use Webmozart\Assert\Assert; class ProxmoxStorageRepository extends ProxmoxRepository { - public function download(ContentType $contentType, string $fileName, string $link, ?bool $verifyCertificates = true, ?ChecksumData $checksumData = null) + public function download( + ContentType $contentType, string $fileName, string $link, + ?bool $verifyCertificates = true, + ?ChecksumData $checksumData = null, + ) { Assert::isInstanceOf($this->node, Node::class); Assert::regex($link, '/^(http|https):\/\//'); @@ -33,12 +38,12 @@ public function download(ContentType $contentType, string $fileName, string $lin } $response = $this->getHttpClient() - ->withUrlParameters([ - 'node' => $this->node->cluster, - 'storage' => $this->node->iso_storage, - ]) - ->post('/api2/json/nodes/{node}/storage/{storage}/download-url', $payload) - ->json(); + ->withUrlParameters([ + 'node' => $this->node->cluster, + 'storage' => $this->node->iso_storage, + ]) + ->post('/api2/json/nodes/{node}/storage/{storage}/download-url', $payload) + ->json(); return $this->getData($response); } @@ -48,28 +53,28 @@ public function deleteFile(ContentType $contentType, string $fileName) Assert::isInstanceOf($this->node, Node::class); $response = $this->getHttpClient() - ->withUrlParameters([ - 'node' => $this->node->cluster, - 'storage' => $this->node->iso_storage, - 'file' => "{$this->node->iso_storage}:$contentType->value/$fileName", - ]) - ->delete('/api2/json/nodes/{node}/storage/{storage}/content/{file}') - ->json(); + ->withUrlParameters([ + 'node' => $this->node->cluster, + 'storage' => $this->node->iso_storage, + 'file' => "{$this->node->iso_storage}:$contentType->value/$fileName", + ]) + ->delete('/api2/json/nodes/{node}/storage/{storage}/content/{file}') + ->json(); return $this->getData($response); } - public function getIsos() + public function getIsos(): DataCollection { Assert::isInstanceOf($this->node, Node::class); $response = $this->getHttpClient() - ->withUrlParameters([ - 'node' => $this->node->cluster, - 'storage' => $this->node->iso_storage, - ]) - ->get('/api2/json/nodes/{node}/storage/{storage}/content?content=iso') - ->json(); + ->withUrlParameters([ + 'node' => $this->node->cluster, + 'storage' => $this->node->iso_storage, + ]) + ->get('/api2/json/nodes/{node}/storage/{storage}/content?content=iso') + ->json(); $response = $this->getData($response); @@ -86,23 +91,23 @@ public function getIsos() return IsoData::collection($isos); } - public function getFileMetadata(string $link, ?bool $verifyCertificates = true): FileMetaData + public function getFileMetadata(string $link, bool $verifyCertificates = true): FileMetaData { Assert::isInstanceOf($this->node, Node::class); Assert::regex($link, '/^(http|https):\/\//'); $response = $this->getHttpClient() - ->withUrlParameters([ - 'node' => $this->node->cluster, - ]) - ->get('/api2/json/nodes/{node}/query-url-metadata', [ - 'url' => $link, - 'verify-certificates' => $verifyCertificates, - ]) - ->json(); + ->withUrlParameters([ + 'node' => $this->node->cluster, + ]) + ->get('/api2/json/nodes/{node}/query-url-metadata', [ + 'url' => $link, + 'verify-certificates' => $verifyCertificates, + ]) + ->json(); if (Arr::get($response, 'success', 1) !== 1) { - throw new InvalidIsoLinkException; + throw new InvalidIsoLinkException(); } $data = $this->getData($response); diff --git a/app/Services/Isos/IsoService.php b/app/Services/Isos/IsoService.php index fc17090ab86..f6e31f735f7 100644 --- a/app/Services/Isos/IsoService.php +++ b/app/Services/Isos/IsoService.php @@ -21,7 +21,7 @@ public function __construct( } public function download( - Node $node, string $name, ?string $fileName, string $link, + Node $node, string $name, ?string $fileName, string $link, ?ChecksumData $checksumData = null, ?bool $hidden = false, ) { @@ -57,11 +57,11 @@ public function getIso(Node $node, string $fileName): ?IsoData return $isos->where('file_name', '=', $fileName)->first(); } - public function delete(Node $node, ISO $iso) + public function delete(Node $node, ISO $iso): void { if (is_null($iso->completed_at)) { throw new BadRequestHttpException( - 'This ISO cannot be restored at this time: not completed.', + 'This ISO cannot be deleted at this time: not completed.', ); } diff --git a/tests/Feature/Controllers/Admin/Nodes/IsoControllerTest.php b/tests/Feature/Controllers/Admin/Nodes/IsoControllerTest.php new file mode 100644 index 00000000000..ddc75b16f1e --- /dev/null +++ b/tests/Feature/Controllers/Admin/Nodes/IsoControllerTest.php @@ -0,0 +1,122 @@ +user = User::factory()->create([ + 'root_admin' => true, + ]); + $this->location = Location::factory()->create(); + $this->node = Node::factory()->for($this->location)->create(); +}); + +it('can fetch ISOs', function () { + $response = $this->actingAs($this->user)->getJson( + "/api/admin/nodes/{$this->node->id}/isos", + ); + + $response->assertOk(); +}); + +it('can create an ISO', function () { + Http::fake([ + '*/download-url' => Http::response( + file_get_contents( + base_path('tests/Fixtures/Repositories/Node/Storage/DownloadIsoData.json'), + ), + 200, + ), + '*/query-url-metadata*' => Http::response( + file_get_contents( + base_path('tests/Fixtures/Repositories/Node/Storage/QueryIsoData.json'), + ), + 200, + ), + ]); + + $response = $this->actingAs($this->user)->postJson( + "/api/admin/nodes/{$this->node->id}/isos", + [ + 'name' => 'Test ISO', + 'file_name' => 'test.iso', + 'link' => 'https://example.com/test.iso', + 'should_download' => true, + 'hidden' => false, + ], + ); + + Queue::assertPushed(MonitorIsoDownloadJob::class); + $response->assertOk(); +}); + +it("can't create an ISO with file_name taken", function () { + ISO::factory()->for($this->node)->create([ + 'file_name' => 'duplicate.iso', + ]); + + $response = $this->actingAs($this->user)->postJson( + "/api/admin/nodes/{$this->node->id}/isos", + [ + 'name' => 'Test ISO', + 'file_name' => 'duplicate.iso', + 'link' => 'https://example.com/duplicate.iso', + 'should_download' => true, + 'hidden' => false, + ], + ); + + $response->assertStatus(422); +}); + +it('can update an ISO', function () { + $iso = ISO::factory()->for($this->node)->create(); + + $response = $this->actingAs($this->user)->putJson( + "/api/admin/nodes/{$this->node->id}/isos/{$iso->uuid}", + [ + 'name' => 'Updated ISO', + ], + ); + + $response->assertOk(); +}); + +it('can delete an ISO', function () { + Http::fake([ + '*/storage/*/content/*' => Http::response( + file_get_contents( + base_path('tests/Fixtures/Repositories/Node/Storage/DeleteIsoData.json'), + ), 200, + ), + ]); + $iso = ISO::factory()->for($this->node)->create(); + + $response = $this->actingAs($this->user)->deleteJson( + "/api/admin/nodes/{$this->node->id}/isos/{$iso->uuid}", + ); + + $response->assertNoContent(); +}); + +it('can query link', function () { + Http::fake([ + '*/query-url-metadata*' => Http::response( + file_get_contents( + base_path('tests/Fixtures/Repositories/Node/Storage/QueryIsoData.json'), + ), + 200, + ), + ]); + + $response = $this->actingAs($this->user)->getJson( + '/tools/query-remote-file?link=' . urlencode( + 'https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso', + ), + ); + + $response->assertOk(); +}); \ No newline at end of file diff --git a/tests/Fixtures/Repositories/Node/Storage/DeleteIsoData.json b/tests/Fixtures/Repositories/Node/Storage/DeleteIsoData.json new file mode 100644 index 00000000000..69fbd7c7fcf --- /dev/null +++ b/tests/Fixtures/Repositories/Node/Storage/DeleteIsoData.json @@ -0,0 +1,4 @@ +{ + "success": 1, + "data": null +} \ No newline at end of file diff --git a/tests/Fixtures/Repositories/Node/Storage/DownloadIsoData.json b/tests/Fixtures/Repositories/Node/Storage/DownloadIsoData.json new file mode 100644 index 00000000000..bd69cfbe1ae --- /dev/null +++ b/tests/Fixtures/Repositories/Node/Storage/DownloadIsoData.json @@ -0,0 +1,4 @@ +{ + "data": "UPID:us-southeast:001BE662:04671913:65CF8596:download:virtio-win.iso:root@pam:", + "success": 1 +} \ No newline at end of file diff --git a/tests/Fixtures/Repositories/Node/Storage/QueryIsoData.json b/tests/Fixtures/Repositories/Node/Storage/QueryIsoData.json new file mode 100644 index 00000000000..38a8aeb1b75 --- /dev/null +++ b/tests/Fixtures/Repositories/Node/Storage/QueryIsoData.json @@ -0,0 +1,8 @@ +{ + "data": { + "filename": "virtio-win.iso", + "size": 627519488, + "mimetype": "application/octet-stream" + }, + "success": 1 +} \ No newline at end of file