un-inception/clients/php/sync/tests/NewFunctionsTest.php
russell@unturf.com 6e746ace44 feat: full feature parity for all 42 SDKs + comprehensive tests
All SDKs now implement 58+ functions matching C reference (un.h):
- Execution (8): execute, execute_async, wait_job, get_job, cancel_job, list_jobs, get_languages, detect_language
- Sessions (9): list, get, create, destroy, freeze, unfreeze, boost, unboost, execute
- Services (17): list, get, create, destroy, freeze, unfreeze, lock, unlock, set_unfreeze_on_demand, redeploy, logs, execute, env_get/set/delete/export, resize
- Snapshots (9): list, get, session, service, restore, delete, lock, unlock, clone
- Images (13): list, get, publish, delete, lock, unlock, set_visibility, grant/revoke_access, list_trusted, transfer, spawn, clone
- PaaS Logs (2): fetch, stream
- Utilities (5): validate_keys, hmac_sign, health_check, version, last_error

Test suites created for all SDKs with unit, integration, and functional tests.

Languages: AWK, Bash, C++, C#, Clojure, COBOL, Crystal, D, Dart, .NET, Elixir, Erlang, F#, Forth, Fortran, Go, Groovy, Haskell, Java, JavaScript, Julia, Kotlin, Lisp, Lua, Nim, Objective-C, OCaml, Perl, PHP, PowerShell, Prolog, Python, R, Raku, Ruby, Rust, Scheme, Swift, Tcl, TypeScript, V, Zig
2026-02-05 16:45:02 -05:00

298 lines
11 KiB
PHP

