fix: music poll resilience + hostile-URL guard + embed dup-index (gadfly round 1)
- pollResult tolerates up to 5 CONSECUTIVE bad polls (transport blip, unparseable payload, task momentarily absent) instead of killing a multi-minute exclusive-GPU job on the first hiccup; only status=2, a failure run, or ctx deadline aborts - server-supplied result.File must be server-relative; combined with the upstreamPath dot-dot/scheme rejection this stops a hostile upstream from steering the follow-up GET at other proxy endpoints (test: ../../api/models/unload refused) - WithSteps(<=0) rejected; embed responses repeating an index rejected; musicFormatMIME now wraps speechMIME (one format table, wav32 normalized); poll interval is a test-shrinkable var (CI no longer burns 2s+ per music test); parens + comments per review Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
@@ -51,6 +51,10 @@ func aceStepStub(t *testing.T, mp3 []byte) (*httptest.Server, *atomic.Int32) {
|
||||
}
|
||||
|
||||
func TestMusicGenerate(t *testing.T) {
|
||||
old := musicPollInterval
|
||||
musicPollInterval = 5 * time.Millisecond
|
||||
defer func() { musicPollInterval = old }()
|
||||
|
||||
mp3 := []byte("ID3fakeaudio")
|
||||
srv, polls := aceStepStub(t, mp3)
|
||||
defer srv.Close()
|
||||
@@ -79,6 +83,10 @@ func TestMusicGenerate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMusicGenerateUpstreamFailure(t *testing.T) {
|
||||
old := musicPollInterval
|
||||
musicPollInterval = 5 * time.Millisecond
|
||||
defer func() { musicPollInterval = old }()
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/upstream/musicgen-acestep/release_task":
|
||||
@@ -222,3 +230,66 @@ func TestInstructedQuery(t *testing.T) {
|
||||
t.Errorf("InstructedQuery = %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMusicGenerateSurvivesTransientPollFailures(t *testing.T) {
|
||||
old := musicPollInterval
|
||||
musicPollInterval = 5 * time.Millisecond
|
||||
defer func() { musicPollInterval = old }()
|
||||
|
||||
mp3 := []byte("ID3fakeaudio")
|
||||
var polls atomic.Int32
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/upstream/musicgen-acestep/release_task":
|
||||
_, _ = w.Write([]byte(`{"data": {"task_id": "t-3"}}`))
|
||||
case "/upstream/musicgen-acestep/query_result":
|
||||
switch polls.Add(1) {
|
||||
case 1:
|
||||
w.WriteHeader(http.StatusBadGateway) // transient transport blip
|
||||
case 2:
|
||||
_, _ = w.Write([]byte(`{"data": []}`)) // task momentarily absent
|
||||
default:
|
||||
_, _ = w.Write([]byte(`{"data": [{"task_id": "t-3", "status": 1,
|
||||
"result": "{\"file\": \"/v1/audio?path=out.mp3\"}"}]}`))
|
||||
}
|
||||
case "/upstream/musicgen-acestep/v1/audio":
|
||||
w.Header().Set("Content-Type", "audio/mpeg")
|
||||
_, _ = w.Write(mp3)
|
||||
}
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
p := New(WithBaseURL(srv.URL), WithHTTPClient(srv.Client()))
|
||||
mm, _ := p.MusicModel("musicgen-acestep")
|
||||
res, err := mm.Generate(context.Background(), musicgen.Request{Prompt: "p"})
|
||||
if err != nil {
|
||||
t.Fatalf("Generate should survive 2 transient failures: %v", err)
|
||||
}
|
||||
if len(res.Audio.Data) == 0 {
|
||||
t.Fatal("no audio")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMusicGenerateRejectsHostileFileURL(t *testing.T) {
|
||||
old := musicPollInterval
|
||||
musicPollInterval = 5 * time.Millisecond
|
||||
defer func() { musicPollInterval = old }()
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/upstream/musicgen-acestep/release_task":
|
||||
_, _ = w.Write([]byte(`{"data": {"task_id": "t-4"}}`))
|
||||
case "/upstream/musicgen-acestep/query_result":
|
||||
_, _ = w.Write([]byte(`{"data": [{"task_id": "t-4", "status": 1,
|
||||
"result": "{\"file\": \"/v1/audio?path=../../api/models/unload\"}"}]}`))
|
||||
}
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
p := New(WithBaseURL(srv.URL), WithHTTPClient(srv.Client()))
|
||||
mm, _ := p.MusicModel("musicgen-acestep")
|
||||
_, err := mm.Generate(context.Background(), musicgen.Request{Prompt: "p"})
|
||||
if err == nil {
|
||||
t.Fatal("dot-dot result file URL accepted")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user