From 1da3cf14c3d2a155d77a6e83ec56e31f3bfc0222 Mon Sep 17 00:00:00 2001 From: Erik Zigo Date: Tue, 18 Nov 2025 08:26:26 +0100 Subject: [PATCH 1/2] feat: add Client::updateAutosaveTimestamp() method for updating sandbox autosave timestamps --- src/Client.php | 7 +++++ tests/ClientFunctionalTest.php | 24 ++++++++++++++++ tests/ClientUnitTest.php | 51 ++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/src/Client.php b/src/Client.php index d822d46..f30456b 100644 --- a/src/Client.php +++ b/src/Client.php @@ -35,6 +35,13 @@ public function update(Sandbox $sandbox): Sandbox return Sandbox::fromArray($this->sendRequest($request)); } + public function updateAutosaveTimestamp(string $id, string $timestamp): Sandbox + { + $jobData = json_encode(['lastAutosaveTimestamp' => $timestamp]); + $request = new Request('PATCH', "sandboxes/{$id}", [], $jobData); + return Sandbox::fromArray($this->sendRequest($request)); + } + public function deactivate(string $id, bool $skipBillingReport = false): Sandbox { $query = []; diff --git a/tests/ClientFunctionalTest.php b/tests/ClientFunctionalTest.php index 4c19427..c9cb4ce 100644 --- a/tests/ClientFunctionalTest.php +++ b/tests/ClientFunctionalTest.php @@ -348,6 +348,30 @@ public function testProjectPersistentStorage(): void self::assertNull($persistentStorage->getK8sStorageClassName()); } + public function testUpdateAutosaveTimestamp(): void + { + // 1. Create sandbox + $sandbox = (new Sandbox()) + ->setType('python') + ->setActive(true); + + $createdSandbox = $this->client->create($sandbox); + $sandboxId = $createdSandbox->getId(); + $this->assertNotEmpty($sandboxId); + + // 2. Update autosave timestamp + $timestamp = date('c'); + $updatedSandbox = $this->client->updateAutosaveTimestamp($sandboxId, $timestamp); + $this->assertSame($timestamp, $updatedSandbox->getLastAutosaveTimestamp()); + + // 3. Verify persistence by getting the sandbox again + $retrievedSandbox = $this->client->get($sandboxId); + $this->assertSame($timestamp, $retrievedSandbox->getLastAutosaveTimestamp()); + + // 4. Clean up + $this->client->delete($sandboxId); + } + protected function tearDown(): void { $this->componentsClient->deleteConfiguration('transformation', $this->configurationId); diff --git a/tests/ClientUnitTest.php b/tests/ClientUnitTest.php index d944d19..1b3cd11 100644 --- a/tests/ClientUnitTest.php +++ b/tests/ClientUnitTest.php @@ -184,4 +184,55 @@ public function testDelete(string $sandboxId, bool $skipBillingReport, string $e )); self::assertSame('', (string) $request->getBody()); } + + public function testUpdateAutosaveTimestamp(): void + { + $requestsLog = []; + $sandboxId = '123'; + $timestamp = '2025-01-18T10:30:00+00:00'; + $responseData = [ + 'id' => $sandboxId, + 'projectId' => 'project-id', + 'tokenId' => 'token-id', + 'type' => 'python', + 'active' => true, + 'createdTimestamp' => '2021-01-01T00:00:00+00:00', + 'lastAutosaveTimestamp' => $timestamp, + ]; + + $mockedResponses = [ + new Response(200, [], (string) json_encode($responseData)), + ]; + + $handlerStack = HandlerStack::create(new MockHandler($mockedResponses)); + $handlerStack->push(Middleware::history($requestsLog)); + + $client = new Client((string) getenv('API_URL'), (string) getenv('KBC_STORAGE_TOKEN'), [ + 'handler' => $handlerStack, + ]); + + $result = $client->updateAutosaveTimestamp($sandboxId, $timestamp); + + self::assertEquals(Sandbox::fromArray($responseData), $result); + self::assertEquals($timestamp, $result->getLastAutosaveTimestamp()); + + self::assertCount(1, $requestsLog); + + $request = $requestsLog[0]['request']; + self::assertInstanceOf(Request::class, $request); + + self::assertSame('PATCH', $request->getMethod()); + self::assertSame('/sandboxes/123', Uri::composeComponents( + '', + '', + $request->getUri()->getPath(), + $request->getUri()->getQuery(), + '', + )); + + $requestBody = json_decode((string) $request->getBody(), true); + self::assertIsArray($requestBody); + self::assertArrayHasKey('lastAutosaveTimestamp', $requestBody); + self::assertSame($timestamp, $requestBody['lastAutosaveTimestamp']); + } } From a5c01845eeea074d3f876bef3f6a6080e3dc1a7d Mon Sep 17 00:00:00 2001 From: Erik Zigo Date: Tue, 18 Nov 2025 17:39:04 +0100 Subject: [PATCH 2/2] chore: CI - remove unused KBC_MANAGE_NOTIFY_TOKEN environment variable --- .github/workflows/build.yml | 1 - docker-compose.yml | 1 - tests/bootstrap.php | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ef20dda..315fc5f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,6 @@ concurrency: ci-pipeline env: KBC_STORAGE_TOKEN: '${{ secrets.KBC_STORAGE_TOKEN }}' KBC_MANAGE_TOKEN: '${{ secrets.KBC_MANAGE_TOKEN }}' - KBC_MANAGE_NOTIFY_TOKEN: '${{ secrets.KBC_MANAGE_NOTIFY_TOKEN }}' # Azure AZURE_CLIENT_ID: 233328da-9afe-423b-82c1-915d8c539f71 diff --git a/docker-compose.yml b/docker-compose.yml index 1412c4b..5a79450 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,7 +14,6 @@ services: KBC_URL: https://connection.keboola.com KBC_STORAGE_TOKEN: KBC_MANAGE_TOKEN: - KBC_MANAGE_NOTIFY_TOKEN: DYNAMO_ENDPOINT: http://localstack:4566 DYNAMO_TABLE_SANDBOXES: sandboxes DYNAMO_TABLE_ML_DEPLOYMENTS: ml-deployments diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 5528d30..4e05474 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -26,7 +26,7 @@ if (file_exists(__DIR__ . '/../.env')) { $dotenv->load(); } -$dotenv->required(['API_URL', 'KBC_MANAGE_TOKEN', 'KBC_MANAGE_NOTIFY_TOKEN', 'KBC_STORAGE_TOKEN', 'KBC_URL']); +$dotenv->required(['API_URL', 'KBC_MANAGE_TOKEN', 'KBC_STORAGE_TOKEN', 'KBC_URL']); $tokenEnvs = [ 'KBC_STORAGE_TOKEN', @@ -69,7 +69,6 @@ $tokenEnvs = [ 'KBC_MANAGE_TOKEN', - 'KBC_MANAGE_NOTIFY_TOKEN', ]; foreach ($tokenEnvs as $tokenEnv) {