- 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
171 lines
4.2 KiB
Go
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")
|
|
}
|
|
}
|
|
}
|