feat: 自动更新
This commit is contained in:
@@ -74,6 +74,7 @@ func (h *coreHandlers) register(mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/v1/run/jobs/ack", h.runJobAck)
|
||||
mux.HandleFunc("/api/v1/run/jobs/progress", h.runJobProgress)
|
||||
mux.HandleFunc("/api/v1/run/jobs/result", h.runJobResult)
|
||||
mux.HandleFunc("/api/v1/run/jobs/build-input", h.runJobBuildInput)
|
||||
mux.HandleFunc("/api/v1/run/jobs/cancel", h.runJobCancelPoll)
|
||||
mux.HandleFunc("/api/v1/run/jobs/reconcile", h.runJobReconcile)
|
||||
mux.HandleFunc("/api/v1/run/logs/batches", h.runLogBatchIngest)
|
||||
@@ -462,6 +463,9 @@ func (h *coreHandlers) requirePlatformAdmin(w http.ResponseWriter, r *http.Reque
|
||||
// @Router /api/v1/ai-providers [get]
|
||||
// @Router /api/v1/ai-providers [post]
|
||||
func (h *coreHandlers) aiProviders(w http.ResponseWriter, r *http.Request) {
|
||||
if _, ok := h.requirePlatformAdmin(w, r); !ok {
|
||||
return
|
||||
}
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
providers, err := h.core.ListAIProviders(domain.AIProviderFilter{
|
||||
@@ -504,6 +508,9 @@ func (h *coreHandlers) aiProviders(w http.ResponseWriter, r *http.Request) {
|
||||
// @Router /api/v1/ai-providers/{id} [get]
|
||||
// @Router /api/v1/ai-providers/{id} [put]
|
||||
func (h *coreHandlers) aiProviderDetail(w http.ResponseWriter, r *http.Request) {
|
||||
if _, ok := h.requirePlatformAdmin(w, r); !ok {
|
||||
return
|
||||
}
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
provider, err := h.core.GetAIProvider(r.PathValue("id"))
|
||||
@@ -548,6 +555,9 @@ func (h *coreHandlers) aiProviderDetail(w http.ResponseWriter, r *http.Request)
|
||||
// @Failure 405 {object} dto.ErrorResponse
|
||||
// @Router /api/v1/ai-providers/{id}/status [post]
|
||||
func (h *coreHandlers) aiProviderStatus(w http.ResponseWriter, r *http.Request) {
|
||||
if _, ok := h.requirePlatformAdmin(w, r); !ok {
|
||||
return
|
||||
}
|
||||
if r.Method != http.MethodPost {
|
||||
writeMethodNotAllowed(w, http.MethodPost)
|
||||
return
|
||||
@@ -576,6 +586,9 @@ func (h *coreHandlers) aiProviderStatus(w http.ResponseWriter, r *http.Request)
|
||||
// @Failure 405 {object} dto.ErrorResponse
|
||||
// @Router /api/v1/ai-providers/{id}/test [post]
|
||||
func (h *coreHandlers) aiProviderTest(w http.ResponseWriter, r *http.Request) {
|
||||
if _, ok := h.requirePlatformAdmin(w, r); !ok {
|
||||
return
|
||||
}
|
||||
if r.Method != http.MethodPost {
|
||||
writeMethodNotAllowed(w, http.MethodPost)
|
||||
return
|
||||
@@ -599,6 +612,9 @@ func (h *coreHandlers) aiProviderTest(w http.ResponseWriter, r *http.Request) {
|
||||
// @Failure 405 {object} dto.ErrorResponse
|
||||
// @Router /api/v1/ai-providers/{id}/models [get]
|
||||
func (h *coreHandlers) aiProviderModels(w http.ResponseWriter, r *http.Request) {
|
||||
if _, ok := h.requirePlatformAdmin(w, r); !ok {
|
||||
return
|
||||
}
|
||||
if r.Method != http.MethodGet {
|
||||
writeMethodNotAllowed(w, http.MethodGet)
|
||||
return
|
||||
@@ -1383,6 +1399,25 @@ func (h *coreHandlers) runJobResult(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, dto.RunJobResultFromDomain(result))
|
||||
}
|
||||
|
||||
// runJobBuildInput returns secret-bearing build input only to the active leased run worker.
|
||||
func (h *coreHandlers) runJobBuildInput(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeMethodNotAllowed(w, http.MethodPost)
|
||||
return
|
||||
}
|
||||
request, err := decodeJSON[dto.DistributionBuildInputRequest](r)
|
||||
if err != nil {
|
||||
writeDecodeError(w, err)
|
||||
return
|
||||
}
|
||||
result, err := h.core.GetDistributionBuildInput(request.ToDomain())
|
||||
if err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, dto.DistributionBuildInputFromDomain(result))
|
||||
}
|
||||
|
||||
// runJobCancelPoll godoc
|
||||
// @Summary Poll run job cancellation
|
||||
// @Description Lets a registered run endpoint poll for cancellation requests on active leased jobs.
|
||||
|
||||
@@ -35,12 +35,12 @@ func TestCoreAPICreateListDetailWorkflows(t *testing.T) {
|
||||
users := getJSONWithAuth[dto.UserListResponse](t, router, "/api/v1/users?status=active", adminSession)
|
||||
assertListCount(t, users.Count, 2)
|
||||
|
||||
providerResponse := postJSON[dto.AIProviderResponse](t, router, "/api/v1/ai-providers", validAIProviderRequest())
|
||||
providerResponse := createAIProviderFixture(t, router, adminSession)
|
||||
if providerResponse.APIKeyRef != "secret://providers/openai" {
|
||||
t.Fatalf("expected AI provider key reference, got %+v", providerResponse)
|
||||
}
|
||||
getJSON[dto.AIProviderResponse](t, router, "/api/v1/ai-providers/ai.openai")
|
||||
providers := getJSON[dto.AIProviderListResponse](t, router, "/api/v1/ai-providers?kind=openai&status=active")
|
||||
getJSONWithAuth[dto.AIProviderResponse](t, router, "/api/v1/ai-providers/ai.openai", adminSession)
|
||||
providers := getJSONWithAuth[dto.AIProviderListResponse](t, router, "/api/v1/ai-providers?kind=openai&status=active", adminSession)
|
||||
assertListCount(t, providers.Count, 1)
|
||||
|
||||
pluginResponse := postJSON[dto.GamePluginResponse](t, router, "/api/v1/game-plugins", validGamePluginRequest())
|
||||
@@ -305,28 +305,18 @@ func TestCoreAPIServerRuntimeDistributionAndJobWorkflows(t *testing.T) {
|
||||
}
|
||||
|
||||
runDistribution := postJSONWithAuth[dto.RunDistributionResponse](t, router, "/api/v1/server-instances/"+serverID+"/run/generate", dto.RunDistributionGenerateRequest{TargetOS: "linux", TargetArch: "amd64", IdempotencyKey: "api-run-generate"}, adminSession)
|
||||
if runDistribution.ArtifactID == "" || runDistribution.KeyGeneration != 1 || runDistribution.SecretRef == "" {
|
||||
if runDistribution.ArtifactID == "" || runDistribution.BuildJobID == "" || runDistribution.KeyGeneration != 1 || runDistribution.SecretRef == "" || runDistribution.Status != string(domain.DistributionStatusBuilding) {
|
||||
t.Fatalf("unexpected run distribution: %+v", runDistribution)
|
||||
}
|
||||
runDownload := postOKJSONWithAuth[dto.ArtifactDownloadReferenceResponse](t, router, "/api/v1/server-instances/"+serverID+"/run/download", map[string]string{}, adminSession)
|
||||
if runDownload.ArtifactID != runDistribution.ArtifactID || runDownload.DownloadURL == "" {
|
||||
t.Fatalf("unexpected run download: %+v", runDownload)
|
||||
}
|
||||
updateRecorder := requestJSONWithAuth(t, router, http.MethodPost, "/api/v1/server-instances/"+serverID+"/run/update", dto.RunUpdateRequest{ArtifactID: runDistribution.ArtifactID, Checksum: runDistribution.Checksum, IdempotencyKey: "api-run-update"}, adminSession)
|
||||
assertStatus(t, updateRecorder, http.StatusAccepted)
|
||||
update := decodeBody[dto.RunUpdateJobResponse](t, updateRecorder)
|
||||
if update.JobID == "" || update.ArtifactID != runDistribution.ArtifactID || update.Status != string(domain.DistributionJobStatusQueued) {
|
||||
t.Fatalf("unexpected run update job: %+v", update)
|
||||
}
|
||||
runDownloadRecorder := requestJSONWithAuth(t, router, http.MethodPost, "/api/v1/server-instances/"+serverID+"/run/download", map[string]string{}, adminSession)
|
||||
assertErrorResponse(t, runDownloadRecorder, http.StatusNotFound, errorCodeNotFound)
|
||||
|
||||
clientDistribution := postJSONWithAuth[dto.ClientManagerDistributionResponse](t, router, "/api/v1/server-instances/"+serverID+"/client-managers/generate", dto.ClientManagerBuildRequest{ProfileKey: "scum-client-manager", TargetOS: "windows", TargetArch: "amd64", RepositoryURL: "https://github.com/F88888/scum_client.git", SourceRevision: "main", IdempotencyKey: "api-client-manager"}, adminSession)
|
||||
if clientDistribution.ArtifactID == "" || clientDistribution.BuildJobID == "" || clientDistribution.SecretRef == runDistribution.SecretRef {
|
||||
t.Fatalf("unexpected client distribution: %+v", clientDistribution)
|
||||
}
|
||||
clientDownload := postOKJSONWithAuth[dto.ArtifactDownloadReferenceResponse](t, router, "/api/v1/server-instances/"+serverID+"/client-managers/download", dto.ClientManagerDownloadRequest{ProfileKey: "scum-client-manager"}, adminSession)
|
||||
if clientDownload.ArtifactID != clientDistribution.ArtifactID {
|
||||
t.Fatalf("unexpected client download: %+v", clientDownload)
|
||||
}
|
||||
clientDownloadRecorder := requestJSONWithAuth(t, router, http.MethodPost, "/api/v1/server-instances/"+serverID+"/client-managers/download", dto.ClientManagerDownloadRequest{ProfileKey: "scum-client-manager"}, adminSession)
|
||||
assertErrorResponse(t, clientDownloadRecorder, http.StatusNotFound, errorCodeNotFound)
|
||||
|
||||
dependencyCheckRecorder := requestJSONWithAuth(t, router, http.MethodPost, "/api/v1/server-instances/"+serverID+"/dependencies/check", dto.DependencyJobRequest{ProbeKey: "java-runtime", IdempotencyKey: "api-dependency-check"}, adminSession)
|
||||
assertStatus(t, dependencyCheckRecorder, http.StatusAccepted)
|
||||
@@ -363,7 +353,7 @@ func TestCoreAPIServerRuntimeDistributionAndJobWorkflows(t *testing.T) {
|
||||
t.Fatalf("unexpected client key reset: %+v", clientReset)
|
||||
}
|
||||
|
||||
for _, body := range []string{mustJSON(t, runDistribution), mustJSON(t, clientDistribution), mustJSON(t, runDownload), mustJSON(t, clientDownload), mustJSON(t, runReset), mustJSON(t, clientReset), mustJSON(t, dependencyInstall), mustJSON(t, backfill)} {
|
||||
for _, body := range []string{mustJSON(t, runDistribution), mustJSON(t, clientDistribution), mustJSON(t, runReset), mustJSON(t, clientReset), mustJSON(t, dependencyInstall), mustJSON(t, backfill)} {
|
||||
for _, forbidden := range []string{"authKey", "enc:v1", "password=", "unix://", "tcp://", "/Users/", "mysql://", "sqlite://"} {
|
||||
if strings.Contains(body, forbidden) {
|
||||
t.Fatalf("runtime API response exposed forbidden fragment %q: %s", forbidden, body)
|
||||
@@ -376,7 +366,7 @@ func TestCoreAPIServerRuntimeDistributionAndJobWorkflows(t *testing.T) {
|
||||
for _, audit := range audits.Items {
|
||||
auditActions[audit.Action] = true
|
||||
}
|
||||
for _, action := range []string{"run.generate", "run.download", "run.update", "client-manager.build", "client-manager.download", "dependency.install", "logs.backfill", "runtime-key.reset"} {
|
||||
for _, action := range []string{"run.generate", "client-manager.build", "dependency.install", "logs.backfill", "runtime-key.reset"} {
|
||||
if !auditActions[action] {
|
||||
t.Fatalf("expected audit action %q in %+v", action, audits.Items)
|
||||
}
|
||||
@@ -412,9 +402,9 @@ func TestCoreAPIErrorResponses(t *testing.T) {
|
||||
rawKey := validAIProviderRequest()
|
||||
rawKey.ID = "ai.raw"
|
||||
rawKey.APIKeyRef = "sk-raw-secret"
|
||||
providerFailure := performJSON(t, router, http.MethodPost, "/api/v1/ai-providers", rawKey)
|
||||
providerFailure := requestJSONWithAuth(t, router, http.MethodPost, "/api/v1/ai-providers", rawKey, adminSession)
|
||||
assertErrorResponse(t, providerFailure, http.StatusBadRequest, errorCodeValidation)
|
||||
missingProvider := performRaw(t, router, http.MethodGet, "/api/v1/ai-providers/ai.raw", "")
|
||||
missingProvider := requestWithAuth(t, router, http.MethodGet, "/api/v1/ai-providers/ai.raw", "", adminSession)
|
||||
assertErrorResponse(t, missingProvider, http.StatusNotFound, errorCodeNotFound)
|
||||
|
||||
methodFailure := requestWithAuth(t, router, http.MethodDelete, "/api/v1/users", "", adminSession)
|
||||
@@ -791,7 +781,8 @@ func TestServerAccessAPIScopesOwnersAndAdministrators(t *testing.T) {
|
||||
|
||||
func TestAIProviderAPIResponseDoesNotExposeRawKeyFields(t *testing.T) {
|
||||
router := newTestRouter()
|
||||
recorder := performJSON(t, router, http.MethodPost, "/api/v1/ai-providers", validAIProviderRequest())
|
||||
adminSession := createAdminSession(t, router)
|
||||
recorder := requestJSONWithAuth(t, router, http.MethodPost, "/api/v1/ai-providers", validAIProviderRequest(), adminSession)
|
||||
assertStatus(t, recorder, http.StatusCreated)
|
||||
|
||||
var body map[string]any
|
||||
@@ -811,38 +802,39 @@ func TestAIProviderAPIResponseDoesNotExposeRawKeyFields(t *testing.T) {
|
||||
|
||||
func TestAIProviderManagementAPI(t *testing.T) {
|
||||
router := newTestRouter()
|
||||
postJSON[dto.AIProviderResponse](t, router, "/api/v1/ai-providers", validAIProviderRequest())
|
||||
adminSession := createAdminSession(t, router)
|
||||
createAIProviderFixture(t, router, adminSession)
|
||||
|
||||
update := validAIProviderUpdateRequest()
|
||||
updatedRecorder := performJSON(t, router, http.MethodPut, "/api/v1/ai-providers/ai.openai", update)
|
||||
updatedRecorder := requestJSONWithAuth(t, router, http.MethodPut, "/api/v1/ai-providers/ai.openai", update, adminSession)
|
||||
assertStatus(t, updatedRecorder, http.StatusOK)
|
||||
updated := decodeBody[dto.AIProviderResponse](t, updatedRecorder)
|
||||
if updated.Name != "OpenAI Relay" || updated.APIKeyRef != "vault://providers/openai" || updated.Status != domain.AIProviderStatusActive {
|
||||
t.Fatalf("unexpected updated provider: %+v", updated)
|
||||
}
|
||||
|
||||
statusRecorder := performJSON(t, router, http.MethodPost, "/api/v1/ai-providers/ai.openai/status", dto.AIProviderStatusRequest{Status: domain.AIProviderStatusDisabled})
|
||||
statusRecorder := requestJSONWithAuth(t, router, http.MethodPost, "/api/v1/ai-providers/ai.openai/status", dto.AIProviderStatusRequest{Status: domain.AIProviderStatusDisabled}, adminSession)
|
||||
assertStatus(t, statusRecorder, http.StatusOK)
|
||||
disabled := decodeBody[dto.AIProviderResponse](t, statusRecorder)
|
||||
if disabled.Status != domain.AIProviderStatusDisabled {
|
||||
t.Fatalf("expected disabled provider, got %+v", disabled)
|
||||
}
|
||||
|
||||
testRecorder := performRaw(t, router, http.MethodPost, "/api/v1/ai-providers/ai.openai/test", "")
|
||||
testRecorder := requestWithAuth(t, router, http.MethodPost, "/api/v1/ai-providers/ai.openai/test", "", adminSession)
|
||||
assertStatus(t, testRecorder, http.StatusOK)
|
||||
testResult := decodeBody[dto.AIProviderTestResponse](t, testRecorder)
|
||||
if testResult.Success || testResult.Mode != "metadata" {
|
||||
t.Fatalf("expected metadata test failure for disabled provider, got %+v", testResult)
|
||||
}
|
||||
|
||||
models := getJSON[dto.AIProviderModelsResponse](t, router, "/api/v1/ai-providers/ai.openai/models")
|
||||
models := getJSONWithAuth[dto.AIProviderModelsResponse](t, router, "/api/v1/ai-providers/ai.openai/models", adminSession)
|
||||
if models.DefaultModel != "gpt-4.1-mini" || len(models.Models) != 2 {
|
||||
t.Fatalf("unexpected models response: %+v", models)
|
||||
}
|
||||
|
||||
statusRecorder = performJSON(t, router, http.MethodPost, "/api/v1/ai-providers/ai.openai/status", dto.AIProviderStatusRequest{Status: domain.AIProviderStatusActive})
|
||||
statusRecorder = requestJSONWithAuth(t, router, http.MethodPost, "/api/v1/ai-providers/ai.openai/status", dto.AIProviderStatusRequest{Status: domain.AIProviderStatusActive}, adminSession)
|
||||
assertStatus(t, statusRecorder, http.StatusOK)
|
||||
testRecorder = performRaw(t, router, http.MethodPost, "/api/v1/ai-providers/ai.openai/test", "")
|
||||
testRecorder = requestWithAuth(t, router, http.MethodPost, "/api/v1/ai-providers/ai.openai/test", "", adminSession)
|
||||
assertStatus(t, testRecorder, http.StatusOK)
|
||||
testResult = decodeBody[dto.AIProviderTestResponse](t, testRecorder)
|
||||
if !testResult.Success {
|
||||
@@ -852,30 +844,60 @@ func TestAIProviderManagementAPI(t *testing.T) {
|
||||
|
||||
func TestAIProviderManagementAPIErrors(t *testing.T) {
|
||||
router := newTestRouter()
|
||||
postJSON[dto.AIProviderResponse](t, router, "/api/v1/ai-providers", validAIProviderRequest())
|
||||
adminSession := createAdminSession(t, router)
|
||||
createAIProviderFixture(t, router, adminSession)
|
||||
|
||||
rawUpdate := validAIProviderUpdateRequest()
|
||||
rawUpdate.APIKeyRef = "sk-raw-secret"
|
||||
rawFailure := performJSON(t, router, http.MethodPut, "/api/v1/ai-providers/ai.openai", rawUpdate)
|
||||
rawFailure := requestJSONWithAuth(t, router, http.MethodPut, "/api/v1/ai-providers/ai.openai", rawUpdate, adminSession)
|
||||
assertErrorResponse(t, rawFailure, http.StatusBadRequest, errorCodeValidation)
|
||||
|
||||
invalidStatus := performJSON(t, router, http.MethodPost, "/api/v1/ai-providers/ai.openai/status", dto.AIProviderStatusRequest{Status: domain.AIProviderStatusError})
|
||||
invalidStatus := requestJSONWithAuth(t, router, http.MethodPost, "/api/v1/ai-providers/ai.openai/status", dto.AIProviderStatusRequest{Status: domain.AIProviderStatusError}, adminSession)
|
||||
assertErrorResponse(t, invalidStatus, http.StatusBadRequest, errorCodeValidation)
|
||||
|
||||
missingUpdate := performJSON(t, router, http.MethodPut, "/api/v1/ai-providers/missing", validAIProviderUpdateRequest())
|
||||
missingUpdate := requestJSONWithAuth(t, router, http.MethodPut, "/api/v1/ai-providers/missing", validAIProviderUpdateRequest(), adminSession)
|
||||
assertErrorResponse(t, missingUpdate, http.StatusNotFound, errorCodeNotFound)
|
||||
missingStatus := performJSON(t, router, http.MethodPost, "/api/v1/ai-providers/missing/status", dto.AIProviderStatusRequest{Status: domain.AIProviderStatusDisabled})
|
||||
missingStatus := requestJSONWithAuth(t, router, http.MethodPost, "/api/v1/ai-providers/missing/status", dto.AIProviderStatusRequest{Status: domain.AIProviderStatusDisabled}, adminSession)
|
||||
assertErrorResponse(t, missingStatus, http.StatusNotFound, errorCodeNotFound)
|
||||
missingTest := performRaw(t, router, http.MethodPost, "/api/v1/ai-providers/missing/test", "")
|
||||
missingTest := requestWithAuth(t, router, http.MethodPost, "/api/v1/ai-providers/missing/test", "", adminSession)
|
||||
assertErrorResponse(t, missingTest, http.StatusNotFound, errorCodeNotFound)
|
||||
missingModels := performRaw(t, router, http.MethodGet, "/api/v1/ai-providers/missing/models", "")
|
||||
missingModels := requestWithAuth(t, router, http.MethodGet, "/api/v1/ai-providers/missing/models", "", adminSession)
|
||||
assertErrorResponse(t, missingModels, http.StatusNotFound, errorCodeNotFound)
|
||||
}
|
||||
|
||||
func TestAIProviderManagementRequiresPlatformAdmin(t *testing.T) {
|
||||
router := newTestRouter()
|
||||
|
||||
for _, request := range []struct {
|
||||
name string
|
||||
method string
|
||||
path string
|
||||
body any
|
||||
}{
|
||||
{name: "list", method: http.MethodGet, path: "/api/v1/ai-providers"},
|
||||
{name: "create", method: http.MethodPost, path: "/api/v1/ai-providers", body: validAIProviderRequest()},
|
||||
{name: "detail", method: http.MethodGet, path: "/api/v1/ai-providers/ai.openai"},
|
||||
{name: "update", method: http.MethodPut, path: "/api/v1/ai-providers/ai.openai", body: validAIProviderUpdateRequest()},
|
||||
{name: "status", method: http.MethodPost, path: "/api/v1/ai-providers/ai.openai/status", body: dto.AIProviderStatusRequest{Status: domain.AIProviderStatusDisabled}},
|
||||
{name: "test", method: http.MethodPost, path: "/api/v1/ai-providers/ai.openai/test"},
|
||||
{name: "models", method: http.MethodGet, path: "/api/v1/ai-providers/ai.openai/models"},
|
||||
} {
|
||||
t.Run(request.name, func(t *testing.T) {
|
||||
var recorder *httptest.ResponseRecorder
|
||||
if request.body == nil {
|
||||
recorder = performRaw(t, router, request.method, request.path, "")
|
||||
} else {
|
||||
recorder = performJSON(t, router, request.method, request.path, request.body)
|
||||
}
|
||||
assertErrorResponse(t, recorder, http.StatusUnauthorized, errorCodeUnauthorized)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAIInvocationAPIIsMediatedAndSafe(t *testing.T) {
|
||||
router := newTestRouter()
|
||||
adminSession := createAdminSession(t, router)
|
||||
postJSON[dto.AIProviderResponse](t, router, "/api/v1/ai-providers", validAIProviderRequest())
|
||||
createAIProviderFixture(t, router, adminSession)
|
||||
registration := validGamePluginManifestRegistrationRequest()
|
||||
registration.Manifest.Pages[0].Permissions = []string{"server.read", "server.logs.read", "ai.invoke"}
|
||||
registration.Manifest.Pages[0].BridgeActions = []string{string(domain.PluginBridgeActionServerInstancesRead), string(domain.PluginBridgeActionLogsQuery), string(domain.PluginBridgeActionAIInvoke)}
|
||||
@@ -1090,7 +1112,7 @@ func TestPluginBridgeExecuteAPI(t *testing.T) {
|
||||
Password: "secret-password",
|
||||
}, adminSession)
|
||||
ownerSession := postOKJSON[dto.AuthSessionResponse](t, router, "/api/v1/auth/login", dto.LoginRequest{Account: "bridge-owner@example.test", Password: "secret-password"}).SessionID
|
||||
postJSON[dto.AIProviderResponse](t, router, "/api/v1/ai-providers", validAIProviderRequest())
|
||||
createAIProviderFixture(t, router, adminSession)
|
||||
|
||||
registration := validGamePluginManifestRegistrationRequest()
|
||||
registration.Manifest.Bridge.Actions = append(registration.Manifest.Bridge.Actions, string(domain.PluginBridgeActionJobsDispatch))
|
||||
@@ -1404,6 +1426,11 @@ func createAdminSession(t *testing.T, router http.Handler) string {
|
||||
return session.SessionID
|
||||
}
|
||||
|
||||
func createAIProviderFixture(t *testing.T, router http.Handler, adminSession string) dto.AIProviderResponse {
|
||||
t.Helper()
|
||||
return postJSONWithAuth[dto.AIProviderResponse](t, router, "/api/v1/ai-providers", validAIProviderRequest(), adminSession)
|
||||
}
|
||||
|
||||
func decodeBody[T any](t *testing.T, recorder *httptest.ResponseRecorder) T {
|
||||
t.Helper()
|
||||
var body T
|
||||
@@ -1494,6 +1521,7 @@ func createRuntimeAPIFixtures(t *testing.T, router http.Handler, adminSession st
|
||||
endpoint := validRunEndpointRequest()
|
||||
endpoint.ID = "run-runtime"
|
||||
endpoint.Capabilities = append(endpoint.Capabilities,
|
||||
domain.JobCapabilityDistributionBuild,
|
||||
domain.JobCapabilityRunSelfUpdate,
|
||||
domain.JobCapabilityDependenciesCheck,
|
||||
domain.JobCapabilityDependenciesInstall,
|
||||
|
||||
Reference in New Issue
Block a user