fix server creation run binding
This commit is contained in:
@@ -783,14 +783,22 @@ func TestServerLifecycleWorkflowAPI(t *testing.T) {
|
||||
created := postOKJSONWithAuth[dto.ServerLifecycleResponse](t, router, "/api/v1/server-instances/workflows/create", dto.ServerLifecycleCreateRequest{
|
||||
ID: "server-create",
|
||||
PluginID: "server.scum",
|
||||
RunEndpointID: "run-local",
|
||||
Name: "SCUM Create",
|
||||
IdempotencyKey: "idem-create",
|
||||
ProfileKey: "local",
|
||||
}, adminSession)
|
||||
if created.Action != domain.ServerLifecycleActionCreate || created.Instance.State != domain.ServerInstanceStateInstalling || created.Job.Capability != domain.LifecycleCapabilityInstall {
|
||||
if created.Action != domain.ServerLifecycleActionCreate || created.Instance.State != domain.ServerInstanceStateDraft || created.Job.ID != "" || created.Instance.RunEndpointID != "" {
|
||||
t.Fatalf("expected create workflow response, got %+v", created)
|
||||
}
|
||||
legacyCreate := requestJSONWithAuth(t, router, http.MethodPost, "/api/v1/server-instances/workflows/create", dto.ServerLifecycleCreateRequest{
|
||||
ID: "server-create-legacy",
|
||||
PluginID: "server.scum",
|
||||
RunEndpointID: "run-local",
|
||||
Name: "SCUM Legacy Create",
|
||||
IdempotencyKey: "idem-create-legacy",
|
||||
ProfileKey: "local",
|
||||
Bindings: map[string]string{"server-root": "runtime.server-root"},
|
||||
}, adminSession)
|
||||
assertErrorResponse(t, legacyCreate, http.StatusBadRequest, errorCodeValidation)
|
||||
|
||||
ready := postJSONWithAuth[dto.ServerInstanceResponse](t, router, "/api/v1/server-instances", dto.ServerInstanceCreateRequest{
|
||||
ID: "server-ready",
|
||||
@@ -844,7 +852,7 @@ func TestServerDeploymentRevealAPIIsExplicitAndOwnerScoped(t *testing.T) {
|
||||
endpoint := validRunEndpointRequest()
|
||||
endpoint.Capabilities = append(endpoint.Capabilities, domain.JobCapabilityDeploymentPlan)
|
||||
postJSON[dto.RunEndpointResponse](t, router, "/api/v1/run/endpoints", endpoint)
|
||||
created := postOKJSONWithAuth[dto.ServerLifecycleResponse](t, router, "/api/v1/server-instances/workflows/create", dto.ServerLifecycleCreateRequest{ID: "deployment-reveal", PluginID: "server.scum", RunEndpointID: "run-local", Name: "Reveal", IdempotencyKey: "deployment-reveal", ProfileKey: "local", Deployment: dto.ServerDeploymentRequest{Mode: domain.ServerDeploymentModeCustom, ServerRoot: "/srv/reveal", WorkingDirectory: "/srv/reveal", StartCommand: "./start-server"}}, adminSession)
|
||||
postOKJSONWithAuth[dto.ServerLifecycleResponse](t, router, "/api/v1/server-instances/workflows/create", dto.ServerLifecycleCreateRequest{ID: "deployment-reveal", PluginID: "server.scum", Name: "Reveal", IdempotencyKey: "deployment-reveal", Deployment: dto.ServerDeploymentRequest{Mode: domain.ServerDeploymentModeCustom, ServerRoot: "/srv/reveal", WorkingDirectory: "/srv/reveal", StartCommand: "./start-server"}}, adminSession)
|
||||
|
||||
redactedRecorder := requestWithAuth(t, router, http.MethodGet, "/api/v1/server-instances/deployment-reveal/deployment", "", adminSession)
|
||||
assertStatus(t, redactedRecorder, http.StatusOK)
|
||||
@@ -852,8 +860,8 @@ func TestServerDeploymentRevealAPIIsExplicitAndOwnerScoped(t *testing.T) {
|
||||
t.Fatalf("normal deployment view leaked protected inputs: %s", body)
|
||||
}
|
||||
redacted := decodeBody[dto.ServerDeploymentResponse](t, redactedRecorder)
|
||||
if redacted.LatestDispatch == nil || !redacted.LatestDispatch.DeploymentDefinitionIncluded || redacted.LatestDispatch.JobID != created.Job.ID || redacted.LatestDispatch.DeploymentRevision != 1 {
|
||||
t.Fatalf("expected safe deployment dispatch evidence, got %+v", redacted.LatestDispatch)
|
||||
if redacted.LatestDispatch != nil {
|
||||
t.Fatalf("create-time deployment settings must not dispatch to Run, got %+v", redacted.LatestDispatch)
|
||||
}
|
||||
|
||||
revealed := getJSONWithAuth[dto.ServerDeploymentRevealResponse](t, router, "/api/v1/server-instances/deployment-reveal/deployment/reveal", adminSession)
|
||||
@@ -1631,10 +1639,8 @@ func TestRuntimeBindingAPIIsAuthorizedValidatedAndRedacted(t *testing.T) {
|
||||
undeclared := requestJSONWithAuth(t, router, http.MethodPut, "/api/v1/server-instances/"+server.ID+"/runtime-binding", dto.RuntimeBindingUpdateRequest{ProfileKey: "local", Bindings: map[string]string{"host.socket": "runtime.socket"}}, adminSession)
|
||||
assertErrorResponse(t, undeclared, http.StatusBadRequest, errorCodeValidation)
|
||||
|
||||
created := postOKJSONWithAuth[dto.ServerLifecycleResponse](t, router, "/api/v1/server-instances/workflows/create", dto.ServerLifecycleCreateRequest{ID: "runtime-create-complete", PluginID: registration.Manifest.ID, RunEndpointID: "run-local", Name: "Runtime Create Complete", IdempotencyKey: "runtime-create-complete", ProfileKey: "local", Bindings: map[string]string{"server-root": "runtime.server-root", "rcon.password": "secret://runtime-create-complete/rcon"}}, adminSession)
|
||||
if created.Job.TargetKey != "actions/install.json" {
|
||||
t.Fatalf("create workflow did not dispatch selected profile: %+v", created.Job)
|
||||
}
|
||||
legacyCreate := requestJSONWithAuth(t, router, http.MethodPost, "/api/v1/server-instances/workflows/create", dto.ServerLifecycleCreateRequest{ID: "runtime-create-complete", PluginID: registration.Manifest.ID, RunEndpointID: "run-local", Name: "Runtime Create Complete", IdempotencyKey: "runtime-create-complete", ProfileKey: "local", Bindings: map[string]string{"server-root": "runtime.server-root", "rcon.password": "secret://runtime-create-complete/rcon"}}, adminSession)
|
||||
assertErrorResponse(t, legacyCreate, http.StatusBadRequest, errorCodeValidation)
|
||||
incompleteCreate := requestJSONWithAuth(t, router, http.MethodPost, "/api/v1/server-instances/workflows/create", dto.ServerLifecycleCreateRequest{ID: "runtime-create-incomplete", PluginID: registration.Manifest.ID, RunEndpointID: "run-local", Name: "Runtime Create Incomplete", IdempotencyKey: "runtime-create-incomplete", ProfileKey: "local", Bindings: map[string]string{"server-root": "runtime.server-root"}}, adminSession)
|
||||
assertErrorResponse(t, incompleteCreate, http.StatusBadRequest, errorCodeValidation)
|
||||
missingServer := requestWithAuth(t, router, http.MethodGet, "/api/v1/server-instances/runtime-create-incomplete", "", adminSession)
|
||||
|
||||
@@ -137,7 +137,7 @@ Artifact bridge execution returns safe metadata and platform content routes only
|
||||
|
||||
## Implemented Server Lifecycle Actions
|
||||
|
||||
- `POST /api/v1/server-instances/workflows/create`: accepts `ServerLifecycleCreateRequest`. Creation starts from `pluginId` and `name`, and may include the create-wizard deployment definition such as deployment mode, plugin create inputs, server root, or custom start command. The browser must not require a deployment target, run endpoint, or runtime profile at creation; those bindings remain post-creation/runtime-registration concerns. Legacy `runEndpointId` and `deploymentTargetId` inputs remain accepted for compatible programmatic flows, but are never prerequisites for creation and do not select a distribution builder.
|
||||
- `POST /api/v1/server-instances/workflows/create`: accepts `ServerLifecycleCreateRequest`. Creation starts from `pluginId` and `name`, and may include the create-wizard deployment definition such as deployment mode, plugin create inputs, server root, or custom start command. The browser must not require or submit a deployment target, run endpoint, runtime profile, or runtime bindings during creation; those bindings remain post-creation/runtime-registration concerns. Requests that include `deploymentTargetId`, `runEndpointId`, `profileKey`, `bindings`, `deployment.runEndpointId`, `deployment.profileKey`, or `deployment.runtimeBindings` are rejected.
|
||||
- `POST /api/v1/server-instances/{id}/start`: accept `ServerLifecycleCommandRequest`, validate state/config version/run capability, and queue a `process.start` job using `ServerLifecycleResponse`.
|
||||
- `POST /api/v1/server-instances/{id}/stop`: accept `ServerLifecycleCommandRequest`, validate state/config version/run capability, and queue a `process.stop` job using `ServerLifecycleResponse`.
|
||||
|
||||
|
||||
@@ -29,6 +29,10 @@ func (h *coreHandlers) serverInstanceCreateWorkflow(w http.ResponseWriter, r *ht
|
||||
writeDecodeError(w, err)
|
||||
return
|
||||
}
|
||||
if err := request.ValidateCreateOnly(); err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
}
|
||||
result, err := h.core.CreateServerInstanceWorkflowForSession(bearerToken(r), request.ToDomain())
|
||||
if err != nil {
|
||||
writeServiceError(w, err)
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"browser.local/platform/domain"
|
||||
"browser.local/platform/validator"
|
||||
)
|
||||
|
||||
type ServerDeploymentRequest struct {
|
||||
@@ -78,7 +80,7 @@ type ServerLifecycleCreateRequest struct {
|
||||
ID string `json:"id"`
|
||||
PluginID string `json:"pluginId"`
|
||||
DeploymentTargetID string `json:"deploymentTargetId,omitempty"`
|
||||
RunEndpointID string `json:"runEndpointId"`
|
||||
RunEndpointID string `json:"runEndpointId,omitempty"`
|
||||
Name string `json:"name"`
|
||||
OwnerUserID string `json:"ownerUserId,omitempty"`
|
||||
IdempotencyKey string `json:"idempotencyKey"`
|
||||
@@ -87,6 +89,35 @@ type ServerLifecycleCreateRequest struct {
|
||||
Deployment ServerDeploymentRequest `json:"deployment,omitempty"`
|
||||
}
|
||||
|
||||
func (request ServerLifecycleCreateRequest) ValidateCreateOnly() error {
|
||||
var violations []string
|
||||
if strings.TrimSpace(request.DeploymentTargetID) != "" {
|
||||
violations = append(violations, "deploymentTargetId must not be provided during server creation")
|
||||
}
|
||||
if strings.TrimSpace(request.RunEndpointID) != "" {
|
||||
violations = append(violations, "runEndpointId must not be provided during server creation")
|
||||
}
|
||||
if strings.TrimSpace(request.ProfileKey) != "" {
|
||||
violations = append(violations, "profileKey must not be provided during server creation")
|
||||
}
|
||||
if len(request.Bindings) > 0 {
|
||||
violations = append(violations, "bindings must not be provided during server creation")
|
||||
}
|
||||
if strings.TrimSpace(request.Deployment.RunEndpointID) != "" {
|
||||
violations = append(violations, "deployment.runEndpointId must not be provided during server creation")
|
||||
}
|
||||
if strings.TrimSpace(request.Deployment.ProfileKey) != "" {
|
||||
violations = append(violations, "deployment.profileKey must not be provided during server creation")
|
||||
}
|
||||
if len(request.Deployment.RuntimeBindings) > 0 {
|
||||
violations = append(violations, "deployment.runtimeBindings must not be provided during server creation")
|
||||
}
|
||||
if len(violations) > 0 {
|
||||
return validator.ValidationError{Violations: violations}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ServerLifecycleCommandRequest struct {
|
||||
ExpectedConfigVersion int `json:"expectedConfigVersion"`
|
||||
IdempotencyKey string `json:"idempotencyKey"`
|
||||
@@ -103,13 +134,13 @@ func (request ServerLifecycleCreateRequest) ToDomain() domain.ServerLifecycleCre
|
||||
return domain.ServerLifecycleCreate{
|
||||
ID: request.ID,
|
||||
PluginID: request.PluginID,
|
||||
DeploymentTargetID: request.DeploymentTargetID,
|
||||
RunEndpointID: request.RunEndpointID,
|
||||
DeploymentTargetID: "",
|
||||
RunEndpointID: "",
|
||||
Name: request.Name,
|
||||
OwnerUserID: request.OwnerUserID,
|
||||
IdempotencyKey: request.IdempotencyKey,
|
||||
ProfileKey: request.ProfileKey,
|
||||
Bindings: domain.CopyStringMap(request.Bindings),
|
||||
ProfileKey: "",
|
||||
Bindings: nil,
|
||||
Deployment: request.Deployment.deploymentDefinition(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -621,7 +621,7 @@ describe("PlatformApiClient AI providers", () => {
|
||||
await expect(client.listArtifacts({ ownerKind: "job", ownerId: job.id, state: "available" })).resolves.toMatchObject({ count: 1, items: [{ id: artifact.id }] });
|
||||
await expect(client.openArtifactDownload(artifact.id)).resolves.toMatchObject({ downloadUrl: "/api/v1/artifacts/artifact-1/content", rangeSupported: true });
|
||||
await expect(client.readArtifactContent(artifact.id, 0, 8)).resolves.toMatchObject({ contentLength: 8, contentRange: "bytes 0-7/18", checksum: artifact.checksum });
|
||||
await expect(client.createServerWorkflow({ id: "server-2", pluginId: plugin.id, runEndpointId: endpoint.id, name: "Server 2", idempotencyKey: "idem-create", profileKey: "local", bindings: {} })).resolves.toMatchObject({
|
||||
await expect(client.createServerWorkflow({ id: "server-2", pluginId: plugin.id, name: "Server 2", idempotencyKey: "idem-create" })).resolves.toMatchObject({
|
||||
action: "create"
|
||||
});
|
||||
await expect(client.startServerInstance(server.id, { expectedConfigVersion: 1, idempotencyKey: "idem-start" })).resolves.toMatchObject({ action: "start" });
|
||||
|
||||
@@ -22,7 +22,7 @@ Normal browser login uses the platform's HttpOnly SameSite cookie and `credentia
|
||||
|
||||
## Server Management Workflows
|
||||
|
||||
- `createServerWorkflow` posts `ServerLifecycleCreateRequest` with the create-wizard deployment definition to `/server-instances/workflows/create`, including deployment mode, plugin create inputs, and custom startup fields when provided. It does not require deployment target, run endpoint, or runtime profile selection during creation.
|
||||
- `createServerWorkflow` posts `ServerLifecycleCreateRequest` with the create-wizard deployment definition to `/server-instances/workflows/create`, including deployment mode, plugin create inputs, and custom startup fields when provided. It must not include deployment target, run endpoint, runtime profile, or runtime bindings during creation; those are established only after creation through generated Run registration, runtime binding, or deployment update flows.
|
||||
- `getServerRuntimeBinding` reads `/server-instances/{id}/runtime-binding`; `updateServerRuntimeBinding` patches the selected profile and logical refs. Responses contain only profile metadata, logical key names, configured/secret-backed flags, missing keys, and safe reasons. They never contain stored refs or secret values.
|
||||
- `startServerInstance` and `stopServerInstance` post `ServerLifecycleCommandRequest` with the current config version and receive the lifecycle job response.
|
||||
- `listServerAdministratorCandidates`, `addServerAdministrator`, and `removeServerAdministrator` call server membership endpoints so server owners can invite or remove active non-platform-admin server administrators.
|
||||
|
||||
@@ -505,12 +505,8 @@ export interface ServerInstanceListResponse {
|
||||
export interface ServerLifecycleCreateRequest {
|
||||
id: string;
|
||||
pluginId: string;
|
||||
deploymentTargetId?: string;
|
||||
runEndpointId?: string;
|
||||
name: string;
|
||||
idempotencyKey: string;
|
||||
profileKey?: string;
|
||||
bindings?: Record<string, string>;
|
||||
deployment?: ServerDeploymentRequest;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,13 +116,17 @@ describe("ServerDeploymentWorkflow", () => {
|
||||
pluginId: "game.runtime",
|
||||
name: "Custom Runtime Server",
|
||||
idempotencyKey: "web:create:server-custom-runtime-server-17:17",
|
||||
runEndpointId: undefined,
|
||||
deployment: {
|
||||
mode: "custom-command",
|
||||
serverRoot: "/srv/custom-runtime",
|
||||
startCommand: "./start-runtime.sh"
|
||||
}
|
||||
});
|
||||
expect(submitted && "runEndpointId" in submitted).toBe(false);
|
||||
expect(submitted && "profileKey" in submitted).toBe(false);
|
||||
expect(submitted && "bindings" in submitted).toBe(false);
|
||||
expect(submitted?.deployment && "profileKey" in submitted.deployment).toBe(false);
|
||||
expect(submitted?.deployment && "runtimeBindings" in submitted.deployment).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import { UsersPage } from "./UsersPage";
|
||||
import runtimeTaskProgressSource from "../components/RuntimeTaskProgress.tsx?raw";
|
||||
import serverDeploymentWorkflowSource from "../components/ServerDeploymentWorkflow.tsx?raw";
|
||||
import serverLiveOperationsSource from "../components/ServerLiveOperations.tsx?raw";
|
||||
import serverCreateSchemaSource from "../schemas/serverManagement.ts?raw";
|
||||
import serversPageSource from "./ServersPage.tsx?raw";
|
||||
import serverDetailPageSource from "./ServerDetailPage.tsx?raw";
|
||||
import type { PageComponentProps } from "../contracts/page";
|
||||
@@ -239,6 +240,10 @@ describe("first-party console pages", () => {
|
||||
expect(serverDeploymentWorkflowSource).toContain('const configurationStep = kind === "create" ? 2 : needsTargetSelection ? 1 : 0;');
|
||||
expect(serverDeploymentWorkflowSource).toContain('const needsTargetSelection = kind === "edit" && !initialForm.runEndpointId;');
|
||||
expect(serversPageSource).toContain("serverCreateRequestFromForm(nextForm)");
|
||||
expect(serverCreateSchemaSource).not.toContain("runEndpointId: form.runEndpointId");
|
||||
expect(serverCreateSchemaSource).not.toContain("deploymentTargetId: form.deploymentTargetId");
|
||||
expect(serverCreateSchemaSource).not.toContain("profileKey: form.profileKey");
|
||||
expect(serverCreateSchemaSource).not.toContain("runtimeBindings:");
|
||||
});
|
||||
|
||||
it("renders server runtime actions as a compact popover trigger instead of an in-card details stack", () => {
|
||||
|
||||
@@ -107,9 +107,7 @@ export function ServersPage({ session, operations, onNavigate }: PageComponentPr
|
||||
pluginId: plugin?.id ?? "",
|
||||
profileKey,
|
||||
bindings: plugin?.id === current.pluginId && profileKey === current.profileKey ? current.bindings : {},
|
||||
runEndpointId: endpointResponse.items.some((endpoint) => endpoint.id === current.runEndpointId)
|
||||
? current.runEndpointId
|
||||
: endpointResponse.items[0]?.id || ""
|
||||
runEndpointId: endpointResponse.items.some((endpoint) => endpoint.id === current.runEndpointId) ? current.runEndpointId : ""
|
||||
};
|
||||
});
|
||||
if (showLoading) {
|
||||
|
||||
@@ -53,7 +53,7 @@ describe("runtime profile server creation contracts", () => {
|
||||
expect(runtimeBindingFields(plugin, "local").some((field) => field.key === "ftp.profile")).toBe(false);
|
||||
});
|
||||
|
||||
it("selects the plugin profile and submits real profile bindings", () => {
|
||||
it("submits deployment inputs without binding a Run or runtime profile", () => {
|
||||
const form = defaultServerCreateForm([plugin], []);
|
||||
expect(form.profileKey).toBe("local");
|
||||
expect(
|
||||
@@ -69,15 +69,10 @@ describe("runtime profile server creation contracts", () => {
|
||||
).toEqual({
|
||||
id: "server-1",
|
||||
pluginId: "game.runtime",
|
||||
runEndpointId: undefined,
|
||||
name: "Runtime Server",
|
||||
idempotencyKey: "web:create:server-1:17",
|
||||
profileKey: "local",
|
||||
bindings: { "server-root": "runtime.server-root", "rcon.password": "secret://runtime/server-1/rcon" },
|
||||
deployment: {
|
||||
mode: "guided-install",
|
||||
profileKey: "local",
|
||||
runtimeBindings: { "server-root": "runtime.server-root", "rcon.password": "secret://runtime/server-1/rcon" },
|
||||
createInputs: { gamePort: "7777", maxPlayers: "64" }
|
||||
}
|
||||
});
|
||||
@@ -117,7 +112,11 @@ describe("runtime profile server creation contracts", () => {
|
||||
it("keeps complete paths and commands in a write-only deployment payload", () => {
|
||||
const form = defaultServerCreateForm([plugin], []);
|
||||
const request = serverCreateRequestFromForm({ ...form, name: "Venv Server", deploymentMode: "custom-command", serverRoot: "/srv/venv-server", workingDirectory: "/srv/venv-server", startCommand: "/srv/venv-server/.venv/bin/python server.py", shell: "" }, 19);
|
||||
expect(request.runEndpointId).toBeUndefined();
|
||||
expect("runEndpointId" in request).toBe(false);
|
||||
expect("profileKey" in request).toBe(false);
|
||||
expect("bindings" in request).toBe(false);
|
||||
expect(request.deployment).toMatchObject({ mode: "custom-command", serverRoot: "/srv/venv-server", workingDirectory: "/srv/venv-server", startCommand: "/srv/venv-server/.venv/bin/python server.py" });
|
||||
expect("profileKey" in (request.deployment ?? {})).toBe(false);
|
||||
expect("runtimeBindings" in (request.deployment ?? {})).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,16 +26,10 @@ export function serverCreateRequestFromForm(form: ServerCreateFormState, sequenc
|
||||
return {
|
||||
id,
|
||||
pluginId: form.pluginId.trim(),
|
||||
deploymentTargetId: form.deploymentTargetId.trim() || undefined,
|
||||
runEndpointId: form.runEndpointId.trim() || undefined,
|
||||
name: form.name.trim(),
|
||||
idempotencyKey: lifecycleIdempotencyKey("create", id, sequence),
|
||||
profileKey: form.profileKey.trim() || undefined,
|
||||
bindings: Object.fromEntries(Object.entries(form.bindings).map(([key, value]) => [key, value.trim()]).filter(([, value]) => value !== "")),
|
||||
deployment: {
|
||||
mode: form.deploymentMode,
|
||||
profileKey: form.profileKey.trim() || undefined,
|
||||
runtimeBindings: Object.fromEntries(Object.entries(form.bindings).map(([key, value]) => [key, value.trim()]).filter(([, value]) => value !== "")),
|
||||
createInputs: Object.fromEntries(Object.entries(form.createInputs).map(([key, value]) => [key, value.trim()])),
|
||||
serverRoot: form.serverRoot.trim() || undefined,
|
||||
workingDirectory: form.workingDirectory.trim() || undefined,
|
||||
|
||||
@@ -847,11 +847,8 @@ cat >"$WORK_DIR/create-scum-beta.request.json" <<JSON
|
||||
{
|
||||
"id": "$SCUM_BETA_ID",
|
||||
"pluginId": "game.scum",
|
||||
"runEndpointId": "$RUN_ENDPOINT_ID",
|
||||
"name": "SCUM Beta $SMOKE_INVOCATION_ID",
|
||||
"idempotencyKey": "local-debug-scum-beta-create-$SMOKE_INVOCATION_ID",
|
||||
"profileKey": "run-local",
|
||||
"bindings": {}
|
||||
"idempotencyKey": "local-debug-scum-beta-create-$SMOKE_INVOCATION_ID"
|
||||
}
|
||||
JSON
|
||||
|
||||
@@ -859,11 +856,8 @@ cat >"$WORK_DIR/create-scum-dynamic.request.json" <<JSON
|
||||
{
|
||||
"id": "$SCUM_DYNAMIC_ID",
|
||||
"pluginId": "game.scum",
|
||||
"runEndpointId": "$RUN_ENDPOINT_ID",
|
||||
"name": "SCUM Dynamic $SMOKE_INVOCATION_ID",
|
||||
"idempotencyKey": "local-debug-scum-dynamic-create-$SMOKE_INVOCATION_ID",
|
||||
"profileKey": "run-local",
|
||||
"bindings": {}
|
||||
"idempotencyKey": "local-debug-scum-dynamic-create-$SMOKE_INVOCATION_ID"
|
||||
}
|
||||
JSON
|
||||
|
||||
@@ -1000,8 +994,6 @@ curl -fsS -X PUT -H 'Content-Type: application/json' "${AUTH_HEADER[@]}" \
|
||||
reject_forbidden_fragments "$WORK_DIR/scum-alpha-runtime-binding.response.json"
|
||||
require_file_contains "$WORK_DIR/scum-alpha-runtime-binding.response.json" '"status"[[:space:]]*:[[:space:]]*"complete"'
|
||||
|
||||
wait_for_lifecycle_install_success "$SCUM_DYNAMIC_ID" "$WORK_DIR/scum-dynamic-jobs.response.json"
|
||||
|
||||
printf 'checking SCUM runtime distribution action\n'
|
||||
json_get "$API_URL/server-instances/$SCUM_ALPHA_ID/runtime/actions" "$WORK_DIR/scum-alpha-runtime-actions.response.json" "${AUTH_HEADER[@]}"
|
||||
reject_forbidden_fragments "$WORK_DIR/scum-alpha-runtime-actions.response.json"
|
||||
@@ -1047,8 +1039,6 @@ printf 'checking jobs, logs, artifacts, and marketplace refs\n'
|
||||
json_get "$API_URL/server-instances" "$WORK_DIR/server-instances.response.json" "${AUTH_HEADER[@]}"
|
||||
json_get "$API_URL/jobs?serverInstanceId=$SERVER_ID" "$WORK_DIR/jobs.response.json" "${AUTH_HEADER[@]}"
|
||||
json_get "$API_URL/jobs?serverInstanceId=$SCUM_ALPHA_ID" "$WORK_DIR/scum-alpha-jobs.response.json" "${AUTH_HEADER[@]}"
|
||||
json_get "$API_URL/jobs?serverInstanceId=$SCUM_BETA_ID" "$WORK_DIR/scum-beta-jobs.response.json" "${AUTH_HEADER[@]}"
|
||||
json_get "$API_URL/jobs?serverInstanceId=$SCUM_DYNAMIC_ID" "$WORK_DIR/scum-dynamic-jobs.response.json" "${AUTH_HEADER[@]}"
|
||||
json_get "$API_URL/log-streams" "$WORK_DIR/log-streams.response.json" "${AUTH_HEADER[@]}"
|
||||
json_get "$API_URL/artifacts" "$WORK_DIR/artifacts.response.json" "${AUTH_HEADER[@]}"
|
||||
json_get "$API_URL/plugin-marketplace/plugins" "$WORK_DIR/marketplace.response.json" "${AUTH_HEADER[@]}"
|
||||
@@ -1056,8 +1046,8 @@ json_get "$API_URL/plugin-marketplace/plugins?serverType=scum&keyword=scum" "$WO
|
||||
require_file_contains "$WORK_DIR/scum-marketplace.response.json" '"id"[[:space:]]*:[[:space:]]*"game.scum"'
|
||||
require_file_contains "$WORK_DIR/artifacts.response.json" "\"id\"[[:space:]]*:[[:space:]]*\"artifact-run-dist-$SCUM_ALPHA_ID"
|
||||
require_file_contains "$WORK_DIR/scum-alpha-jobs.response.json" "\"serverInstanceId\"[[:space:]]*:[[:space:]]*\"$SCUM_ALPHA_ID\""
|
||||
require_file_contains "$WORK_DIR/scum-beta-jobs.response.json" "\"serverInstanceId\"[[:space:]]*:[[:space:]]*\"$SCUM_BETA_ID\""
|
||||
require_file_contains "$WORK_DIR/scum-dynamic-jobs.response.json" '"state"[[:space:]]*:[[:space:]]*"succeeded"'
|
||||
require_file_contains "$WORK_DIR/server-instances.response.json" "\"id\"[[:space:]]*:[[:space:]]*\"$SCUM_BETA_ID\""
|
||||
require_file_contains "$WORK_DIR/server-instances.response.json" "\"id\"[[:space:]]*:[[:space:]]*\"$SCUM_DYNAMIC_ID\""
|
||||
|
||||
for file in \
|
||||
"$WORK_DIR"/server-instances.response.json \
|
||||
|
||||
Reference in New Issue
Block a user