<?php
/**
* Tests for new SDK functions (feature parity with C implementation)
*/
declare(strict_types=1);
namespace Unsandbox\Tests;
use PHPUnit\Framework\TestCase;
require_once __DIR__ . '/../src/un.php';
use Unsandbox\Unsandbox;
class NewFunctionsTest extends TestCase
{
private Unsandbox $client;
protected function setUp(): void
{
$this->client = new Unsandbox();
}
// =========================================================================
// Utility Functions Tests
// =========================================================================
public function testVersionReturnsString(): void
{
$v = Unsandbox::version();
$this->assertIsString($v);
$this->assertNotEmpty($v);
}
public function testVersionIsSemanticFormat(): void
{
$v = Unsandbox::version();
$parts = explode('.', $v);
$this->assertGreaterThanOrEqual(2, count($parts), "Version should be semantic: $v");
}
public function testHmacSignReturns64HexChars(): void
{
$signature = Unsandbox::hmacSign('secret_key', 'message_to_sign');
$this->assertIsString($signature);
$this->assertEquals(64, strlen($signature));
$this->assertMatchesRegularExpression('/^[0-9a-f]+$/', $signature);
}
public function testHmacSignIsDeterministic(): void
{
$sig1 = Unsandbox::hmacSign('secret', 'message');
$sig2 = Unsandbox::hmacSign('secret', 'message');
$this->assertEquals($sig1, $sig2);
}
public function testHmacSignDifferentSecretsDifferentSignatures(): void
{
$sig1 = Unsandbox::hmacSign('secret1', 'message');
$sig2 = Unsandbox::hmacSign('secret2', 'message');
$this->assertNotEquals($sig1, $sig2);
}
public function testHmacSignDifferentMessagesDifferentSignatures(): void
{
$sig1 = Unsandbox::hmacSign('secret', 'message1');
$sig2 = Unsandbox::hmacSign('secret', 'message2');
$this->assertNotEquals($sig1, $sig2);
}
public function testHmacSignMatchesPhpHashHmac(): void
{
$secret = 'test_secret';
$message = '1234567890:POST:/execute:';
$signature = Unsandbox::hmacSign($secret, $message);
$expected = hash_hmac('sha256', $message, $secret);
$this->assertEquals($expected, $signature);
}
public function testLastErrorReturnsNullOrString(): void
{
$error = Unsandbox::lastError();
$this->assertTrue($error === null || is_string($error));
}
// =========================================================================
// Method Exports Tests
// =========================================================================
public function testExecutionMethodsExist(): void
{
// 8 execution methods
$this->assertTrue(method_exists($this->client, 'executeCode'));
$this->assertTrue(method_exists($this->client, 'executeAsync'));
$this->assertTrue(method_exists($this->client, 'getJob'));
$this->assertTrue(method_exists($this->client, 'waitForJob'));
$this->assertTrue(method_exists($this->client, 'cancelJob'));
$this->assertTrue(method_exists($this->client, 'listJobs'));
$this->assertTrue(method_exists($this->client, 'getLanguages'));
$this->assertTrue(method_exists(Unsandbox::class, 'detectLanguage'));
}
public function testSessionMethodsExist(): void
{
// 9 session methods
$this->assertTrue(method_exists($this->client, 'listSessions'));
$this->assertTrue(method_exists($this->client, 'getSession'));
$this->assertTrue(method_exists($this->client, 'createSession'));
$this->assertTrue(method_exists($this->client, 'deleteSession'));
$this->assertTrue(method_exists($this->client, 'freezeSession'));
$this->assertTrue(method_exists($this->client, 'unfreezeSession'));
$this->assertTrue(method_exists($this->client, 'boostSession'));
$this->assertTrue(method_exists($this->client, 'unboostSession'));
$this->assertTrue(method_exists($this->client, 'shellSession'));
}
public function testServiceMethodsExist(): void
{
// 17 service methods
$this->assertTrue(method_exists($this->client, 'listServices'));
$this->assertTrue(method_exists($this->client, 'createService'));
$this->assertTrue(method_exists($this->client, 'getService'));
$this->assertTrue(method_exists($this->client, 'updateService'));
$this->assertTrue(method_exists($this->client, 'deleteService'));
$this->assertTrue(method_exists($this->client, 'freezeService'));
$this->assertTrue(method_exists($this->client, 'unfreezeService'));
$this->assertTrue(method_exists($this->client, 'lockService'));
$this->assertTrue(method_exists($this->client, 'unlockService'));
$this->assertTrue(method_exists($this->client, 'setUnfreezeOnDemand'));
$this->assertTrue(method_exists($this->client, 'getServiceLogs'));
$this->assertTrue(method_exists($this->client, 'getServiceEnv'));
$this->assertTrue(method_exists($this->client, 'setServiceEnv'));
$this->assertTrue(method_exists($this->client, 'deleteServiceEnv'));
$this->assertTrue(method_exists($this->client, 'exportServiceEnv'));
$this->assertTrue(method_exists($this->client, 'redeployService'));
$this->assertTrue(method_exists($this->client, 'executeInService'));
$this->assertTrue(method_exists($this->client, 'resizeService'), 'resizeService should exist (NEW)');
}
public function testSnapshotMethodsExist(): void
{
// 9 snapshot methods
$this->assertTrue(method_exists($this->client, 'sessionSnapshot'));
$this->assertTrue(method_exists($this->client, 'serviceSnapshot'));
$this->assertTrue(method_exists($this->client, 'listSnapshots'));
$this->assertTrue(method_exists($this->client, 'getSnapshot'), 'getSnapshot should exist (NEW)');
$this->assertTrue(method_exists($this->client, 'restoreSnapshot'));
$this->assertTrue(method_exists($this->client, 'deleteSnapshot'));
$this->assertTrue(method_exists($this->client, 'lockSnapshot'));
$this->assertTrue(method_exists($this->client, 'unlockSnapshot'));
$this->assertTrue(method_exists($this->client, 'cloneSnapshot'));
}
public function testImageMethodsExist(): void
{
// 13 image methods
$this->assertTrue(method_exists($this->client, 'imagePublish'));
$this->assertTrue(method_exists($this->client, 'listImages'));
$this->assertTrue(method_exists($this->client, 'getImage'));
$this->assertTrue(method_exists($this->client, 'deleteImage'));
$this->assertTrue(method_exists($this->client, 'lockImage'));
$this->assertTrue(method_exists($this->client, 'unlockImage'));
$this->assertTrue(method_exists($this->client, 'setImageVisibility'));
$this->assertTrue(method_exists($this->client, 'grantImageAccess'));
$this->assertTrue(method_exists($this->client, 'revokeImageAccess'));
$this->assertTrue(method_exists($this->client, 'listImageTrusted'));
$this->assertTrue(method_exists($this->client, 'transferImage'));
$this->assertTrue(method_exists($this->client, 'spawnFromImage'));
$this->assertTrue(method_exists($this->client, 'cloneImage'));
}
public function testLogsMethodsExist(): void
{
// 2 PaaS logs methods (NEW)
$this->assertTrue(method_exists($this->client, 'logsFetch'), 'logsFetch should exist (NEW)');
$this->assertTrue(method_exists($this->client, 'logsStream'), 'logsStream should exist (NEW)');
}
public function testUtilityMethodsExist(): void
{
$this->assertTrue(method_exists($this->client, 'validateKeys'));
$this->assertTrue(method_exists(Unsandbox::class, 'version'), 'version should exist (NEW)');
$this->assertTrue(method_exists(Unsandbox::class, 'healthCheck'), 'healthCheck should exist (NEW)');
$this->assertTrue(method_exists(Unsandbox::class, 'lastError'), 'lastError should exist (NEW)');
$this->assertTrue(method_exists(Unsandbox::class, 'hmacSign'), 'hmacSign should exist (NEW)');
}
// =========================================================================
// Language Detection Tests
// =========================================================================
public function testDetectLanguagePython(): void
{
$this->assertEquals('python', Unsandbox::detectLanguage('test.py'));
}
public function testDetectLanguageJavascript(): void
{
$this->assertEquals('javascript', Unsandbox::detectLanguage('test.js'));
}
public function testDetectLanguageTypescript(): void
{
$this->assertEquals('typescript', Unsandbox::detectLanguage('test.ts'));
}
public function testDetectLanguageRuby(): void
{
$this->assertEquals('ruby', Unsandbox::detectLanguage('test.rb'));
}
public function testDetectLanguageGo(): void
{
$this->assertEquals('go', Unsandbox::detectLanguage('test.go'));
}
public function testDetectLanguageRust(): void
{
$this->assertEquals('rust', Unsandbox::detectLanguage('test.rs'));
}
public function testDetectLanguageUnknownReturnsNull(): void
{
$this->assertNull(Unsandbox::detectLanguage('test.unknown'));
}
}
/**
* Functional tests that require API credentials
*/
class FunctionalAPITest extends TestCase
{
private ?Unsandbox $client = null;
protected function setUp(): void
{
if (!$this->credentialsAvailable()) {
$this->markTestSkipped('UNSANDBOX_PUBLIC_KEY and UNSANDBOX_SECRET_KEY required');
}
$this->client = new Unsandbox();
}
private function credentialsAvailable(): bool
{
return getenv('UNSANDBOX_PUBLIC_KEY') && getenv('UNSANDBOX_SECRET_KEY');
}
public function testHealthCheck(): void
{
$result = Unsandbox::healthCheck();
$this->assertIsBool($result);
}
public function testValidateKeys(): void
{
$result = $this->client->validateKeys();
$this->assertIsArray($result);
}
public function testGetLanguages(): void
{
$languages = $this->client->getLanguages();
$this->assertIsArray($languages);
$this->assertContains('python', $languages);
}
public function testListSessions(): void
{
$sessions = $this->client->listSessions();
$this->assertIsArray($sessions);
}
public function testListServices(): void
{
$services = $this->client->listServices();
$this->assertIsArray($services);
}
public function testListSnapshots(): void
{
$snapshots = $this->client->listSnapshots();
$this->assertIsArray($snapshots);
}
public function testListImages(): void
{
$images = $this->client->listImages();
$this->assertIsArray($images);
}
public function testExecuteCode(): void
{
$result = $this->client->executeCode('python', 'print("hello")');
$this->assertIsArray($result);
$this->assertContains($result['status'] ?? '', ['completed', 'pending']);
}
}