internal/autogen/flagtable_test.go
Rama main · réplica de lectura del repositorio original.
package autogen
import (
"strings"
"testing"
"github.com/quartermaster-labs/quartermaster/internal/config"
)
// intPtr / floatPtr keep the kitchen-sink override below readable.
func intPtr(i int) *int { return &i }
func floatPtr(f float64) *float64 { return &f }
// Every flag the llama emitter can produce must be in the table. The fixture is
// a kitchen-sink override that turns on every optional flag, so a new emitter
// flag fails here until the table knows it (and therefore until custom-args
// suppression can handle it).
func TestFlagTable_CoversEveryEmittedFlag(t *testing.T) {
yes := true
s := Settings{
ServerExe: "llama-server",
Threads: 8,
TtlSec: 600,
SlotCache: SlotCacheSettings{Enable: true, Path: "C:/cache/slotkv"},
}
meta := Metadata{
Architecture: "qwen3moe",
BlockCount: 32,
IsMoE: true,
IsMTP: true,
FullAttnInterval: 4,
}
row := GgufRow{
FullPath: "/models/foo.gguf",
MmprojPath: "/models/mmproj.gguf",
DraftPath: "/models/mtp-draft.gguf",
DraftKind: "mtp",
}
prof := profile{
Name: "foo",
Target: 24,
Overhead: 2,
Ctx: 8192,
IsLong: true,
TensorSplit: []float64{2, 1},
Vision: true,
CpuMmproj: true,
ReasoningFmt: "deepseek",
}
ov := &Override{
Mmap: "off", DirectIo: true, // --load-mode dio
FlashAttn: "on", Threads: 8, Parallel: 4, Ub: 512,
KvInRam: true, KvK: "q8_0", KvV: "q8_0", KvKDraft: "q8_0", KvVDraft: "q8_0",
Spec: "draft-mtp+ngram-mod", SpecDraftNMax: 3, SpecDraftNMin: 1, SpecDefault: true,
SpecNgramSizeN: 4, SpecNgramSizeM: 8, SpecNgramMinHits: 2,
ReasoningFmt: "deepseek", ReasoningBudget: 4096,
CtxCheckpoints: intPtr(6), CheckpointMinStep: 2048,
Dry: &yes, DryMultiplier: 0.9, DryBase: 1.5, DryAllowedLength: 4,
Temp: floatPtr(0.7), TopK: intPtr(20), TopP: floatPtr(0.95), MinP: floatPtr(0.05), PresencePenalty: floatPtr(0.2),
ThreadsBatch: 8, Prio: 1, NoOpOffload: true, NoRepack: true, CacheReuse: 64,
CacheRamMB: 2048, LogVerbosity: 2, CacheIdleSlots: "on", SwaFull: true,
ContextShift: "on", SlotPromptSimilarity: 0.5, RopeScaling: "yarn", RopeScale: 2,
RopeFreqBase: 1e6, YarnOrigCtx: 4096, SplitMode: "layer", TensorSplit: "3,1",
OverrideTensor: "exps=CPU", ChatTemplateFile: "/models/tmpl.jinja",
MmprojFile: "/models/mmproj.gguf", SlotCache: &yes,
}
lines := buildCmdLines(s, meta, row, prof, 8192, 99, 8, "q8_0", "q8_0", true, ov)
argv, err := config.SanitizeCommand(strings.Join(lines, " "))
if err != nil {
t.Fatalf("generated command does not split: %v", err)
}
for i := 0; i < len(argv); i++ {
tok := argv[i]
if !strings.HasPrefix(tok, "-") {
continue
}
name, _, inline := SplitFlagToken(tok)
def, ok := LookupFlag(name)
if !ok {
t.Errorf("emitted flag %q is missing from llamaFlagTable (add it there and to the knob-clearing switch)", tok)
continue
}
if def.Value && !inline {
i++ // skip the value, which may itself start with '-' (negative samplers)
}
}
}
// The table must not contain a spelling twice, and every alias must resolve
// back to its own entry.
func TestFlagTable_NoDuplicateSpellings(t *testing.T) {
seen := map[string]string{}
for _, d := range llamaFlagTable {
for _, name := range append([]string{d.Name}, d.Aliases...) {
if prev, dup := seen[name]; dup {
t.Errorf("flag %q appears in both %q and %q", name, prev, d.Name)
}
seen[name] = d.Name
}
}
for _, d := range llamaFlagTable {
for _, name := range append([]string{d.Name}, d.Aliases...) {
got, ok := LookupFlag(name)
if !ok || got.Name != d.Name {
t.Errorf("LookupFlag(%q) = %q/%v, want %q", name, got.Name, ok, d.Name)
}
}
}
}
func TestSplitFlagToken(t *testing.T) {
cases := []struct {
in string
name string
value string
hasValue bool
}{
{"-c", "-c", "", false},
{"--ctx-size", "--ctx-size", "", false},
{"--ctx-size=32768", "--ctx-size", "32768", true},
{"-c=32768", "-c=32768", "", false}, // short '=' form is not a thing
{"q8_0", "q8_0", "", false},
}
for _, c := range cases {
name, value, has := SplitFlagToken(c.in)
if name != c.name || value != c.value || has != c.hasValue {
t.Errorf("SplitFlagToken(%q) = %q/%q/%v, want %q/%q/%v", c.in, name, value, has, c.name, c.value, c.hasValue)
}
}
}
func TestOwnedKnobs(t *testing.T) {
tokens := []string{"--ctx-size", "32768", "--temp", "-0.5", "-cram", "2048", "--foo", "bar", "-m", "/x.gguf"}
owned := OwnedKnobs(tokens)
for _, want := range []string{"ctx", "temp", "cacheRam", "model"} {
if !owned[want] {
t.Errorf("knob %q should be owned (owned=%v)", want, owned)
}
}
if len(owned) != 4 {
t.Errorf("owned = %v, want exactly ctx/temp/cacheRam/model", owned)
}
}
func TestClearOwnedFields(t *testing.T) {
ov := &Override{
Ctx: 8192, Mmap: "off", Mlock: true, DirectIo: true,
Temp: floatPtr(0.5), TopK: intPtr(20), CacheRamMB: 4096, LogVerbosity: 3,
PreserveThinking: boolPtr(false), CtxCheckpoints: intPtr(6),
}
cleared := ClearOwnedFields(ov, map[string]bool{"ctx": true, "loadMode": true, "cacheRam": true, "temp": true})
if ov.Ctx != 0 || ov.Mmap != "" || ov.Mlock || ov.DirectIo || ov.CacheRamMB != 0 || ov.Temp != nil {
t.Errorf("owned fields not cleared: %+v", ov)
}
if ov.TopK == nil || *ov.TopK != 20 || ov.LogVerbosity != 3 || ov.PreserveThinking == nil || ov.CtxCheckpoints == nil {
t.Errorf("unowned fields must survive: %+v", ov)
}
want := map[string]bool{"ctx": true, "loadMode": true, "cacheRam": true, "temp": true}
if len(cleared) != len(want) {
t.Fatalf("cleared = %v, want %v", cleared, want)
}
for _, k := range cleared {
if !want[k] {
t.Errorf("unexpected cleared knob %q", k)
}
}
}
func boolPtr(b bool) *bool { return &b }