Skip to content

Commit 9235483

Browse files
committed
service/settings: Fix job polling mechanism
Instead of using the unauthorized internal job URL, which is returned by the API, parse the job uuid from the URL and use that ID for polling on the proper endpoint. Ideally this is fixed in the API, but this is how it's been done in kamikaze so far as well, so let's first start here.
1 parent 2c7a821 commit 9235483

File tree

6 files changed

+156
-31
lines changed

6 files changed

+156
-31
lines changed

src/Defaults.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Hypernode\Api;
6+
7+
class Defaults {
8+
const HYPERNODE_API_URL = 'https://api.hypernode.com/';
9+
}

src/HypernodeClientFactory.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
class HypernodeClientFactory
1818
{
19-
public const HYPERNODE_API_URL = 'https://api.hypernode.com/';
20-
2119
public static function create(string $authToken, ?ClientInterface $httpClient = null): HypernodeClient
2220
{
2321
$httpHeaders = [
@@ -29,7 +27,7 @@ public static function create(string $authToken, ?ClientInterface $httpClient =
2927
'Accept' => 'application/json',
3028
'Content-Type' => 'application/json',
3129
];
32-
$httpClient = self::getHttpClient(self::HYPERNODE_API_URL, $httpHeaders, $httpClient);
30+
$httpClient = self::getHttpClient(Defaults::HYPERNODE_API_URL, $httpHeaders, $httpClient);
3331

3432
$apiClient = new HttpMethodsClient(
3533
$httpClient, Psr17FactoryDiscovery::findRequestFactory(), Psr17FactoryDiscovery::findStreamFactory()

src/Resource/Logbook/Job.php

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Hypernode\Api\HypernodeClient;
88
use Hypernode\Api\Resource\AbstractResource;
9+
use Hypernode\Api\Service\App;
910

1011
/**
1112
* @property-read string $result
@@ -15,17 +16,19 @@
1516
*/
1617
class Job extends AbstractResource
1718
{
18-
private string $url;
19+
private string $id;
20+
private string $appName;
1921
private bool $exists = false;
2022
private bool $running = false;
23+
private bool $success = false;
2124
private bool $complete = false;
22-
2325
protected HypernodeClient $client;
2426

25-
public function __construct(HypernodeClient $client, string $urlOrId, array $data = [])
27+
public function __construct(HypernodeClient $client, string $appName, string $id, array $data = [])
2628
{
2729
$this->client = $client;
28-
$this->url = $urlOrId;
30+
$this->appName = $appName;
31+
$this->id = $id;
2932
$this->data = $data;
3033
}
3134

@@ -37,37 +40,60 @@ public function __construct(HypernodeClient $client, string $urlOrId, array $dat
3740
*/
3841
public function refresh()
3942
{
40-
$response = $this->client->api->get($this->url);
43+
$url = sprintf(App::V1_APP_FLOWS_URL, $this->appName) . '?' . http_build_query(['tracker_uuid' => $this->id]);
44+
$response = $this->client->api->get($url);
45+
$this->data = $this->client->getJsonFromResponse($response);
4146

42-
if ($response->getStatusCode() === 404) {
47+
if ($response->getStatusCode() === 404 || $this->data['count'] === 0) {
4348
$this->data = [];
4449
$this->exists = false;
4550
$this->running = false;
4651
return;
4752
}
4853

49-
if ($response->getStatusCode() === 303) {
50-
$this->data = [];
51-
$this->exists = true;
52-
$this->running = false;
53-
$this->complete = true;
54-
return;
54+
$this->exists = true;
55+
56+
$result = $this->data['results'][0];
57+
switch ($result['state']) {
58+
case 'running':
59+
$this->running = true;
60+
break;
61+
case 'success':
62+
$this->success = true;
63+
$this->running = false;
64+
$this->complete = true;
65+
break;
66+
case 'reverted':
67+
$this->running = false;
68+
$this->complete = true;
69+
break;
5570
}
5671

5772
$this->client->maybeThrowApiExceptions($response);
73+
}
5874

59-
$this->data = $this->client->getJsonFromResponse($response);
60-
$this->exists = true;
61-
$this->running = true;
75+
public function id()
76+
{
77+
return $this->id;
6278
}
6379

6480
public function exists(): bool
6581
{
6682
return $this->exists;
6783
}
6884

85+
public function running(): bool
86+
{
87+
return $this->running;
88+
}
89+
6990
public function completed(): bool
7091
{
7192
return $this->complete;
7293
}
73-
}
94+
95+
public function success(): bool
96+
{
97+
return $this->success;
98+
}
99+
}

src/Service/Settings.php

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

55
namespace Hypernode\Api\Service;
66

7+
use Hypernode\Api\Defaults;
78
use Hypernode\Api\Resource\Logbook\Job;
89

910
class Settings extends AbstractService
1011
{
12+
public const JOB_URL_REGEX = '#' . Defaults::HYPERNODE_API_URL. 'logbook/v1/jobs/(.*)/#';
13+
1114
public function set(string $app, string $key, string $value): ?Job
1215
{
1316
return $this->setBatch($app, [$key => $value]);
@@ -21,7 +24,11 @@ public function setBatch(string $app, array $settings): ?Job
2124
$this->client->maybeThrowApiExceptions($response);
2225

2326
if ($response->getStatusCode() === 202) {
24-
$job = new Job($this->client, $response->getHeaderLine('Location'));
27+
$location = $response->getHeaderLine('Location');
28+
if (!preg_match(self::JOB_URL_REGEX, $location, $matches)) {
29+
return null;
30+
}
31+
$job = new Job($this->client, $app, $matches[1]);
2532
return $job;
2633
}
2734

tests/unit/Resource/Logbook/JobTest.php

Lines changed: 92 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ class JobTest extends HypernodeClientTestCase
1616
protected function setUp(): void
1717
{
1818
parent::setUp();
19-
$this->jobUrl = "https://api.hypernode.com/logbook/v1/jobs/abcd/";
20-
$this->job = new Job($this->client, $this->jobUrl);
19+
$this->job = new Job($this->client, 'johndoe', 'abcd');
2120
}
2221

2322
public function testIsInstanceOfAbstractResource()
@@ -29,17 +28,100 @@ public function testRefresh()
2928
{
3029
$this->responses->append(
3130
new Response(404, [], json_encode([])),
31+
new Response(200, [], json_encode(['count' => 0, 'results' => []])),
3232
new Response(200, [], json_encode([
33-
'result' => 'pending',
34-
'flow_name' => 'update_node',
35-
'app_name' => 'johndoe'
33+
'count' => 1,
34+
'results' => [
35+
[
36+
'uuid' => 'abcd',
37+
'state' => NULL,
38+
'name' => 'update_node'
39+
]
40+
]
3641
])),
3742
new Response(200, [], json_encode([
38-
'result' => 'running',
39-
'flow_name' => 'update_node',
40-
'app_name' => 'johndoe'
43+
'count' => 1,
44+
'results' => [
45+
[
46+
'uuid' => 'abcd',
47+
'state' => 'running',
48+
'name' => 'update_node'
49+
]
50+
]
51+
])),
52+
new Response(200, [], json_encode([
53+
'count' => 1,
54+
'results' => [
55+
[
56+
'uuid' => 'abcd',
57+
'state' => 'success',
58+
'name' => 'update_node'
59+
]
60+
]
61+
])),
62+
);
63+
64+
$this->job->refresh();
65+
66+
$this->assertFalse($this->job->exists());
67+
$this->assertFalse($this->job->completed());
68+
69+
$this->job->refresh();
70+
71+
$this->assertFalse($this->job->exists());
72+
$this->assertFalse($this->job->completed());
73+
74+
$this->job->refresh();
75+
76+
$this->assertTrue($this->job->exists());
77+
$this->assertFalse($this->job->completed());
78+
79+
$this->job->refresh();
80+
81+
$this->assertTrue($this->job->exists());
82+
$this->assertFalse($this->job->completed());
83+
84+
$this->job->refresh();
85+
86+
$this->assertTrue($this->job->exists());
87+
$this->assertTrue($this->job->completed());
88+
$this->assertTrue($this->job->success());
89+
}
90+
91+
public function testRefreshFailedJob()
92+
{
93+
$this->responses->append(
94+
new Response(404, [], json_encode([])),
95+
new Response(200, [], json_encode([
96+
'count' => 1,
97+
'results' => [
98+
[
99+
'uuid' => 'abcd',
100+
'state' => NULL,
101+
'name' => 'update_node'
102+
]
103+
]
104+
])),
105+
new Response(200, [], json_encode([
106+
'count' => 1,
107+
'results' => [
108+
[
109+
'uuid' => 'abcd',
110+
'state' => 'running',
111+
'name' => 'update_node'
112+
]
113+
]
114+
])),
115+
new Response(200, [], json_encode([
116+
'count' => 1,
117+
'results' => [
118+
[
119+
'uuid' => 'abcd',
120+
'state' => 'reverted',
121+
'name' => 'update_node'
122+
]
123+
]
41124
])),
42-
new Response(303, [], json_encode([])),
43125
);
44126

45127
$this->job->refresh();
@@ -61,6 +143,7 @@ public function testRefresh()
61143

62144
$this->assertTrue($this->job->exists());
63145
$this->assertTrue($this->job->completed());
146+
$this->assertFalse($this->job->success());
64147
}
65148

66149
public function testExistsReturnsFalseByDefault()

tests/unit/Service/SettingsTest.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,15 @@ public function testSetSingleSettingToDifferentValue()
3333
{
3434
$jobUrl = 'https://api.hypernode.com/logbook/v1/jobs/abcd/';
3535
$this->responses->append(
36-
new Response(202, ['Location: ' . $jobUrl], null),
36+
new Response(202, ['Location' => $jobUrl], null),
3737
);
3838

3939
$job = $this->client->settings->set('johndoe', 'php_version', '8.1');
4040

4141
$request = $this->responses->getLastRequest();
4242

4343
$this->assertNotNull($job);
44+
$this->assertEquals('abcd', $job->id());
4445
$this->assertEquals('PATCH', $request->getMethod());
4546
$this->assertEquals('/v2/app/johndoe/', $request->getUri());
4647
$this->assertJson((string)$request->getBody());
@@ -54,7 +55,7 @@ public function testSetMultipleSettings()
5455
{
5556
$jobUrl = 'https://api.hypernode.com/logbook/v1/jobs/abcd/';
5657
$this->responses->append(
57-
new Response(202, ['Location: ' . $jobUrl], null),
58+
new Response(202, ['Location' => $jobUrl], null),
5859
);
5960

6061
$job = $this->client->settings->setBatch(
@@ -68,6 +69,7 @@ public function testSetMultipleSettings()
6869
$request = $this->responses->getLastRequest();
6970

7071
$this->assertNotNull($job);
72+
$this->assertEquals('abcd', $job->id());
7173
$this->assertEquals('PATCH', $request->getMethod());
7274
$this->assertEquals('/v2/app/johndoe/', $request->getUri());
7375
$this->assertJson((string)$request->getBody());

0 commit comments

Comments
 (0)