diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f892cf..ac48c04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ CHANGE LOG * Fixed hydration of object-backed App Platform and project resource fields * Fixed `LoadBalancer` hydration and update serialization * Fixed `Volume` hydration when `droplet_ids` is null +* Add support for listing Droplets by name or type ## 5.0.5 (03/05/2025) diff --git a/src/Api/Droplet.php b/src/Api/Droplet.php index a9053b3..a3a9f43 100644 --- a/src/Api/Droplet.php +++ b/src/Api/Droplet.php @@ -33,7 +33,59 @@ class Droplet extends AbstractApi */ public function getAll(?string $tag = null): array { - $droplets = $this->get('droplets', null === $tag ? [] : ['tag_name' => $tag]); + return $this->getAllWithQuery(null === $tag ? [] : ['tag_name' => $tag]); + } + + /** + * @throws ExceptionInterface + * + * @return DropletEntity[] + */ + public function getAllByTag(string $tag): array + { + return $this->getAllWithQuery(['tag_name' => $tag]); + } + + /** + * @param 'droplets'|'gpus'|null $type + * + * @throws ExceptionInterface + * + * @return DropletEntity[] + */ + public function getAllByName(string $name, ?string $type = null): array + { + $query = ['name' => $name]; + + if (null !== $type && \in_array($type, ['droplets', 'gpus'], true)) { + $query['type'] = $type; + } + + return $this->getAllWithQuery($query); + } + + /** + * @param 'droplets'|'gpus' $type + * + * @throws ExceptionInterface + * + * @return DropletEntity[] + */ + public function getAllByType(string $type): array + { + return $this->getAllWithQuery(\in_array($type, ['droplets', 'gpus'], true) ? ['type' => $type] : []); + } + + /** + * @param array $query + * + * @throws ExceptionInterface + * + * @return DropletEntity[] + */ + private function getAllWithQuery(array $query): array + { + $droplets = $this->get('droplets', $query); return \array_map(function ($droplet) { return new DropletEntity($droplet); diff --git a/tests/Api/DropletTest.php b/tests/Api/DropletTest.php new file mode 100644 index 0000000..a0f6458 --- /dev/null +++ b/tests/Api/DropletTest.php @@ -0,0 +1,116 @@ + + * (c) Graham Campbell + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace DigitalOceanV2\Tests\Api; + +use DigitalOceanV2\Api\Droplet; +use DigitalOceanV2\Client; +use DigitalOceanV2\Entity\Droplet as DropletEntity; +use GuzzleHttp\Psr7\Response; +use GuzzleHttp\Psr7\Utils; +use Http\Client\Common\HttpMethodsClientInterface; +use PHPUnit\Framework\TestCase; + +/** + * @author Graham Campbell + */ +class DropletTest extends TestCase +{ + public function testItCreatesAnArrayOfDropletEntities(): void + { + $droplets = $this->createApiExpectingGet('/v2/droplets')->getAll(); + + self::assertInstanceOf(DropletEntity::class, $droplets[0]); + self::assertSame('example.com', $droplets[0]->name); + } + + public function testItFiltersDropletsByTagName(): void + { + $droplets = $this->createApiExpectingGet('/v2/droplets?tag_name=awesome')->getAll('awesome'); + + self::assertInstanceOf(DropletEntity::class, $droplets[0]); + self::assertSame('example.com', $droplets[0]->name); + } + + public function testItFiltersDropletsByTagNameMethod(): void + { + $droplets = $this->createApiExpectingGet('/v2/droplets?tag_name=awesome')->getAllByTag('awesome'); + + self::assertInstanceOf(DropletEntity::class, $droplets[0]); + self::assertSame('example.com', $droplets[0]->name); + } + + public function testItFiltersDropletsByName(): void + { + $droplets = $this->createApiExpectingGet('/v2/droplets?name=example.com')->getAllByName('example.com'); + + self::assertInstanceOf(DropletEntity::class, $droplets[0]); + self::assertSame('example.com', $droplets[0]->name); + } + + public function testItFiltersDropletsByType(): void + { + $droplets = $this->createApiExpectingGet('/v2/droplets?type=gpus')->getAllByType('gpus'); + + self::assertInstanceOf(DropletEntity::class, $droplets[0]); + self::assertSame('example.com', $droplets[0]->name); + } + + public function testItFiltersDropletsByStandardType(): void + { + $droplets = $this->createApiExpectingGet('/v2/droplets?type=droplets')->getAllByType('droplets'); + + self::assertInstanceOf(DropletEntity::class, $droplets[0]); + self::assertSame('example.com', $droplets[0]->name); + } + + public function testItFiltersDropletsByNameAndType(): void + { + $droplets = $this->createApiExpectingGet('/v2/droplets?name=example.com&type=gpus') + ->getAllByName('example.com', 'gpus'); + + self::assertInstanceOf(DropletEntity::class, $droplets[0]); + self::assertSame('example.com', $droplets[0]->name); + } + + private function createApiExpectingGet(string $uri): Droplet + { + $client = $this->createMock(Client::class); + $client->expects(self::once()) + ->method('getHttpClient') + ->willReturn($httpClient = $this->createMock(HttpMethodsClientInterface::class)); + + $httpClient->expects(self::once()) + ->method('get') + ->with($uri) + ->willReturn(self::createResponse()); + + return new Droplet($client); + } + + private static function createResponse(): Response + { + return new Response( + 200, + ['Content-Type' => ['application/json']], + Utils::streamFor(\json_encode(['droplets' => [ + [ + 'id' => 3164444, + 'name' => 'example.com', + 'features' => [], + ], + ]])) + ); + } +}