package api import ( "context" "encoding/json" "errors" "fmt" "net/http" "strings" "testing" hub "git.ipao.vip/rogee/creator-hub/internal/environment" ) func TestStartUnknownPreservesGatewayFailureReason(t *testing.T) { for _, disconnected := range []bool{false, true} { t.Run(map[bool]string{false: "server failure", true: "connection lost"}[disconnected], func(t *testing.T) { gatewayID := 90 + map[bool]int{false: 1, true: 2}[disconnected] store := newMemoryStore() accessKey := fmt.Sprintf("error-reason-key-%05d", gatewayID) store.gateways["gw-1"] = hub.Gateway{ID: int64(gatewayID), Name: "gw-1", AccessKey: accessKey} environment := hub.EnvironmentContext{Env: hub.Env{Alias: "account-a", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}, AccountID: "account-a", AccountStatus: "active", BindingVersion: 1} store.bindings[environment.Alias] = environment routes := map[string]string{"GET /v1/browsers": `[]`} if !disconnected { routes["POST /v1/browsers"] = "503 " + `{"error":"no free Xvfb display is available"}` } else { routes["POST /v1/browsers"] = "disconnect" } cleanup := startFakeChannelGateway(t, int64(gatewayID), accessKey, routes) defer cleanup() finish := func(outcome, reason string, _ hub.EnvironmentContext) error { if outcome != "unknown" || reason != "gateway_result_unknown" { t.Errorf("unexpected result: %s/%s", outcome, reason) } return nil } err := startBrowserRuntime(context.Background(), store, nil, environment, finish) want := "no free Xvfb display is available" if disconnected { want = "gateway start result unknown" } if err == nil || !strings.Contains(err.Error(), want) { t.Fatalf("original startup cause was hidden: %v", err) } }) } } func TestStartBrowserRuntimeSuccessfulAndFailedCompletion(t *testing.T) { for _, existing := range []bool{false, true} { for _, finishFails := range []bool{false, true} { t.Run(map[bool]string{false: "create", true: "reconcile"}[existing]+map[bool]string{false: " success", true: " finish error"}[finishFails], func(t *testing.T) { posts := 0 runtime := runtimeStatus{ID: "runtime-a", Alias: "account-a", State: "running", NetworkID: "net-a", BindingVersion: 1, ProxyReady: true} gatewayID := int64(95) store := newMemoryStore() store.gateways["gw-1"] = hub.Gateway{ID: gatewayID, Name: "gw-1", AccessKey: fmt.Sprintf("error-reason-key-%05d", gatewayID)} runtimeBody, _ := json.Marshal(runtime) listBody := `[]` if existing { listBody = "[" + string(runtimeBody) + "]" } channelCleanup := startFakeChannelGateway(t, gatewayID, store.gateways["gw-1"].AccessKey, map[string]string{ "POST /v1/browsers": "201 " + string(runtimeBody), "GET /v1/browsers": "200 " + listBody, }) defer channelCleanup() environment := hub.EnvironmentContext{Env: hub.Env{Alias: "account-a", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}, AccountID: "account-a", AccountStatus: "active", BindingVersion: 1} store.bindings[environment.Alias] = environment finishErr := errors.New("completion recording failed") finish := func(outcome, reason string, current hub.EnvironmentContext) error { want := "environment_started" if existing { want = "gateway_reconciled" } if outcome != "succeeded" || reason != want || current.RuntimeID != runtime.ID { t.Errorf("unexpected completion: %s/%s/%s", outcome, reason, current.RuntimeID) } if finishFails { return finishErr } return nil } err := startBrowserRuntime(context.Background(), store, nil, environment, finish) if finishFails && !errors.Is(err, finishErr) || !finishFails && err != nil { t.Fatalf("unexpected start result: %v", err) } _ = posts }) } } } func TestGatewayRejectedPreservesServerFailureReason(t *testing.T) { err := gatewayRejected(http.StatusServiceUnavailable, []byte(`{"error":"no free Xvfb display is available"}`)) if !strings.Contains(err.Error(), "no free Xvfb display is available") { t.Fatalf("gateway failure hid its cause: %v", err) } }