mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-22 14:38:12 +02:00
Lot 8 : téléchargements de modèles tenus par la façade (LOKI_DOWNLOADS=rust)
La façade Rust mène les téléchargements de .gguf quand LOKI_DOWNLOADS=rust (expérimental ; le Go reste le défaut) : sonde, lancement, suivi, annulation, avec les mêmes contrats et la même mécanique que le Go (tranches rapatriées en entier, plages d'octets parallèles, reprise, place disque vérifiée sur le total, jeton réservé aux hôtes Hugging Face, refus traduits, .part vidés au démarrage). Côté Go : facade_downloads.go remet ces routes à la façade quand elles arrivent par le tunnel du relais, et le Go ne vide plus les .part qu'elle mène. Parité : journal des fonctions pures tiré du Go (parity_dl_test.go) et rejoué en Rust ; téléchargements de bout en bout contre un faux Hugging Face (tests/downloads.rs). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
This commit is contained in:
20 files changed
+2820
-17
No files matched your search
@@ -5,6 +5,8 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -303,3 +305,76 @@ func TestFacadeReglageQuiGardeLaConversation(t *testing.T) {
|
||||
t.Fatalf("sans la variable : %s", w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
// LOKI_DOWNLOADS=rust : les routes des téléchargements de modèles partent à la
|
||||
// façade (avec ou sans LOKI_CHAT), les autres routes des modèles restent ici ;
|
||||
// sans la variable, rien ne change. Façade muette : erreur qui le dit.
|
||||
func TestFacadeRelaieLesTelechargements(t *testing.T) {
|
||||
testHome(t)
|
||||
f := demarrerFacade(t)
|
||||
t.Setenv(facadeChatEnv, "")
|
||||
t.Setenv(facadeDownloadsEnv, "rust")
|
||||
local := func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "go") }
|
||||
|
||||
for _, p := range []string{"/api/models/download", "/api/models/download/probe",
|
||||
"/api/models/download/status", "/api/models/download/cancel"} {
|
||||
w := httptest.NewRecorder()
|
||||
withFacadeChat(p, local)(w, httptest.NewRequest("POST", p, strings.NewReader(`{"url":"u"}`)))
|
||||
if w.Body.String() != f.reply {
|
||||
t.Fatalf("%s : réponse %q", p, w.Body.String())
|
||||
}
|
||||
}
|
||||
if got := f.recu(); len(got) != 4 || got[0] != `POST /api/models/download jeton {"url":"u"}` {
|
||||
t.Fatalf("reçu par la façade : %v", got)
|
||||
}
|
||||
// Le chat, lui, reste ici (LOKI_CHAT absent), et les autres routes des
|
||||
// modèles aussi.
|
||||
for _, p := range []string{"/api/chat/send", "/api/models", "/api/models/delete"} {
|
||||
w := httptest.NewRecorder()
|
||||
withFacadeChat(p, local)(w, httptest.NewRequest("POST", p, nil))
|
||||
if w.Body.String() != "go" {
|
||||
t.Fatalf("%s relayé : %q", p, w.Body.String())
|
||||
}
|
||||
}
|
||||
// Façade injoignable : 502 qui nomme ce qui manque.
|
||||
f.srv.Close()
|
||||
w := httptest.NewRecorder()
|
||||
withFacadeChat("/api/models/download/status", local)(w, httptest.NewRequest("GET", "/api/models/download/status", nil))
|
||||
if w.Code != http.StatusBadGateway || !strings.Contains(w.Body.String(), "téléchargements indisponibles : ") {
|
||||
t.Fatalf("façade muette : %d %s", w.Code, w.Body.String())
|
||||
}
|
||||
// Sans LOKI_DOWNLOADS=rust : tout reste ici.
|
||||
t.Setenv(facadeDownloadsEnv, "")
|
||||
w = httptest.NewRecorder()
|
||||
withFacadeChat("/api/models/download", local)(w, httptest.NewRequest("POST", "/api/models/download", nil))
|
||||
if w.Body.String() != "go" {
|
||||
t.Fatalf("relayé sans la variable : %q", w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
// Les .part orphelins ne sont plus vidés par ce Go quand la façade tient les
|
||||
// téléchargements : elle les vide à son démarrage, et un Go relancé seul
|
||||
// effacerait celui qu'elle mène.
|
||||
func TestFacadeTelechargementsGardeLesPart(t *testing.T) {
|
||||
home := testHome(t)
|
||||
dir := filepath.Join(home, "models")
|
||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
part := filepath.Join(dir, "m.gguf.part")
|
||||
if err := os.WriteFile(part, []byte("x"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv(internalTokenEnv, jetonTest)
|
||||
t.Setenv(facadeAddrEnv, "127.0.0.1:1")
|
||||
t.Setenv(facadeDownloadsEnv, "rust")
|
||||
cleanStartupPartFiles()
|
||||
if _, err := os.Stat(part); err != nil {
|
||||
t.Fatalf(".part effacé alors que la façade tient les téléchargements : %v", err)
|
||||
}
|
||||
t.Setenv(facadeDownloadsEnv, "")
|
||||
cleanStartupPartFiles()
|
||||
if _, err := os.Stat(part); !os.IsNotExist(err) {
|
||||
t.Fatalf(".part orphelin gardé : %v", err)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user