un-inception/clients/ocaml/sync/tests/test_functional.ml
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

190 lines
7.3 KiB
OCaml
Executable file

#!/usr/bin/env ocaml
(*
* Functional Tests for Un OCaml SDK
*
* Run with: ocaml test_functional.ml
* Requires: UNSANDBOX_PUBLIC_KEY and UNSANDBOX_SECRET_KEY environment variables
*
* These tests make real API calls to api.unsandbox.com
*)
(* ANSI colors *)
let blue = "\x1b[34m"
let red = "\x1b[31m"
let green = "\x1b[32m"
let yellow = "\x1b[33m"
let reset = "\x1b[0m"
(* API constants *)
let api_base = "https://api.unsandbox.com"
let portal_base = "https://unsandbox.com"
(* HMAC-SHA256 using openssl command *)
let hmac_sha256 secret message =
let cmd = Printf.sprintf "echo -n '%s' | openssl dgst -sha256 -hmac '%s' | awk '{print $2}'"
(Str.global_replace (Str.regexp "'") "'\\''" message)
(Str.global_replace (Str.regexp "'") "'\\''" secret) in
let ic = Unix.open_process_in cmd in
let result = input_line ic in
let _ = Unix.close_process_in ic in
String.trim result
(* Build auth headers *)
let build_auth_headers public_key secret_key method_ path body =
let timestamp = string_of_int (int_of_float (Unix.time ())) in
let message = Printf.sprintf "%s:%s:%s:%s" timestamp method_ path body in
let signature = hmac_sha256 secret_key message in
Printf.sprintf " -H 'Authorization: Bearer %s' -H 'X-Timestamp: %s' -H 'X-Signature: %s'"
public_key timestamp signature
(* HTTP helpers *)
let curl_get public_key secret_key endpoint =
let auth_headers = build_auth_headers public_key secret_key "GET" endpoint "" in
let cmd = Printf.sprintf "curl -s %s%s%s" api_base endpoint auth_headers in
let ic = Unix.open_process_in cmd in
let rec read_all acc =
try let line = input_line ic in read_all (acc ^ line ^ "\n")
with End_of_file -> acc
in
let output = read_all "" in
let _ = Unix.close_process_in ic in
output
let curl_post public_key secret_key endpoint json =
let auth_headers = build_auth_headers public_key secret_key "POST" endpoint json in
let tmp_file = Printf.sprintf "/tmp/un_ocaml_test_%d.json" (Random.int 999999) in
let oc = open_out tmp_file in
output_string oc json;
close_out oc;
let cmd = Printf.sprintf "curl -s -X POST %s%s -H 'Content-Type: application/json'%s -d @%s"
api_base endpoint auth_headers tmp_file in
let ic = Unix.open_process_in cmd in
let rec read_all acc =
try let line = input_line ic in read_all (acc ^ line ^ "\n")
with End_of_file -> acc
in
let output = read_all "" in
let _ = Unix.close_process_in ic in
Sys.remove tmp_file;
output
let curl_post_portal public_key secret_key endpoint json =
let auth_headers = build_auth_headers public_key secret_key "POST" endpoint json in
let tmp_file = Printf.sprintf "/tmp/un_ocaml_test_%d.json" (Random.int 999999) in
let oc = open_out tmp_file in
output_string oc json;
close_out oc;
let cmd = Printf.sprintf "curl -s -X POST %s%s -H 'Content-Type: application/json'%s -d @%s"
portal_base endpoint auth_headers tmp_file in
let ic = Unix.open_process_in cmd in
let rec read_all acc =
try let line = input_line ic in read_all (acc ^ line ^ "\n")
with End_of_file -> acc
in
let output = read_all "" in
let _ = Unix.close_process_in ic in
Sys.remove tmp_file;
output
(* String contains helper *)
let contains haystack needle =
try
let _ = Str.search_forward (Str.regexp_string needle) haystack 0 in
true
with Not_found -> false
(* Test tracking *)
let passed = ref 0
let failed = ref 0
let run_test name test_fn =
Printf.printf " Running %s... " name;
flush stdout;
try
test_fn ();
Printf.printf "%sPASS%s\n" green reset;
incr passed
with e ->
Printf.printf "%sFAIL%s\n" red reset;
Printf.printf " %s\n" (Printexc.to_string e);
incr failed
let assert_true condition message =
if not condition then failwith message
(* ============================================================================
Functional Tests
============================================================================ *)
let test_health_check () =
let cmd = Printf.sprintf "curl -s -o /dev/null -w '%%{http_code}' %s/health" api_base in
let ic = Unix.open_process_in cmd in
let status = try input_line ic with End_of_file -> "0" in
let _ = Unix.close_process_in ic in
assert_true (String.trim status = "200") "health check should return 200"
let test_validate_keys public_key secret_key =
let response = curl_post_portal public_key secret_key "/keys/validate" "{}" in
assert_true (contains response "\"valid\"" || contains response "\"status\"") "should contain valid or status"
let test_execute_python public_key secret_key =
let json = "{\"language\":\"python\",\"code\":\"print(6 * 7)\"}" in
let response = curl_post public_key secret_key "/execute" json in
assert_true (contains response "42") "stdout should contain 42"
let test_execute_with_error public_key secret_key =
let json = "{\"language\":\"python\",\"code\":\"import sys; sys.exit(1)\"}" in
let response = curl_post public_key secret_key "/execute" json in
assert_true (contains response "\"exit_code\":1" || contains response "\"exit_code\": 1") "exit_code should be 1"
let test_session_list public_key secret_key =
let response = curl_get public_key secret_key "/sessions" in
let trimmed = String.trim response in
assert_true (String.length trimmed > 0 && (trimmed.[0] = '[' || trimmed.[0] = '{')) "response should be JSON"
let test_service_list public_key secret_key =
let response = curl_get public_key secret_key "/services" in
let trimmed = String.trim response in
assert_true (String.length trimmed > 0 && (trimmed.[0] = '[' || trimmed.[0] = '{')) "response should be JSON"
let test_snapshot_list public_key secret_key =
let response = curl_get public_key secret_key "/snapshots" in
let trimmed = String.trim response in
assert_true (String.length trimmed > 0 && (trimmed.[0] = '[' || trimmed.[0] = '{')) "response should be JSON"
let test_image_list public_key secret_key =
let response = curl_get public_key secret_key "/images" in
let trimmed = String.trim response in
assert_true (String.length trimmed > 0 && (trimmed.[0] = '[' || trimmed.[0] = '{')) "response should be JSON"
let () =
Random.self_init ();
Printf.printf "\n%s=== Un OCaml SDK Functional Tests ===%s\n\n" blue reset;
(* Check for credentials *)
let public_key = try Some (Sys.getenv "UNSANDBOX_PUBLIC_KEY") with Not_found -> None in
let secret_key = try Some (Sys.getenv "UNSANDBOX_SECRET_KEY") with Not_found -> None in
match (public_key, secret_key) with
| (Some pk, Some sk) ->
run_test "health_check" test_health_check;
run_test "validate_keys" (fun () -> test_validate_keys pk sk);
run_test "execute_python" (fun () -> test_execute_python pk sk);
run_test "execute_with_error" (fun () -> test_execute_with_error pk sk);
run_test "session_list" (fun () -> test_session_list pk sk);
run_test "service_list" (fun () -> test_service_list pk sk);
run_test "snapshot_list" (fun () -> test_snapshot_list pk sk);
run_test "image_list" (fun () -> test_image_list pk sk);
let total = !passed + !failed in
Printf.printf "\n%sResults: %d/%d passed%s\n" blue !passed total reset;
if !failed > 0 then begin
Printf.printf "%s%d test(s) failed%s\n" red !failed reset;
exit 1
end else
Printf.printf "%sAll functional tests passed!%s\n" green reset
| _ ->
Printf.printf "%sSKIP: UNSANDBOX_PUBLIC_KEY and UNSANDBOX_SECRET_KEY not set%s\n" yellow reset