118 lines
3.8 KiB
Go
118 lines
3.8 KiB
Go
package customer
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"sync/atomic"
|
|
"testing"
|
|
)
|
|
|
|
func TestEnsureImagePullsMissingImage(t *testing.T) {
|
|
var present atomic.Bool
|
|
var pulls atomic.Int32
|
|
image := "registry.example.com/neuralhunt/worker:v4.1"
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch {
|
|
case r.Method == http.MethodGet && strings.HasPrefix(r.URL.Path, "/images/") && strings.HasSuffix(r.URL.Path, "/json"):
|
|
if !present.Load() {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_, _ = w.Write([]byte(`{"Id":"sha256:test"}`))
|
|
case r.Method == http.MethodPost && r.URL.Path == "/images/create":
|
|
if got := r.URL.Query().Get("fromImage"); got != image {
|
|
t.Fatalf("fromImage=%q want %q", got, image)
|
|
}
|
|
pulls.Add(1)
|
|
present.Store(true)
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_, _ = w.Write([]byte("{\"status\":\"Pull complete\"}\n"))
|
|
default:
|
|
http.Error(w, "unexpected request", http.StatusBadRequest)
|
|
}
|
|
}))
|
|
defer ts.Close()
|
|
|
|
d := &DockerClient{hc: ts.Client(), base: ts.URL}
|
|
if err := d.EnsureImage(context.Background(), image, true, ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if pulls.Load() != 1 {
|
|
t.Fatalf("pulls=%d want 1", pulls.Load())
|
|
}
|
|
if err := d.EnsureImage(context.Background(), image, true, ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if pulls.Load() != 1 {
|
|
t.Fatalf("second ensure pulled again: pulls=%d", pulls.Load())
|
|
}
|
|
}
|
|
|
|
func TestEnsureImageCanRequirePrePulledImage(t *testing.T) {
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
http.NotFound(w, r)
|
|
}))
|
|
defer ts.Close()
|
|
d := &DockerClient{hc: ts.Client(), base: ts.URL}
|
|
if err := d.EnsureImage(context.Background(), "neuralhunt-worker:local", false, ""); err == nil || !strings.Contains(err.Error(), "CS_WORKER_AUTO_PULL") {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRegistryAuthHeader(t *testing.T) {
|
|
h, err := RegistryAuthHeader("robot", "token", "registry.example.com")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if h == "" {
|
|
t.Fatal("expected registry auth header")
|
|
}
|
|
if _, err := RegistryAuthHeader("robot", "", "registry.example.com"); err == nil {
|
|
t.Fatal("incomplete registry credentials should fail")
|
|
}
|
|
}
|
|
|
|
func TestCreateWorkerUsesImageEntrypointByDefault(t *testing.T) {
|
|
var got map[string]any
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/containers/create" {
|
|
http.Error(w, "unexpected", 400)
|
|
return
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&got); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_, _ = w.Write([]byte(`{"Id":"container-1"}`))
|
|
}))
|
|
defer ts.Close()
|
|
d := &DockerClient{hc: ts.Client(), base: ts.URL}
|
|
|
|
cfg := WorkerContainerConfig{Image: "neuralhunt-worker:local", Network: "nh", GameURL: "http://app:8080", RegisterURL: "http://cs:8092/internal/workers/register", WorkerID: "wrk_1", RegisterToken: "secret", TaskID: "task_1", BeaconPath: "auto", Volume: "vol_1", Name: "worker-1"}
|
|
if _, err := d.CreateWorker(context.Background(), cfg); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, exists := got["Entrypoint"]; exists {
|
|
t.Fatalf("dedicated worker image should keep its image ENTRYPOINT: %#v", got["Entrypoint"])
|
|
}
|
|
host, _ := got["HostConfig"].(map[string]any)
|
|
rp, _ := host["RestartPolicy"].(map[string]any)
|
|
if rp["Name"] != "unless-stopped" {
|
|
t.Fatalf("worker restart policy=%#v want unless-stopped", rp)
|
|
}
|
|
|
|
cfg.Name = "worker-2"
|
|
cfg.Entrypoint = "/app/neuralhunt-client"
|
|
if _, err := d.CreateWorker(context.Background(), cfg); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, exists := got["Entrypoint"]; !exists {
|
|
t.Fatal("compatibility Entrypoint override was not sent")
|
|
}
|
|
}
|