Files
hpc/cmd/server/integration_file_test.go
dailz b9b2f0d9b4 feat(testutil): add MockSlurm, MockMinIO, TestEnv and 37 integration tests
- mockminio: in-memory ObjectStorage with all 11 methods, thread-safe, SHA256 ETag, Range support
- mockslurm: httptest server with 11 Slurm REST API endpoints, job eviction from active to history queue
- testenv: one-line test environment factory (SQLite + MockSlurm + MockMinIO + all stores/services/handlers + httptest server)
- integration tests: 37 tests covering Jobs(5), Cluster(5), App(6), Upload(5), File(4), Folder(4), Task(4), E2E(1)
- no external dependencies, no existing files modified
2026-04-16 13:23:27 +08:00

171 lines
4.2 KiB
Go

package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"testing"
"gcy_hpc_server/internal/model"
"gcy_hpc_server/internal/testutil/testenv"
)
// fileAPIResp mirrors server.APIResponse for file integration tests.
type fileAPIResp struct {
Success bool `json:"success"`
Data json.RawMessage `json:"data,omitempty"`
Error string `json:"error,omitempty"`
}
// fileDecode parses an HTTP response body into fileAPIResp.
func fileDecode(t *testing.T, body io.Reader) fileAPIResp {
t.Helper()
data, err := io.ReadAll(body)
if err != nil {
t.Fatalf("fileDecode: read body: %v", err)
}
var r fileAPIResp
if err := json.Unmarshal(data, &r); err != nil {
t.Fatalf("fileDecode: unmarshal: %v (body: %s)", err, string(data))
}
return r
}
func TestIntegration_File_List(t *testing.T) {
env := testenv.NewTestEnv(t)
// Upload a file so the list is non-empty.
env.UploadTestData("list_test.txt", []byte("hello list"))
resp := env.DoRequest("GET", "/api/v1/files", nil)
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Fatalf("expected 200, got %d", resp.StatusCode)
}
r := fileDecode(t, resp.Body)
if !r.Success {
t.Fatalf("response not success: %s", r.Error)
}
var listResp model.ListFilesResponse
if err := json.Unmarshal(r.Data, &listResp); err != nil {
t.Fatalf("unmarshal list response: %v", err)
}
if len(listResp.Files) == 0 {
t.Fatal("expected at least 1 file in list, got 0")
}
found := false
for _, f := range listResp.Files {
if f.Name == "list_test.txt" {
found = true
break
}
}
if !found {
t.Fatal("expected to find list_test.txt in file list")
}
if listResp.Total < 1 {
t.Fatalf("expected total >= 1, got %d", listResp.Total)
}
if listResp.Page < 1 {
t.Fatalf("expected page >= 1, got %d", listResp.Page)
}
}
func TestIntegration_File_Get(t *testing.T) {
env := testenv.NewTestEnv(t)
fileID, _ := env.UploadTestData("get_test.txt", []byte("hello get"))
resp := env.DoRequest("GET", fmt.Sprintf("/api/v1/files/%d", fileID), nil)
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Fatalf("expected 200, got %d", resp.StatusCode)
}
r := fileDecode(t, resp.Body)
if !r.Success {
t.Fatalf("response not success: %s", r.Error)
}
var fileResp model.FileResponse
if err := json.Unmarshal(r.Data, &fileResp); err != nil {
t.Fatalf("unmarshal file response: %v", err)
}
if fileResp.ID != fileID {
t.Fatalf("expected file ID %d, got %d", fileID, fileResp.ID)
}
if fileResp.Name != "get_test.txt" {
t.Fatalf("expected name get_test.txt, got %s", fileResp.Name)
}
if fileResp.Size != int64(len("hello get")) {
t.Fatalf("expected size %d, got %d", len("hello get"), fileResp.Size)
}
}
func TestIntegration_File_Download(t *testing.T) {
env := testenv.NewTestEnv(t)
content := []byte("hello world")
fileID, _ := env.UploadTestData("download_test.txt", content)
resp := env.DoRequest("GET", fmt.Sprintf("/api/v1/files/%d/download", fileID), nil)
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Fatalf("expected 200, got %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatalf("read download body: %v", err)
}
if string(body) != string(content) {
t.Fatalf("downloaded content mismatch: got %q, want %q", string(body), string(content))
}
contentType := resp.Header.Get("Content-Type")
if contentType == "" {
t.Fatal("expected Content-Type header to be set")
}
}
func TestIntegration_File_Delete(t *testing.T) {
env := testenv.NewTestEnv(t)
fileID, _ := env.UploadTestData("delete_test.txt", []byte("hello delete"))
// Delete the file.
resp := env.DoRequest("DELETE", fmt.Sprintf("/api/v1/files/%d", fileID), nil)
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Fatalf("expected 200, got %d", resp.StatusCode)
}
r := fileDecode(t, resp.Body)
if !r.Success {
t.Fatalf("delete response not success: %s", r.Error)
}
// Verify the file is gone — GET should return 500 (internal error) or 404.
getResp := env.DoRequest("GET", fmt.Sprintf("/api/v1/files/%d", fileID), nil)
defer getResp.Body.Close()
if getResp.StatusCode == http.StatusOK {
gr := fileDecode(t, getResp.Body)
if gr.Success {
t.Fatal("expected file to be deleted, but GET still returns success")
}
}
}