chore: establish local platform baseline

This commit is contained in:
Codex Local
2026-08-26 06:41:54 +08:00
commit 29bdf4900f
575 changed files with 95644 additions and 0 deletions
+429
View File
@@ -0,0 +1,429 @@
package main
import (
"context"
"crypto/ed25519"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"path/filepath"
"strings"
"testing"
"time"
"data-terminal-cloud/internal/deviceauth"
)
func TestSimulatorRequestSignsBodyAndReturnsEnvelope(t *testing.T) {
secret := []byte("simulator-request-secret-at-least-32-bytes")
server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
body, _ := io.ReadAll(request.Body)
digest := sha256.Sum256(body)
if request.Header.Get(deviceauth.HeaderDeviceID) != "device-1" || request.Header.Get(deviceauth.HeaderContentSHA256) != hex.EncodeToString(digest[:]) || request.Header.Get(deviceauth.HeaderSignature) == "" {
t.Errorf("invalid signed headers: %v", request.Header)
}
if request.Header.Get("Idempotency-Key") != "idem-1" {
t.Errorf("idempotency key=%q", request.Header.Get("Idempotency-Key"))
}
writer.Header().Set("ETag", `"3"`)
writer.Header().Set("Content-Type", "application/json")
_, _ = io.WriteString(writer, `{"data":{"status":"ok"}}`)
}))
defer server.Close()
sim := simulator{baseURL: server.URL, deviceID: "device-1", secret: secret, client: server.Client()}
result, err := sim.request(context.Background(), http.MethodPost, "/device/v2/test", []byte(`{"value":1}`), "idem-1")
if err != nil || result.Status != http.StatusOK || result.Header.Get("ETag") != `"3"` {
t.Fatalf("result=%+v err=%v", result, err)
}
var payload struct {
Status string `json:"status"`
}
if err := decodeData(result.Body, &payload); err != nil || payload.Status != "ok" {
t.Fatalf("payload=%+v err=%v", payload, err)
}
}
func TestSimulatorHelpersAndValidation(t *testing.T) {
scenarios := parseScenarios(" Bootstrap,TELEMETRY, bootstrap ")
if !scenarios["bootstrap"] || !scenarios["telemetry"] || len(scenarios) != 2 {
t.Fatalf("scenarios=%v", scenarios)
}
wav := syntheticWAV(100)
if string(wav[:4]) != "RIFF" || string(wav[8:12]) != "WAVE" || binary.LittleEndian.Uint32(wav[40:44]) != uint32(len(wav)-44) {
t.Fatalf("invalid WAV header: size=%d", len(wav))
}
if len(jsonBody(map[string]int{"value": 1})) == 0 {
t.Fatal("json body is empty")
}
if value, err := newNonce(); err != nil || len(value) != 32 {
t.Fatalf("nonce=%q err=%v", value, err)
}
t.Setenv("SIM_DEVICE_SECRET", "short")
if err := run(context.Background()); err == nil || !strings.Contains(err.Error(), "at least 32") {
t.Fatalf("short secret error=%v", err)
}
}
func TestCreatedConversationIgnoresEngineMode(t *testing.T) {
decode := func(mode string) createdConversation {
var created createdConversation
body := []byte(`{"data":{"conversation_id":"conversation-1","rtc":{"room_id":"room-1","user_id":"device-1","expires_at":"2026-08-23T12:05:00Z"},"session":{"engine_mode":"` + mode + `"}}}`)
if err := decodeData(body, &created); err != nil {
t.Fatalf("decode mode %q: %v", mode, err)
}
return created
}
for _, mode := range []string{"s2s_pure", "s2s_hybrid", "cascade", "future_mode"} {
created := decode(mode)
if created.ID != "conversation-1" || created.RTC.RoomID != "room-1" || created.RTC.UserID != "device-1" {
t.Fatalf("mode %q changed terminal media inputs: %#v", mode, created)
}
}
}
func TestSimulatorWaitForConversationState(t *testing.T) {
for _, test := range []struct {
name, response, wantError string
}{
{name: "active", response: `{"data":{"status":"ACTIVE","action":"continue"}}`},
{name: "failed", response: `{"data":{"status":"FAILED","action":"leave_room","failure_code":"provider_start_rejected"}}`, wantError: "provider_start_rejected"},
} {
t.Run(test.name, func(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
if request.Method != http.MethodGet || request.URL.Path != "/device/v2/conversations/conversation-1" {
t.Errorf("unexpected request %s %s", request.Method, request.URL.Path)
}
writer.Header().Set("Content-Type", "application/json")
_, _ = io.WriteString(writer, test.response)
}))
defer server.Close()
sim := simulator{baseURL: server.URL, deviceID: "device-1", secret: []byte("simulator-request-secret-at-least-32-bytes"), client: server.Client()}
err := sim.waitForConversationActive(context.Background(), "conversation-1", time.Second)
if test.wantError == "" && err != nil {
t.Fatalf("wait failed: %v", err)
}
if test.wantError != "" && (err == nil || !strings.Contains(err.Error(), test.wantError)) {
t.Fatalf("error=%v want %q", err, test.wantError)
}
})
}
}
func TestSimulatorHTTPAndMediaFailures(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {
writer.WriteHeader(http.StatusConflict)
_, _ = io.WriteString(writer, `{"error":{"code":"CONFLICT"}}`)
}))
defer server.Close()
sim := simulator{baseURL: server.URL, deviceID: "device-1", secret: []byte("simulator-request-secret-at-least-32-bytes"), client: server.Client()}
if _, err := sim.request(context.Background(), http.MethodGet, "/conflict", nil, ""); err == nil || !strings.Contains(err.Error(), "HTTP 409") {
t.Fatalf("conflict error=%v", err)
}
t.Setenv("SIM_MEDIA_DURATION_MS", "0")
if err := sim.media(context.Background(), "conversation-1"); err == nil || !strings.Contains(err.Error(), "between 1 and 600000") {
t.Fatalf("media validation error=%v", err)
}
var target map[string]any
if err := decodeData([]byte(`not-json`), &target); err == nil {
t.Fatal("invalid envelope accepted")
}
encoded, _ := json.Marshal(map[string]any{"data": "not-an-object"})
if err := decodeData(encoded, &target); err == nil {
t.Fatal("invalid data payload accepted")
}
}
func TestSimulatorMediaCompletesVerificationAndDeleteReceipt(t *testing.T) {
deleteAcknowledged := false
var server *httptest.Server
server = httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
writer.Header().Set("Content-Type", "application/json")
switch {
case request.Method == http.MethodPost && request.URL.Path == "/device/v2/conversations/conversation-1/upload-batches":
_, _ = io.WriteString(writer, `{"data":{"id":"batch-1","status":"UPLOADING","segments":[{"id":"segment-1","upload_url":"`+server.URL+`/upload","content_type":"audio/wav"}]}}`)
case request.Method == http.MethodPut && request.URL.Path == "/upload":
writer.WriteHeader(http.StatusOK)
case request.Method == http.MethodPost && request.URL.Path == "/device/v2/upload-batches/batch-1/complete":
_, _ = io.WriteString(writer, `{"data":{"id":"batch-1","status":"VERIFYING","segments":[]}}`)
case request.Method == http.MethodGet && request.URL.Path == "/device/v2/upload-batches/batch-1":
deleteAfter := time.Now().Add(-time.Second).UTC().Format(time.RFC3339Nano)
_, _ = io.WriteString(writer, `{"data":{"id":"batch-1","status":"COMPLETED","segments":[{"id":"segment-1","status":"VERIFIED","local_delete_after":"`+deleteAfter+`"}]}}`)
case request.Method == http.MethodPost && request.URL.Path == "/device/v2/media-segments/segment-1/local-delete-ack":
if request.Header.Get("Idempotency-Key") == "" {
t.Error("local delete receipt has no idempotency key")
}
deleteAcknowledged = true
_, _ = io.WriteString(writer, `{"data":{"id":"segment-1","status":"VERIFIED","local_delete_status":"DELETED"}}`)
default:
http.NotFound(writer, request)
}
}))
defer server.Close()
t.Setenv("SIM_MEDIA_VERIFY_TIMEOUT", "2s")
t.Setenv("SIM_MEDIA_DELETE_WAIT_MAX", "2s")
sim := simulator{baseURL: server.URL, deviceID: "device-1", secret: []byte("simulator-request-secret-at-least-32-bytes"), client: server.Client()}
if err := sim.media(context.Background(), "conversation-1"); err != nil {
t.Fatalf("media flow error=%v", err)
}
if !deleteAcknowledged {
t.Fatal("local delete receipt was not sent")
}
}
func TestSimulatorFirmwareCommandSuccess(t *testing.T) {
content := []byte("signed simulated firmware image")
payload := signedSimulatorFirmwarePayload(t, content, "2.3.1")
acks := []map[string]any{}
var server *httptest.Server
server = httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
writer.Header().Set("Content-Type", "application/json")
switch {
case request.Method == http.MethodGet && request.URL.Path == "/device/v2/firmware-releases/release-1/download":
_, _ = io.WriteString(writer, `{"data":{"download_url":"`+server.URL+`/firmware.bin"}}`)
case request.Method == http.MethodGet && request.URL.Path == "/firmware.bin":
writer.Header().Set("Content-Type", "application/octet-stream")
_, _ = writer.Write(content)
case request.Method == http.MethodPost && request.URL.Path == "/device/v2/commands/command-1/ack":
var body map[string]any
if err := json.NewDecoder(request.Body).Decode(&body); err != nil {
t.Errorf("decode ack: %v", err)
}
acks = append(acks, body)
_, _ = io.WriteString(writer, `{"data":{"id":"command-1"}}`)
default:
http.NotFound(writer, request)
}
}))
defer server.Close()
sim := simulator{baseURL: server.URL, deviceID: "device-1", secret: []byte("simulator-request-secret-at-least-32-bytes"), client: server.Client()}
command := simulatedDeviceCommand{ID: "command-1", Type: "firmware_update", Payload: payload}
outcome, err := sim.executeFirmwareCommand(context.Background(), command)
if err != nil || outcome != firmwareCompleted {
t.Fatalf("outcome=%q err=%v", outcome, err)
}
if len(acks) != 4 || acks[0]["status"] != "ACKNOWLEDGED" || acks[1]["status"] != "ACKNOWLEDGED" || acks[2]["status"] != "ACKNOWLEDGED" || acks[3]["status"] != "SUCCEEDED" {
t.Fatalf("acks=%+v", acks)
}
firstResult := acks[0]["result_summary"].(map[string]any)
downloadResult := acks[1]["result_summary"].(map[string]any)
installResult := acks[2]["result_summary"].(map[string]any)
finalResult := acks[3]["result_summary"].(map[string]any)
if firstResult["phase"] != "downloading" || downloadResult["result_code"] != "ARTIFACT_VERIFIED" || downloadResult["verified_signing_key_id"] != "sim-test-key" || installResult["phase"] != "installing" || finalResult["installed_version"] != "2.3.1" || finalResult["verified_sha256"] != payload["sha256"] {
t.Fatalf("firmware results=%+v", acks)
}
}
func TestSimulatorFirmwareCommandFaultsAndInterruptions(t *testing.T) {
content := []byte("simulated firmware fault fixture")
tests := []struct {
fault string
wantOutcome firmwareExecutionOutcome
wantStatuses []string
wantCode string
}{
{fault: "download_failed", wantOutcome: firmwareFailed, wantStatuses: []string{"ACKNOWLEDGED", "FAILED"}, wantCode: "DOWNLOAD_FAILED"},
{fault: "digest_mismatch", wantOutcome: firmwareFailed, wantStatuses: []string{"ACKNOWLEDGED", "FAILED"}, wantCode: "DIGEST_MISMATCH"},
{fault: "signature_mismatch", wantOutcome: firmwareFailed, wantStatuses: []string{"ACKNOWLEDGED", "FAILED"}, wantCode: "SIGNATURE_MISMATCH"},
{fault: "install_failed", wantOutcome: firmwareFailed, wantStatuses: []string{"ACKNOWLEDGED", "ACKNOWLEDGED", "ACKNOWLEDGED", "FAILED"}, wantCode: "INSTALL_FAILED"},
{fault: "interrupt_after_download", wantOutcome: firmwareInterrupted, wantStatuses: []string{"ACKNOWLEDGED", "ACKNOWLEDGED"}, wantCode: "ARTIFACT_VERIFIED"},
{fault: "interrupt_after_install", wantOutcome: firmwareInterrupted, wantStatuses: []string{"ACKNOWLEDGED", "ACKNOWLEDGED", "ACKNOWLEDGED"}, wantCode: "INSTALL_STARTED"},
}
for _, test := range tests {
t.Run(test.fault, func(t *testing.T) {
t.Setenv("SIM_FIRMWARE_FAULT", test.fault)
payload := signedSimulatorFirmwarePayload(t, content, "2.3.1")
acks := []map[string]any{}
var server *httptest.Server
server = httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
writer.Header().Set("Content-Type", "application/json")
switch {
case request.Method == http.MethodGet && strings.HasSuffix(request.URL.Path, "/download"):
_, _ = io.WriteString(writer, `{"data":{"download_url":"`+server.URL+`/firmware.bin"}}`)
case request.Method == http.MethodGet && request.URL.Path == "/firmware.bin":
_, _ = writer.Write(content)
case request.Method == http.MethodPost && strings.HasSuffix(request.URL.Path, "/ack"):
var body map[string]any
_ = json.NewDecoder(request.Body).Decode(&body)
acks = append(acks, body)
_, _ = io.WriteString(writer, `{"data":{"id":"command-1"}}`)
default:
http.NotFound(writer, request)
}
}))
defer server.Close()
sim := simulator{baseURL: server.URL, deviceID: "device-1", secret: []byte("simulator-request-secret-at-least-32-bytes"), client: server.Client()}
command := simulatedDeviceCommand{ID: "command-1", Type: "firmware_update", Payload: payload}
outcome, err := sim.executeFirmwareCommand(context.Background(), command)
if err != nil || outcome != test.wantOutcome {
t.Fatalf("outcome=%q err=%v", outcome, err)
}
statuses := make([]string, 0, len(acks))
for _, ack := range acks {
statuses = append(statuses, ack["status"].(string))
}
if strings.Join(statuses, ",") != strings.Join(test.wantStatuses, ",") {
t.Fatalf("statuses=%v want=%v", statuses, test.wantStatuses)
}
lastResult := acks[len(acks)-1]["result_summary"].(map[string]any)
if lastResult["result_code"] != test.wantCode {
t.Fatalf("last result=%+v", lastResult)
}
})
}
}
func TestSimulatorFirmwareManifestAndConfigurationValidation(t *testing.T) {
digest := strings.Repeat("a", 64)
valid := map[string]any{"release_id": "release-1", "version": "2.3.1", "sha256": digest, "signature": base64.StdEncoding.EncodeToString(make([]byte, ed25519.SignatureSize)), "signing_key_id": "sim-test-key", "download_path": "/device/v2/firmware-releases/release-1/download"}
if _, err := parseSimulatedFirmwareManifest(valid); err != nil {
t.Fatalf("valid manifest error=%v", err)
}
for name, payload := range map[string]map[string]any{
"external path": {"release_id": "release-1", "version": "2.3.1", "sha256": digest, "signature": valid["signature"], "signing_key_id": "sim-test-key", "download_path": "https://example.invalid/firmware"},
"traversal": {"release_id": "release-1", "version": "2.3.1", "sha256": digest, "signature": valid["signature"], "signing_key_id": "sim-test-key", "download_path": "/device/v2/firmware-releases/../download"},
"uppercase": {"release_id": "release-1", "version": "2.3.1", "sha256": strings.Repeat("A", 64), "signature": valid["signature"], "signing_key_id": "sim-test-key", "download_path": "/device/v2/firmware-releases/release-1/download"},
} {
t.Run(name, func(t *testing.T) {
if _, err := parseSimulatedFirmwareManifest(payload); err == nil {
t.Fatalf("invalid manifest accepted: %+v", payload)
}
})
}
t.Setenv("SIM_FIRMWARE_FAULT", "unknown")
if _, err := simulatedFirmwareFault(); err == nil {
t.Fatal("unknown firmware fault was accepted")
}
t.Setenv("SIM_FIRMWARE_STEP_DELAY", "31s")
if _, err := simulatorOptionalDuration("SIM_FIRMWARE_STEP_DELAY", 30*time.Second); err == nil {
t.Fatal("excessive firmware step delay was accepted")
}
t.Setenv("SIM_FIRMWARE_TRUSTED_KEYS", `{}`)
if _, err := simulatedFirmwareTrustedKey("sim-test-key"); err == nil {
t.Fatal("unprovisioned firmware signing key was accepted")
}
t.Setenv("SIM_FIRMWARE_AB_UPDATE", "yes")
if _, err := simulatedABFirmwareEnabled(); err == nil {
t.Fatal("invalid A/B firmware flag was accepted")
}
t.Setenv("SIM_FIRMWARE_AB_UPDATE", "true")
t.Setenv("SIM_FIRMWARE_STATE_FILE", "relative-state.json")
if _, err := simulatedABFirmwareEnabled(); err == nil {
t.Fatal("relative A/B firmware state path was accepted")
}
}
func TestSimulatorABFirmwareBootConfirmationAndRollback(t *testing.T) {
for _, test := range []struct {
name, stageFault, bootFault, wantOutcome, wantPhase, wantSlot, wantCode string
retryAfterBoot bool
wantAckCount int
}{
{name: "healthy boot", stageFault: "none", bootFault: "none", wantOutcome: string(firmwareCompleted), wantPhase: firmwareBootConfirmed, wantSlot: "B", wantCode: "SIMULATED_AB_BOOT_CONFIRMED", wantAckCount: 7},
{name: "failed boot rolls back", stageFault: "none", bootFault: "boot_health_failed", wantOutcome: string(firmwareFailed), wantPhase: firmwareBootRolledBack, wantSlot: "A", wantCode: "BOOT_HEALTH_FAILED_ROLLED_BACK", wantAckCount: 7},
{name: "power loss after staging resumes", stageFault: "power_loss_after_stage", bootFault: "none", wantOutcome: string(firmwareCompleted), wantPhase: firmwareBootConfirmed, wantSlot: "B", wantCode: "SIMULATED_AB_BOOT_CONFIRMED", wantAckCount: 7},
{name: "power loss during boot resumes", stageFault: "none", bootFault: "power_loss_during_boot", retryAfterBoot: true, wantOutcome: string(firmwareCompleted), wantPhase: firmwareBootConfirmed, wantSlot: "B", wantCode: "SIMULATED_AB_BOOT_CONFIRMED", wantAckCount: 8},
} {
t.Run(test.name, func(t *testing.T) {
content := []byte("simulated A/B firmware image")
payload := signedSimulatorFirmwarePayload(t, content, "3.1.0")
stateFile := filepath.Join(t.TempDir(), "firmware-state.json")
t.Setenv("SIM_FIRMWARE_AB_UPDATE", "true")
t.Setenv("SIM_FIRMWARE_STATE_FILE", stateFile)
t.Setenv("SIM_FIRMWARE_BOOT_HEALTH_WINDOW", "30s")
t.Setenv("SIM_FIRMWARE_CURRENT_VERSION", "0.2.0-sim")
t.Setenv("SIM_FIRMWARE_FAULT", test.stageFault)
acks := []map[string]any{}
var server *httptest.Server
server = httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
writer.Header().Set("Content-Type", "application/json")
switch {
case request.Method == http.MethodGet && strings.HasSuffix(request.URL.Path, "/download"):
_, _ = io.WriteString(writer, `{"data":{"download_url":"`+server.URL+`/firmware.bin"}}`)
case request.Method == http.MethodGet && request.URL.Path == "/firmware.bin":
_, _ = writer.Write(content)
case request.Method == http.MethodPost && strings.HasSuffix(request.URL.Path, "/ack"):
var body map[string]any
_ = json.NewDecoder(request.Body).Decode(&body)
acks = append(acks, body)
_, _ = io.WriteString(writer, `{"data":{"id":"command-ab"}}`)
default:
http.NotFound(writer, request)
}
}))
defer server.Close()
sim := simulator{baseURL: server.URL, deviceID: "device-1", secret: []byte("simulator-request-secret-at-least-32-bytes"), client: server.Client()}
command := simulatedDeviceCommand{ID: "command-ab", Type: "firmware_update", Payload: payload}
outcome, err := sim.executeFirmwareCommand(context.Background(), command)
if err != nil {
t.Fatalf("staging outcome=%q err=%v", outcome, err)
}
if test.stageFault == "power_loss_after_stage" {
if outcome != firmwareInterrupted {
t.Fatalf("power loss staging outcome=%q", outcome)
}
staged, stateErr := loadSimulatedFirmwareBootState()
if stateErr != nil || staged.Phase != firmwareBootStaged {
t.Fatalf("power loss staged state=%+v err=%v", staged, stateErr)
}
t.Setenv("SIM_FIRMWARE_FAULT", "none")
outcome, err = sim.executeFirmwareCommand(context.Background(), command)
}
if err != nil || outcome != firmwareRebootRequired {
t.Fatalf("reboot arming outcome=%q err=%v", outcome, err)
}
staged, err := loadSimulatedFirmwareBootState()
if err != nil || staged.Phase != firmwareBootRebootPending || staged.ActiveSlot != "A" || staged.TargetSlot != "B" || staged.BootAttemptID == "" {
t.Fatalf("staged state=%+v err=%v", staged, err)
}
t.Setenv("SIM_FIRMWARE_FAULT", test.bootFault)
outcome, err = sim.executeFirmwareCommand(context.Background(), command)
if test.retryAfterBoot {
if err != nil || outcome != firmwareInterrupted {
t.Fatalf("boot power loss outcome=%q err=%v", outcome, err)
}
t.Setenv("SIM_FIRMWARE_FAULT", "none")
outcome, err = sim.executeFirmwareCommand(context.Background(), command)
}
if err != nil || string(outcome) != test.wantOutcome {
t.Fatalf("boot outcome=%q err=%v", outcome, err)
}
finalState, err := loadSimulatedFirmwareBootState()
if err != nil || finalState.Phase != test.wantPhase || finalState.ActiveSlot != test.wantSlot {
t.Fatalf("final state=%+v err=%v", finalState, err)
}
if len(acks) != test.wantAckCount {
t.Fatalf("ack count=%d acks=%+v", len(acks), acks)
}
lastResult := acks[len(acks)-1]["result_summary"].(map[string]any)
if lastResult["result_code"] != test.wantCode {
t.Fatalf("last result=%+v", lastResult)
}
})
}
}
func signedSimulatorFirmwarePayload(t *testing.T, content []byte, version string) map[string]any {
t.Helper()
publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
digest := sha256.Sum256(content)
digestText := hex.EncodeToString(digest[:])
manifest := fmt.Sprintf("firmware-manifest-v1\nmodel=simulated-terminal\nhardware_revision=sim-rev-a\nversion=%s\nsha256=%s\nsize=%d\n", version, digestText, len(content))
trustedKeys, _ := json.Marshal(map[string]string{"sim-test-key": base64.StdEncoding.EncodeToString(publicKey)})
t.Setenv("SIM_FIRMWARE_TRUSTED_KEYS", string(trustedKeys))
return map[string]any{
"release_id": "release-1", "version": version, "sha256": digestText,
"signature": base64.StdEncoding.EncodeToString(ed25519.Sign(privateKey, []byte(manifest))),
"signing_key_id": "sim-test-key", "download_path": "/device/v2/firmware-releases/release-1/download",
}
}