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
This commit is contained in:
parent
a5155aed4f
commit
6e746ace44
90 changed files with 28955 additions and 3028 deletions
153
clients/elixir/sync/tests/test_functional.exs
Normal file
153
clients/elixir/sync/tests/test_functional.exs
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
#!/usr/bin/env elixir
|
||||
|
||||
# Functional Tests for Un Elixir SDK
|
||||
#
|
||||
# Run with: elixir tests/test_functional.exs
|
||||
# Requires: UNSANDBOX_PUBLIC_KEY and UNSANDBOX_SECRET_KEY environment variables
|
||||
#
|
||||
# These tests make real API calls to api.unsandbox.com
|
||||
|
||||
Code.require_file("../src/un.ex", __DIR__)
|
||||
|
||||
defmodule UnFunctionalTest do
|
||||
@moduledoc """
|
||||
Functional test suite for Un Elixir SDK.
|
||||
Tests real API calls to api.unsandbox.com.
|
||||
"""
|
||||
|
||||
@blue "\e[34m"
|
||||
@red "\e[31m"
|
||||
@green "\e[32m"
|
||||
@yellow "\e[33m"
|
||||
@reset "\e[0m"
|
||||
|
||||
def run_all do
|
||||
IO.puts("\n#{@blue}=== Un Elixir SDK Functional Tests ===#@reset}\n")
|
||||
|
||||
# Check for credentials
|
||||
unless System.get_env("UNSANDBOX_PUBLIC_KEY") && System.get_env("UNSANDBOX_SECRET_KEY") do
|
||||
IO.puts("#{@yellow}SKIP: UNSANDBOX_PUBLIC_KEY and UNSANDBOX_SECRET_KEY not set#{@reset}")
|
||||
System.halt(0)
|
||||
end
|
||||
|
||||
tests = [
|
||||
{"health_check", &test_health_check/0},
|
||||
{"validate_keys", &test_validate_keys/0},
|
||||
{"execute_python", &test_execute_python/0},
|
||||
{"execute_with_error", &test_execute_with_error/0},
|
||||
{"session_list", &test_session_list/0},
|
||||
{"service_list", &test_service_list/0},
|
||||
{"snapshot_list", &test_snapshot_list/0},
|
||||
{"image_list", &test_image_list/0}
|
||||
]
|
||||
|
||||
results = Enum.map(tests, fn {name, test_fn} ->
|
||||
IO.write(" Running #{name}... ")
|
||||
try do
|
||||
test_fn.()
|
||||
IO.puts("#{@green}PASS#{@reset}")
|
||||
:pass
|
||||
rescue
|
||||
e ->
|
||||
IO.puts("#{@red}FAIL#{@reset}")
|
||||
IO.puts(" #{inspect(e)}")
|
||||
:fail
|
||||
end
|
||||
end)
|
||||
|
||||
passed = Enum.count(results, &(&1 == :pass))
|
||||
failed = Enum.count(results, &(&1 == :fail))
|
||||
total = length(results)
|
||||
|
||||
IO.puts("\n#{@blue}Results: #{passed}/#{total} passed#{@reset}")
|
||||
if failed > 0 do
|
||||
IO.puts("#{@red}#{failed} test(s) failed#{@reset}")
|
||||
System.halt(1)
|
||||
else
|
||||
IO.puts("#{@green}All functional tests passed!#{@reset}")
|
||||
end
|
||||
end
|
||||
|
||||
# ============================================================================
|
||||
# Functional Tests
|
||||
# ============================================================================
|
||||
|
||||
def test_health_check do
|
||||
result = Un.health_check()
|
||||
assert is_boolean(result), "health_check should return boolean"
|
||||
# Note: We don't require it to be true in case API is down
|
||||
end
|
||||
|
||||
def test_validate_keys do
|
||||
key_info = Un.validate_keys()
|
||||
assert is_map(key_info), "validate_keys should return a map"
|
||||
assert Map.has_key?(key_info, :valid), "key_info should have :valid key"
|
||||
assert is_boolean(key_info.valid), ":valid should be boolean"
|
||||
end
|
||||
|
||||
def test_execute_python do
|
||||
result = Un.execute("python", "print(6 * 7)")
|
||||
assert is_map(result), "execute should return a map"
|
||||
assert Map.has_key?(result, :success), "result should have :success key"
|
||||
assert Map.has_key?(result, :stdout), "result should have :stdout key"
|
||||
assert Map.has_key?(result, :exit_code), "result should have :exit_code key"
|
||||
|
||||
# Check output
|
||||
assert result.success == true, "execution should succeed"
|
||||
assert String.contains?(result.stdout, "42"), "stdout should contain '42'"
|
||||
assert result.exit_code == 0, "exit_code should be 0"
|
||||
end
|
||||
|
||||
def test_execute_with_error do
|
||||
result = Un.execute("python", "import sys; sys.exit(1)")
|
||||
assert is_map(result), "execute should return a map"
|
||||
assert result.success == false, "execution should fail"
|
||||
assert result.exit_code == 1, "exit_code should be 1"
|
||||
end
|
||||
|
||||
def test_session_list do
|
||||
response = Un.session_list()
|
||||
assert is_binary(response), "session_list should return a string"
|
||||
# Response should be valid JSON (starts with [ or {)
|
||||
trimmed = String.trim(response)
|
||||
assert String.starts_with?(trimmed, "[") || String.starts_with?(trimmed, "{"),
|
||||
"response should be JSON"
|
||||
end
|
||||
|
||||
def test_service_list do
|
||||
response = Un.service_list()
|
||||
assert is_binary(response), "service_list should return a string"
|
||||
trimmed = String.trim(response)
|
||||
assert String.starts_with?(trimmed, "[") || String.starts_with?(trimmed, "{"),
|
||||
"response should be JSON"
|
||||
end
|
||||
|
||||
def test_snapshot_list do
|
||||
response = Un.snapshot_list()
|
||||
assert is_binary(response), "snapshot_list should return a string"
|
||||
trimmed = String.trim(response)
|
||||
assert String.starts_with?(trimmed, "[") || String.starts_with?(trimmed, "{"),
|
||||
"response should be JSON"
|
||||
end
|
||||
|
||||
def test_image_list do
|
||||
response = Un.image_list()
|
||||
assert is_binary(response), "image_list should return a string"
|
||||
trimmed = String.trim(response)
|
||||
assert String.starts_with?(trimmed, "[") || String.starts_with?(trimmed, "{"),
|
||||
"response should be JSON"
|
||||
end
|
||||
|
||||
# ============================================================================
|
||||
# Helpers
|
||||
# ============================================================================
|
||||
|
||||
defp assert(true, _message), do: :ok
|
||||
defp assert(false, message), do: raise message
|
||||
defp assert(condition, message) when is_boolean(condition) do
|
||||
if condition, do: :ok, else: raise message
|
||||
end
|
||||
end
|
||||
|
||||
# Run tests
|
||||
UnFunctionalTest.run_all()
|
||||
135
clients/elixir/sync/tests/test_library.exs
Normal file
135
clients/elixir/sync/tests/test_library.exs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
#!/usr/bin/env elixir
|
||||
|
||||
# Tests for Un Elixir SDK
|
||||
#
|
||||
# Run with: elixir tests/test_library.exs
|
||||
# Requires: UNSANDBOX_PUBLIC_KEY and UNSANDBOX_SECRET_KEY environment variables
|
||||
|
||||
Code.require_file("../src/un.ex", __DIR__)
|
||||
|
||||
defmodule UnTest do
|
||||
@moduledoc """
|
||||
Test suite for Un Elixir SDK library functions.
|
||||
"""
|
||||
|
||||
@blue "\e[34m"
|
||||
@red "\e[31m"
|
||||
@green "\e[32m"
|
||||
@yellow "\e[33m"
|
||||
@reset "\e[0m"
|
||||
|
||||
def run_all do
|
||||
IO.puts("\n#{@blue}=== Un Elixir SDK Tests ===#@reset}\n")
|
||||
|
||||
tests = [
|
||||
{"version", &test_version/0},
|
||||
{"detect_language", &test_detect_language/0},
|
||||
{"hmac_sign", &test_hmac_sign/0},
|
||||
{"hmac_sign_deterministic", &test_hmac_sign_deterministic/0},
|
||||
{"hmac_sign_different_secrets", &test_hmac_sign_different_secrets/0},
|
||||
{"get_languages", &test_get_languages/0}
|
||||
]
|
||||
|
||||
results = Enum.map(tests, fn {name, test_fn} ->
|
||||
try do
|
||||
test_fn.()
|
||||
IO.puts("#{@green}PASS#{@reset}: #{name}")
|
||||
:pass
|
||||
rescue
|
||||
e ->
|
||||
IO.puts("#{@red}FAIL#{@reset}: #{name} - #{inspect(e)}")
|
||||
:fail
|
||||
end
|
||||
end)
|
||||
|
||||
passed = Enum.count(results, &(&1 == :pass))
|
||||
failed = Enum.count(results, &(&1 == :fail))
|
||||
total = length(results)
|
||||
|
||||
IO.puts("\n#{@blue}Results: #{passed}/#{total} passed#{@reset}")
|
||||
if failed > 0 do
|
||||
IO.puts("#{@red}#{failed} test(s) failed#{@reset}")
|
||||
System.halt(1)
|
||||
else
|
||||
IO.puts("#{@green}All tests passed!#{@reset}")
|
||||
end
|
||||
end
|
||||
|
||||
# ============================================================================
|
||||
# Unit Tests
|
||||
# ============================================================================
|
||||
|
||||
def test_version do
|
||||
version = Un.version()
|
||||
assert is_binary(version), "version should be a string"
|
||||
assert String.match?(version, ~r/^\d+\.\d+\.\d+$/), "version should be semver format"
|
||||
end
|
||||
|
||||
def test_detect_language do
|
||||
# Test common extensions
|
||||
assert Un.detect_language("script.py") == "python"
|
||||
assert Un.detect_language("app.js") == "javascript"
|
||||
assert Un.detect_language("main.go") == "go"
|
||||
assert Un.detect_language("main.rs") == "rust"
|
||||
assert Un.detect_language("main.c") == "c"
|
||||
assert Un.detect_language("main.cpp") == "cpp"
|
||||
assert Un.detect_language("Main.java") == "java"
|
||||
assert Un.detect_language("script.rb") == "ruby"
|
||||
assert Un.detect_language("script.sh") == "bash"
|
||||
assert Un.detect_language("script.lua") == "lua"
|
||||
assert Un.detect_language("script.pl") == "perl"
|
||||
assert Un.detect_language("index.php") == "php"
|
||||
assert Un.detect_language("main.hs") == "haskell"
|
||||
assert Un.detect_language("main.ml") == "ocaml"
|
||||
assert Un.detect_language("main.ex") == "elixir"
|
||||
assert Un.detect_language("main.erl") == "erlang"
|
||||
|
||||
# Test with paths
|
||||
assert Un.detect_language("/path/to/script.py") == "python"
|
||||
|
||||
# Test unknown extensions
|
||||
assert Un.detect_language("Makefile") == nil
|
||||
assert Un.detect_language("README") == nil
|
||||
assert Un.detect_language("script.unknown") == nil
|
||||
end
|
||||
|
||||
def test_hmac_sign do
|
||||
signature = Un.hmac_sign("my_secret", "test message")
|
||||
assert is_binary(signature), "signature should be a string"
|
||||
assert String.length(signature) == 64, "signature should be 64 hex characters"
|
||||
assert String.match?(signature, ~r/^[0-9a-f]+$/), "signature should be lowercase hex"
|
||||
end
|
||||
|
||||
def test_hmac_sign_deterministic do
|
||||
sig1 = Un.hmac_sign("test_secret", "same message")
|
||||
sig2 = Un.hmac_sign("test_secret", "same message")
|
||||
assert sig1 == sig2, "same inputs should produce same signature"
|
||||
end
|
||||
|
||||
def test_hmac_sign_different_secrets do
|
||||
sig1 = Un.hmac_sign("secret1", "test message")
|
||||
sig2 = Un.hmac_sign("secret2", "test message")
|
||||
assert sig1 != sig2, "different secrets should produce different signatures"
|
||||
end
|
||||
|
||||
def test_get_languages do
|
||||
languages = Un.get_languages()
|
||||
assert is_list(languages), "languages should be a list"
|
||||
assert length(languages) > 0, "languages list should not be empty"
|
||||
assert "python" in languages, "python should be in languages"
|
||||
assert "javascript" in languages, "javascript should be in languages"
|
||||
end
|
||||
|
||||
# ============================================================================
|
||||
# Helpers
|
||||
# ============================================================================
|
||||
|
||||
defp assert(true, _message), do: :ok
|
||||
defp assert(false, message), do: raise message
|
||||
defp assert(condition, message) when is_boolean(condition) do
|
||||
if condition, do: :ok, else: raise message
|
||||
end
|
||||
end
|
||||
|
||||
# Run tests
|
||||
UnTest.run_all()
|
||||
Loading…
Add table
Add a link
Reference in a new issue