Skip to content

Commit 60681c5

Browse files
authored
Merge pull request #2 from ByteInternet/logbook_querying
Logbook querying
2 parents 94bfe56 + a5ef655 commit 60681c5

File tree

9 files changed

+298
-5
lines changed

9 files changed

+298
-5
lines changed

composer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@
2121
"require": {
2222
"ext-curl": "*",
2323
"ext-json": "*",
24-
"symfony/polyfill-php80": "^1.0",
24+
"nesbot/carbon": "^2.0",
2525
"psr/http-client-implementation": "^1.0",
2626
"php-http/client-common": "^2.5",
27-
"php-http/discovery": "^1.14"
27+
"php-http/discovery": "^1.14",
28+
"symfony/polyfill-php80": "^1.0"
2829
},
2930
"require-dev": {
3031
"friendsofphp/php-cs-fixer": "^3.9",

src/HypernodeClient.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
namespace Hypernode\Api;
66

7-
use Http\Client\Common\HttpMethodsClient;
87
use Http\Client\Common\HttpMethodsClientInterface;
98
use Hypernode\Api\Exception\HypernodeApiClientException;
109
use Hypernode\Api\Exception\HypernodeApiServerException;
1110
use Hypernode\Api\Service\App;
11+
use Hypernode\Api\Service\Logbook;
1212
use Hypernode\Api\Service\Settings;
1313
use Psr\Http\Message\ResponseInterface;
1414

@@ -19,12 +19,14 @@ class HypernodeClient
1919
public HttpMethodsClientInterface $api;
2020
public App $app;
2121
public Settings $settings;
22+
public Logbook $logbook;
2223

2324
public function __construct(HttpMethodsClientInterface $apiClient)
2425
{
2526
$this->api = $apiClient;
2627
$this->app = new App($this);
2728
$this->settings = new Settings($this);
29+
$this->logbook = new Logbook($this);
2830
}
2931

3032
public function getJsonFromResponse(ResponseInterface $response)

src/Resource/AbstractResource.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,22 @@
44

55
namespace Hypernode\Api\Resource;
66

7+
use Carbon\Carbon;
8+
79
class AbstractResource
810
{
911
protected array $data;
12+
protected array $dateAttributes = [];
1013

1114
public function __get(string $name)
1215
{
13-
return $this->data[$name] ?? null;
16+
$value = $this->data[$name] ?? null;
17+
18+
if (in_array($name, $this->dateAttributes)) {
19+
return Carbon::create($value);
20+
}
21+
22+
return $value;
1423
}
1524

1625
public function __isset($name)

src/Resource/Logbook/Flow.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Hypernode\Api\Resource\Logbook;
6+
7+
use Carbon\Carbon;
8+
use Hypernode\Api\Resource\AbstractResource;
9+
10+
/**
11+
* @property-read string $state
12+
* @property-read string $name
13+
* @property-read string $app_name
14+
* @property-read Carbon $created_at
15+
* @property-read Carbon $updated_at
16+
*/
17+
class Flow extends AbstractResource
18+
{
19+
public const STATE_SUCCESS = 'success';
20+
public const STATE_REVERTED = 'reverted';
21+
public const STATE_RUNNING = 'running';
22+
public const STATE_WAITING = 'waiting';
23+
24+
protected array $dateAttributes = [
25+
'created_at',
26+
'updated_at',
27+
];
28+
29+
public function __construct(array $data)
30+
{
31+
$this->data = $data;
32+
}
33+
34+
public function isReverted(): bool
35+
{
36+
return $this->state === self::STATE_REVERTED;
37+
}
38+
39+
public function isComplete(): bool
40+
{
41+
return $this->state === self::STATE_SUCCESS;
42+
}
43+
44+
public function isRunning(): bool
45+
{
46+
return $this->state === self::STATE_RUNNING;
47+
}
48+
49+
public function isWaiting(): bool
50+
{
51+
return empty($this->state) || $this->state === self::STATE_WAITING;
52+
}
53+
}

src/Service/App.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@
77
class App extends AbstractService
88
{
99
public const V2_APP_DETAIL_URL = "/v2/app/%s/";
10-
}
10+
public const V1_APP_FLOWS_URL = "/logbook/v1/logbooks/%s/flows/";
11+
}

src/Service/Logbook.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Hypernode\Api\Service;
6+
7+
use Hypernode\Api\Exception\HypernodeApiClientException;
8+
use Hypernode\Api\Exception\HypernodeApiServerException;
9+
use Hypernode\Api\Resource\Logbook\Flow;
10+
11+
class Logbook extends AbstractService
12+
{
13+
/**
14+
* Get jobs (complete and non-complete) from logbook for given Hypernode.
15+
*
16+
* @param string $app Name of the hypernode
17+
* @param int $amount
18+
* @return Flow[]
19+
* @throws HypernodeApiClientException
20+
* @throws HypernodeApiServerException
21+
*/
22+
public function getList(string $app, int $amount = 50): array
23+
{
24+
/** @var Flow[] $result */
25+
$result = [];
26+
27+
$url = sprintf(App::V1_APP_FLOWS_URL, $app);
28+
29+
$data = ['next' => $url];
30+
while (count($result) < $amount && $data['next']) {
31+
$response = $this->client->api->get($data['next']);
32+
$this->client->maybeThrowApiExceptions($response);
33+
$data = $this->client->getJsonFromResponse($response);
34+
foreach ($data['results'] as $flowData) {
35+
$result[] = new Flow($flowData);
36+
}
37+
}
38+
39+
return $result;
40+
}
41+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Hypernode\Api\Resource\Logbook;
6+
7+
use Carbon\Carbon;
8+
use PHPUnit\Framework\TestCase;
9+
10+
class FlowTest extends TestCase
11+
{
12+
public function testCreatedAtDate()
13+
{
14+
$flow = new Flow(['created_at' => '2022-09-12T09:00:00Z']);
15+
$this->assertInstanceOf(Carbon::class, $flow->created_at);
16+
}
17+
18+
public function testUpdatedAtDate()
19+
{
20+
$flow = new Flow(['updated_at' => '2022-09-12T09:00:00Z']);
21+
$this->assertInstanceOf(Carbon::class, $flow->updated_at);
22+
}
23+
24+
public function testIsRevertedReturnsTrue()
25+
{
26+
$flow = new Flow(['state' => 'reverted']);
27+
$this->assertTrue($flow->isReverted());
28+
}
29+
30+
public function testIsRevertedReturnsFalse()
31+
{
32+
$flow = new Flow(['state' => 'running']);
33+
$this->assertFalse($flow->isReverted());
34+
}
35+
36+
public function testIsCompleteReturnTrue()
37+
{
38+
$flow = new Flow(['state' => 'success']);
39+
$this->assertTrue($flow->isComplete());
40+
}
41+
42+
public function testIsCompleteReturnFalse()
43+
{
44+
$flow = new Flow(['state' => 'running']);
45+
$this->assertFalse($flow->isComplete());
46+
}
47+
48+
public function testIsRunningReturnsTrue()
49+
{
50+
$flow = new Flow(['state' => 'running']);
51+
$this->assertTrue($flow->isRunning());
52+
}
53+
54+
public function testIsRunningReturnsFalse()
55+
{
56+
$flow = new Flow(['state' => 'success']);
57+
$this->assertFalse($flow->isRunning());
58+
}
59+
60+
public function testIsWaitingReturnsTrueForEmptyState()
61+
{
62+
$flow = new Flow(['state' => null]);
63+
$this->assertTrue($flow->isWaiting());
64+
}
65+
66+
public function testIsWaitingReturnsTrue()
67+
{
68+
$flow = new Flow(['state' => 'waiting']);
69+
$this->assertTrue($flow->isWaiting());
70+
}
71+
72+
public function testIsWaitingReturnsFalse()
73+
{
74+
$flow = new Flow(['state' => 'running']);
75+
$this->assertFalse($flow->isWaiting());
76+
}
77+
}

tests/unit/Resource/Logbook/JobTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use GuzzleHttp\Psr7\Response;
66
use Hypernode\Api\HypernodeClientTestCase;
7+
use Hypernode\Api\Resource\AbstractResource;
78

89
class JobTest extends HypernodeClientTestCase
910
{
@@ -17,6 +18,11 @@ protected function setUp(): void
1718
$this->job = new Job($this->client, $this->jobUrl);
1819
}
1920

21+
public function testIsInstanceOfAbstractResource()
22+
{
23+
$this->assertInstanceOf(AbstractResource::class, $this->job);
24+
}
25+
2026
public function testRefresh()
2127
{
2228
$this->responses->append(

tests/unit/Service/LogbookTest.php

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Hypernode\Api\Service;
6+
7+
use GuzzleHttp\Psr7\Response;
8+
use Hypernode\Api\HypernodeClientTestCase;
9+
use Hypernode\Api\Resource\Logbook\Flow;
10+
11+
class LogbookTest extends HypernodeClientTestCase
12+
{
13+
public function testGetListFetchesLogbook()
14+
{
15+
$this->responses->append(
16+
new Response(200, [], json_encode([
17+
'count' => 2,
18+
'next' => null,
19+
'previous' => null,
20+
'results' => [
21+
[
22+
'uuid' => 'c130c04f-794e-4f55-b34b-eb8f60472224',
23+
'state' => 'running',
24+
'name' => 'update_node',
25+
'created_at' => '2022-09-12T12:19:15Z',
26+
'updated_at' => '2022-09-12T12:20:30Z',
27+
'logbook' => 'johndoe',
28+
],
29+
[
30+
'uuid' => 'e2f39684-3ce0-48d1-acda-13fa064709b5',
31+
'state' => 'success',
32+
'name' => 'create_backup',
33+
'created_at' => '2022-09-12T11:08:10Z',
34+
'updated_at' => '2022-09-12T11:08:27Z',
35+
'logbook' => 'johndoe',
36+
],
37+
]
38+
])),
39+
);
40+
41+
$flows = $this->client->logbook->getList('johndoe');
42+
[$flow1, $flow2] = $flows;
43+
44+
$this->assertCount(2, $flows);
45+
46+
$this->assertInstanceOf(Flow::class, $flow1);
47+
$this->assertEquals('running', $flow1->state);
48+
$this->assertEquals('update_node', $flow1->name);
49+
50+
$this->assertInstanceOf(Flow::class, $flow2);
51+
$this->assertEquals('success', $flow2->state);
52+
$this->assertEquals('create_backup', $flow2->name);
53+
}
54+
55+
public function testGetListPagesThroughLogbook()
56+
{
57+
$this->responses->append(
58+
new Response(200, [], json_encode([
59+
'count' => 1,
60+
'next' => 'https://api.hypernode.com/logbook/v1/logbooks/johndoe/flows/',
61+
'previous' => null,
62+
'results' => [
63+
[
64+
'uuid' => 'c130c04f-794e-4f55-b34b-eb8f60472224',
65+
'state' => 'running',
66+
'name' => 'update_node',
67+
'created_at' => '2022-09-12T12:19:15Z',
68+
'updated_at' => '2022-09-12T12:20:30Z',
69+
'logbook' => 'johndoe',
70+
],
71+
]
72+
])),
73+
new Response(200, [], json_encode([
74+
'count' => 1,
75+
'next' => null,
76+
'previous' => null,
77+
'results' => [
78+
[
79+
'uuid' => 'e2f39684-3ce0-48d1-acda-13fa064709b5',
80+
'state' => 'success',
81+
'name' => 'create_backup',
82+
'created_at' => '2022-09-12T11:08:10Z',
83+
'updated_at' => '2022-09-12T11:08:27Z',
84+
'logbook' => 'johndoe',
85+
],
86+
]
87+
])),
88+
);
89+
90+
$flows = $this->client->logbook->getList('johndoe');
91+
[$flow1, $flow2] = $flows;
92+
93+
$this->assertCount(2, $flows);
94+
95+
$this->assertInstanceOf(Flow::class, $flow1);
96+
$this->assertEquals('running', $flow1->state);
97+
$this->assertEquals('update_node', $flow1->name);
98+
99+
$this->assertInstanceOf(Flow::class, $flow2);
100+
$this->assertEquals('success', $flow2->state);
101+
$this->assertEquals('create_backup', $flow2->name);
102+
}
103+
}

0 commit comments

Comments
 (0)