114 lines
4.5 KiB
Go
114 lines
4.5 KiB
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"browser.local/platform/domain"
|
|
"browser.local/platform/dto"
|
|
)
|
|
|
|
func TestRunControlAPIHelloHeartbeatWorkflow(t *testing.T) {
|
|
router := newTestRouter()
|
|
|
|
helloRecorder := performJSON(t, router, http.MethodPost, "/api/v1/run/control/hello", validRunControlHelloRequest())
|
|
assertStatus(t, helloRecorder, http.StatusOK)
|
|
hello := decodeBody[dto.RunControlHelloResponse](t, helloRecorder)
|
|
if !hello.Accepted || hello.SessionToken == "" || hello.RunEndpointID != "run-local" {
|
|
t.Fatalf("expected accepted hello response, got %+v", hello)
|
|
}
|
|
|
|
endpoint := getJSON[dto.RunEndpointResponse](t, router, "/api/v1/run/endpoints/run-local")
|
|
if endpoint.Status != domain.RunEndpointStatusOnline || len(endpoint.Capabilities) != 2 {
|
|
t.Fatalf("expected registered endpoint metadata, got %+v", endpoint)
|
|
}
|
|
|
|
heartbeatRecorder := performJSON(t, router, http.MethodPost, "/api/v1/run/control/heartbeat", dto.RunControlHeartbeatRequest{
|
|
RunEndpointID: "run-local",
|
|
SessionToken: hello.SessionToken,
|
|
Version: "0.1.1",
|
|
Status: domain.RunEndpointStatusOnline,
|
|
CapabilityFingerprint: "cap-v2",
|
|
Capacity: dto.RunCapacityResponse{
|
|
MaxJobs: 4,
|
|
RunningJobs: 1,
|
|
},
|
|
})
|
|
assertStatus(t, heartbeatRecorder, http.StatusOK)
|
|
heartbeat := decodeBody[dto.RunControlHeartbeatResponse](t, heartbeatRecorder)
|
|
if !heartbeat.Accepted || !heartbeat.RefreshCapabilities || heartbeat.NextHeartbeatSeconds <= 0 {
|
|
t.Fatalf("expected accepted heartbeat with refresh, got %+v", heartbeat)
|
|
}
|
|
}
|
|
|
|
func TestRunControlAPIReRegistrationRotatesToken(t *testing.T) {
|
|
router := newTestRouter()
|
|
first := decodeBody[dto.RunControlHelloResponse](t, performRunControlHello(t, router, validRunControlHelloRequest()))
|
|
|
|
request := validRunControlHelloRequest()
|
|
request.Version = "0.2.0"
|
|
second := decodeBody[dto.RunControlHelloResponse](t, performRunControlHello(t, router, request))
|
|
if second.SessionToken == first.SessionToken {
|
|
t.Fatalf("expected new session token after re-registration, got %q", second.SessionToken)
|
|
}
|
|
}
|
|
|
|
func TestRunControlAPIErrors(t *testing.T) {
|
|
router := newTestRouter()
|
|
|
|
invalid := validRunControlHelloRequest()
|
|
invalid.RegistrationToken = ""
|
|
invalid.Capacity.RunningJobs = 8
|
|
invalid.Capacity.MaxJobs = 4
|
|
invalidHello := performJSON(t, router, http.MethodPost, "/api/v1/run/control/hello", invalid)
|
|
assertErrorResponse(t, invalidHello, http.StatusBadRequest, errorCodeValidation)
|
|
|
|
hello := decodeBody[dto.RunControlHelloResponse](t, performRunControlHello(t, router, validRunControlHelloRequest()))
|
|
invalidHeartbeat := performJSON(t, router, http.MethodPost, "/api/v1/run/control/heartbeat", dto.RunControlHeartbeatRequest{
|
|
RunEndpointID: "run-local",
|
|
SessionToken: "stale-token",
|
|
Version: "0.1.1",
|
|
Status: domain.RunEndpointStatusOnline,
|
|
CapabilityFingerprint: "cap-v1",
|
|
Capacity: dto.RunCapacityResponse{MaxJobs: 4},
|
|
})
|
|
assertErrorResponse(t, invalidHeartbeat, http.StatusBadRequest, errorCodeValidation)
|
|
|
|
validHeartbeat := performJSON(t, router, http.MethodPost, "/api/v1/run/control/heartbeat", dto.RunControlHeartbeatRequest{
|
|
RunEndpointID: "run-local",
|
|
SessionToken: hello.SessionToken,
|
|
Version: "0.1.1",
|
|
Status: domain.RunEndpointStatusOnline,
|
|
CapabilityFingerprint: "cap-v1",
|
|
Capacity: dto.RunCapacityResponse{MaxJobs: 4},
|
|
})
|
|
assertStatus(t, validHeartbeat, http.StatusOK)
|
|
|
|
methodFailure := performRaw(t, router, http.MethodGet, "/api/v1/run/control/hello", "")
|
|
assertErrorResponse(t, methodFailure, http.StatusMethodNotAllowed, errorCodeMethodNotAllowed)
|
|
}
|
|
|
|
func performRunControlHello(t *testing.T, router http.Handler, request dto.RunControlHelloRequest) *httptest.ResponseRecorder {
|
|
t.Helper()
|
|
recorder := performJSON(t, router, http.MethodPost, "/api/v1/run/control/hello", request)
|
|
assertStatus(t, recorder, http.StatusOK)
|
|
return recorder
|
|
}
|
|
|
|
func validRunControlHelloRequest() dto.RunControlHelloRequest {
|
|
return dto.RunControlHelloRequest{
|
|
RegistrationToken: "registration-token",
|
|
RunEndpointID: "run-local",
|
|
DisplayName: "Local Run",
|
|
Version: "0.1.0",
|
|
Status: domain.RunEndpointStatusOnline,
|
|
Platform: "darwin/arm64",
|
|
CapabilityReport: dto.RunCapabilityReport{
|
|
Capabilities: []string{"control.hello", "control.heartbeat"},
|
|
Fingerprint: "cap-v1",
|
|
},
|
|
Capacity: dto.RunCapacityResponse{MaxJobs: 4},
|
|
}
|
|
}
|