135 lines
4.0 KiB
Go
135 lines
4.0 KiB
Go
package main
|
|
|
|
import (
|
|
"net/http/httptest"
|
|
"testing"
|
|
"unsafe"
|
|
)
|
|
|
|
func testEngine(pipeline uintptr, freed *int) *engine {
|
|
return &engine{
|
|
pipeline: pipeline,
|
|
backend: "test GPU",
|
|
caps: capCoarse | cap512 | capTexture,
|
|
textured: true,
|
|
pipelineFree: func(uintptr) {
|
|
*freed++
|
|
},
|
|
}
|
|
}
|
|
|
|
func TestEngineUnloadRetainsRuntimeInfoAndReloads(t *testing.T) {
|
|
freed, loads := 0, 0
|
|
e := testEngine(41, &freed)
|
|
e.models.dino = "dino.gguf"
|
|
e.pipelineLoad = func(dino, flow, dec, slat, slatHR, shapeDec, shapeEnc, texDec, texFlow, texFlowHR string,
|
|
flags int32, err unsafe.Pointer, errLen int32) uintptr {
|
|
loads++
|
|
if dino != "dino.gguf" {
|
|
t.Fatalf("reload used dino path %q", dino)
|
|
}
|
|
return 42
|
|
}
|
|
e.pipelineBackend = func(uintptr) string { return "test GPU" }
|
|
e.pipelineCaps = func(uintptr) int32 { return capCoarse | cap512 | capTexture }
|
|
|
|
if !e.Unload() || freed != 1 {
|
|
t.Fatalf("Unload() = true with one free wanted; freed=%d", freed)
|
|
}
|
|
backend, caps, textured, loaded := e.Info()
|
|
if loaded || backend != "test GPU" || caps != capCoarse|cap512|capTexture || !textured {
|
|
t.Fatalf("Info() after unload = %q, %d, %v, %v", backend, caps, textured, loaded)
|
|
}
|
|
|
|
e.mu.Lock()
|
|
err := e.loadLocked()
|
|
e.mu.Unlock()
|
|
if err != nil || loads != 1 {
|
|
t.Fatalf("reload: err=%v loads=%d", err, loads)
|
|
}
|
|
_, _, _, loaded = e.Info()
|
|
if !loaded {
|
|
t.Fatal("pipeline is not marked loaded after reload")
|
|
}
|
|
}
|
|
|
|
func TestConfiguredCapsForLazyStartup(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
m engineModels
|
|
want int
|
|
}{
|
|
{"coarse", engineModels{}, capCoarse},
|
|
{"512", engineModels{slat: "slat", shapeDec: "shape"}, capCoarse | cap512},
|
|
{"1024 textured", engineModels{
|
|
slat: "slat", slatHR: "hr", shapeDec: "shape", shapeEnc: "shapeenc",
|
|
texDec: "texdec", texFlow: "texflow",
|
|
}, capCoarse | cap512 | cap1024 | capTexture},
|
|
{"texture missing encoder", engineModels{
|
|
slat: "slat", shapeDec: "shape", texDec: "texdec", texFlow: "texflow",
|
|
}, capCoarse | cap512},
|
|
{"incomplete fine", engineModels{slat: "slat", texDec: "texdec", texFlow: "texflow"}, capCoarse},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := configuredCaps(tt.m); got != tt.want {
|
|
t.Fatalf("configuredCaps() = %d, want %d", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIdlePolicyWaitsForQueuedWork(t *testing.T) {
|
|
freed := 0
|
|
e := testEngine(41, &freed)
|
|
s := &server{eng: e, jobs: map[string]*job{}, q: make(chan *job, 1), queued: 1}
|
|
|
|
if s.setUnloadIdle(true) {
|
|
t.Fatal("enabled idle policy unloaded with queued work")
|
|
}
|
|
if freed != 0 {
|
|
t.Fatalf("pipeline freed with queued work: %d", freed)
|
|
}
|
|
|
|
s.mu.Lock()
|
|
s.queued = 0
|
|
s.mu.Unlock()
|
|
if !s.unloadModelsIfIdle(nil) || freed != 1 {
|
|
t.Fatalf("idle unload failed; freed=%d", freed)
|
|
}
|
|
}
|
|
|
|
func TestParseExportOptions(t *testing.T) {
|
|
def := parseExportOptions(httptest.NewRequest("GET", "/api/glb/job", nil))
|
|
if def.componentFilter != 2 || def.printWrap || def.prepareKey() != "2" {
|
|
t.Fatalf("default export should preserve all components: %+v", def)
|
|
}
|
|
r := httptest.NewRequest("GET", "/api/glb/job?tex=1024&components=largest", nil)
|
|
o := parseExportOptions(r)
|
|
if o.textureSize != 1024 || o.componentFilter != 1 {
|
|
t.Fatalf("parseExportOptions() = %+v", o)
|
|
}
|
|
if o.prepareKey() != "1" || o.glbKey() != "1024-1" {
|
|
t.Fatalf("unexpected export cache keys: %q %q", o.prepareKey(), o.glbKey())
|
|
}
|
|
wrapped := parseExportOptions(httptest.NewRequest("GET",
|
|
"/api/glb/job?print=1&alpha=2.5&offset=0.1", nil))
|
|
if !wrapped.printWrap || wrapped.alphaRatio != 0.025 || wrapped.offsetRatio != 0.001 ||
|
|
wrapped.prepareKey() == def.prepareKey() {
|
|
t.Fatalf("print-wrap options were not parsed/cached independently: %+v", wrapped)
|
|
}
|
|
}
|
|
|
|
func TestKeepAllExportPreviewUsesOriginalMesh(t *testing.T) {
|
|
original := &meshData{NVerts: 3, NTris: 1}
|
|
j := &job{mesh: original}
|
|
s := &server{}
|
|
got, err := s.preparedExportMesh(j, exportOptions{textureSize: 2048, componentFilter: 2})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != original {
|
|
t.Fatal("keep-all export preview did not return the exact source mesh")
|
|
}
|
|
}
|