admin: submissions page, download endpoint, uploads search by app_id

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
tao.chen
2026-07-14 13:45:11 +08:00
co-authored by Claude
parent 573397dbb4
commit 25f93dfb59
10 changed files with 683 additions and 26 deletions
+48 -6
View File
@@ -18,7 +18,7 @@ import (
"spark-mcp-go/internal/uploads"
)
func newTestAdminUploads(t *testing.T) (*gin.Engine, *storage.UploadRepo, *audit.Repo, *uploads.Store) {
func newTestAdminUploads(t *testing.T) (*gin.Engine, *storage.UploadRepo, *storage.SubmissionRepo, *audit.Repo, *uploads.Store) {
t.Helper()
db, err := storage.Open(":memory:")
if err != nil {
@@ -32,12 +32,12 @@ func newTestAdminUploads(t *testing.T) (*gin.Engine, *storage.UploadRepo, *audit
}
r := gin.New()
Mount(r, db.Clusters(), db.Uploads(), audit.NewRepo(db), &uploadStore, []string{"good-token"})
return r, db.Uploads(), audit.NewRepo(db), &uploadStore
Mount(r, db.Clusters(), db.Uploads(), db.Submissions(), audit.NewRepo(db), &uploadStore, []string{"good-token"})
return r, db.Uploads(), db.Submissions(), audit.NewRepo(db), &uploadStore
}
func TestUploadsWeb_RequiresAuth(t *testing.T) {
r, _, _, _ := newTestAdminUploads(t)
r, _, _, _, _ := newTestAdminUploads(t)
w := doReq(t, r, "GET", "/admin/uploads", "", nil)
if w.Code != http.StatusUnauthorized {
@@ -62,7 +62,7 @@ func TestUploadsWeb_RequiresAuth(t *testing.T) {
}
func TestListUploads(t *testing.T) {
r, repo, _, _ := newTestAdminUploads(t)
r, repo, _, _, _ := newTestAdminUploads(t)
ctx := context.Background()
uploadedAt := time.Unix(0, time.Now().UnixNano())
@@ -98,7 +98,7 @@ func TestListUploads(t *testing.T) {
}
func TestDeleteUpload(t *testing.T) {
r, repo, auditRepo, store := newTestAdminUploads(t)
r, repo, _, auditRepo, store := newTestAdminUploads(t)
ctx := context.Background()
id := "00000000000000000000000000000003"
@@ -152,3 +152,45 @@ func TestDeleteUpload(t *testing.T) {
t.Errorf("missing upload.delete audit entry")
}
}
func TestListUploads_SearchByAppID(t *testing.T) {
r, uploadRepo, subRepo, _, _ := newTestAdminUploads(t)
ctx := context.Background()
uploadedAt := time.Unix(0, time.Now().UnixNano())
if err := uploadRepo.Create(ctx, "00000000000000000000000000000010", "gamma.py", 10, "deadbeef", uploadedAt); err != nil {
t.Fatalf("create upload: %v", err)
}
if err := uploadRepo.Create(ctx, "00000000000000000000000000000011", "delta.py", 20, "cafebabe", uploadedAt.Add(time.Second)); err != nil {
t.Fatalf("create upload: %v", err)
}
// Only gamma.py has an associated submission; searching by app_id should
// still return it even though the filename doesn't match the query.
if err := subRepo.Create(ctx, storage.Submission{
FileID: "00000000000000000000000000000010",
AppID: "application_gamma_0001",
TrackingURL: "http://gamma",
ClusterID: "c1",
ExitCode: 0,
DurationMS: 100,
SubmittedAt: time.Now(),
}); err != nil {
t.Fatalf("create submission: %v", err)
}
w := doReq(t, r, "GET", "/admin/uploads/api?search=application_gamma", "good-token", nil)
if w.Code != http.StatusOK {
t.Fatalf("search by app_id: got status %d: %s", w.Code, w.Body.String())
}
var list []map[string]any
if err := json.Unmarshal(w.Body.Bytes(), &list); err != nil {
t.Fatalf("unmarshal search: %v", err)
}
if len(list) != 1 {
t.Errorf("search by app_id result: got %d, want 1", len(list))
}
if len(list) > 0 && list[0]["file_id"] != "00000000000000000000000000000010" {
t.Errorf("file_id=%v, want upload 10", list[0]["file_id"])
}
}