mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
- module github.com/R0m1k3/Loki, cmd/loki, internal/loki (package loki) - LOKI_HOME, LOKI_MODEL_DIRS, LOKI_SERVICE, LOKI_DL_CONNS ; /etc/loki ; units loki-engine / loki-ui ; binaire et aide CLI - updateRepo pointe sur R0m1k3/Loki (l'auto-update ne tirera plus les binaires AJEAN amont) Conservé à l'identique : le domaine ajean.link (service de tunnel amont), les littéraux de migration 0.7.x (migrate_07.go), RELEASE_NOTES.md et LICENSE (historique et licence de l'amont). go build/vet/test : verts.
121 lines
3.9 KiB
Go
121 lines
3.9 KiB
Go
package loki
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestShardInfo(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
idx, total int
|
|
ok bool
|
|
}{
|
|
{"Laguna-S-2.1-UD-IQ4_XS-00001-of-00003.gguf", 1, 3, true},
|
|
{"Laguna-S-2.1-UD-IQ4_XS-00002-of-00003.gguf", 2, 3, true},
|
|
{"m-01-of-03.gguf", 1, 3, true},
|
|
{"Qwen2.5-7B-Instruct-Q4_K_M.gguf", 0, 0, false},
|
|
{"bidon-00004-of-00003.gguf", 0, 0, false}, // numérotation incohérente
|
|
{"pas-un-gguf-00001-of-00002.bin", 0, 0, false},
|
|
}
|
|
for _, c := range cases {
|
|
idx, total, ok := shardInfo(c.name)
|
|
if idx != c.idx || total != c.total || ok != c.ok {
|
|
t.Errorf("shardInfo(%q) = %d,%d,%v ; attendu %d,%d,%v", c.name, idx, total, ok, c.idx, c.total, c.ok)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestShardFamilyGardeLaLargeur(t *testing.T) {
|
|
got := shardFamily("Laguna-00002-of-00003.gguf")
|
|
want := []string{
|
|
"Laguna-00001-of-00003.gguf",
|
|
"Laguna-00002-of-00003.gguf",
|
|
"Laguna-00003-of-00003.gguf",
|
|
}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("famille = %v ; attendu %v", got, want)
|
|
}
|
|
if solo := shardFamily("simple.gguf"); !reflect.DeepEqual(solo, []string{"simple.gguf"}) {
|
|
t.Fatalf("fichier simple = %v", solo)
|
|
}
|
|
}
|
|
|
|
// Le lien collé peut désigner n'importe quelle tranche : on remonte toujours à la
|
|
// première, et on ne réécrit QUE le nom de fichier final (le même libellé peut
|
|
// apparaître plus haut dans le chemin du dépôt).
|
|
func TestShardURLSet(t *testing.T) {
|
|
base := "https://huggingface.co/unsloth/Laguna-S-2.1-GGUF/resolve/main/UD-IQ4_XS/"
|
|
in := base + "Laguna-UD-IQ4_XS-00002-of-00003.gguf"
|
|
urls, names := shardURLSet(in, "Laguna-UD-IQ4_XS-00002-of-00003.gguf")
|
|
if len(urls) != 3 || len(names) != 3 {
|
|
t.Fatalf("attendu 3 tranches, got %d/%d", len(urls), len(names))
|
|
}
|
|
if names[0] != "Laguna-UD-IQ4_XS-00001-of-00003.gguf" {
|
|
t.Fatalf("première tranche = %q", names[0])
|
|
}
|
|
if urls[0] != base+"Laguna-UD-IQ4_XS-00001-of-00003.gguf" {
|
|
t.Fatalf("URL de la première tranche = %q", urls[0])
|
|
}
|
|
if urls[2] != base+"Laguna-UD-IQ4_XS-00003-of-00003.gguf" {
|
|
t.Fatalf("URL de la dernière tranche = %q", urls[2])
|
|
}
|
|
// Fichier simple : une seule URL, inchangée.
|
|
u, n := shardURLSet(base+"m.gguf", "m.gguf")
|
|
if len(u) != 1 || u[0] != base+"m.gguf" || n[0] != "m.gguf" {
|
|
t.Fatalf("fichier simple mal traité : %v %v", u, n)
|
|
}
|
|
}
|
|
|
|
func TestShardFamilyTailleEtManquantes(t *testing.T) {
|
|
dir := t.TempDir()
|
|
write := func(n string, size int) {
|
|
if err := os.WriteFile(filepath.Join(dir, n), make([]byte, size), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
write("m-00001-of-00003.gguf", 100)
|
|
write("m-00003-of-00003.gguf", 300)
|
|
|
|
if got := shardFamilySize(dir, "m-00001-of-00003.gguf"); got != 400 {
|
|
t.Fatalf("taille de la famille = %d ; attendu 400", got)
|
|
}
|
|
missing := shardFamilyMissing(dir, "m-00001-of-00003.gguf")
|
|
if !reflect.DeepEqual(missing, []string{"m-00002-of-00003.gguf"}) {
|
|
t.Fatalf("tranches manquantes = %v", missing)
|
|
}
|
|
write("m-00002-of-00003.gguf", 200)
|
|
if m := shardFamilyMissing(dir, "m-00001-of-00003.gguf"); len(m) != 0 {
|
|
t.Fatalf("famille complète signalée incomplète : %v", m)
|
|
}
|
|
}
|
|
|
|
// Supprimer un modèle découpé doit emporter TOUTES ses tranches, sinon des
|
|
// dizaines de Go restent sur le disque sans que rien ne sache plus les effacer.
|
|
func TestDeleteModelFileEmporteLesTranches(t *testing.T) {
|
|
testHome(t)
|
|
dir := modelsDir()
|
|
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
names := []string{"m-00001-of-00002.gguf", "m-00002-of-00002.gguf", "autre.gguf"}
|
|
for _, n := range names {
|
|
if err := os.WriteFile(filepath.Join(dir, n), []byte("x"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if err := deleteModelFile("m-00001-of-00002.gguf"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, n := range names[:2] {
|
|
if _, err := os.Stat(filepath.Join(dir, n)); !os.IsNotExist(err) {
|
|
t.Fatalf("tranche %s non supprimée", n)
|
|
}
|
|
}
|
|
if _, err := os.Stat(filepath.Join(dir, "autre.gguf")); err != nil {
|
|
t.Fatal("un modèle sans rapport a été supprimé")
|
|
}
|
|
}
|