- 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
194 lines
5.5 KiB
Go
194 lines
5.5 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"testing"
|
|
|
|
"gcy_hpc_server/internal/testutil/testenv"
|
|
)
|
|
|
|
// folderData mirrors the FolderResponse DTO returned by the API.
|
|
type folderData struct {
|
|
ID int64 `json:"id"`
|
|
Name string `json:"name"`
|
|
ParentID *int64 `json:"parent_id,omitempty"`
|
|
Path string `json:"path"`
|
|
FileCount int64 `json:"file_count"`
|
|
SubFolderCount int64 `json:"subfolder_count"`
|
|
}
|
|
|
|
// folderMessageData mirrors the delete endpoint response data structure.
|
|
type folderMessageData struct {
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
// folderDoRequest marshals body and calls env.DoRequest.
|
|
func folderDoRequest(env *testenv.TestEnv, method, path string, body interface{}) *http.Response {
|
|
var r io.Reader
|
|
if body != nil {
|
|
b, err := json.Marshal(body)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("folderDoRequest marshal: %v", err))
|
|
}
|
|
r = bytes.NewReader(b)
|
|
}
|
|
return env.DoRequest(method, path, r)
|
|
}
|
|
|
|
// folderDecodeAll decodes the response and returns status, success, and raw data.
|
|
func folderDecodeAll(env *testenv.TestEnv, resp *http.Response) (statusCode int, success bool, data json.RawMessage, err error) {
|
|
statusCode = resp.StatusCode
|
|
success, data, err = env.DecodeResponse(resp)
|
|
return
|
|
}
|
|
|
|
// folderSeed creates a folder via HTTP and returns its ID.
|
|
func folderSeed(env *testenv.TestEnv, name string) int64 {
|
|
body := map[string]interface{}{"name": name}
|
|
resp := folderDoRequest(env, http.MethodPost, "/api/v1/files/folders", body)
|
|
status, success, data, err := folderDecodeAll(env, resp)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("folderSeed decode: %v", err))
|
|
}
|
|
if status != http.StatusCreated {
|
|
panic(fmt.Sprintf("folderSeed: expected 201, got %d", status))
|
|
}
|
|
if !success {
|
|
panic("folderSeed: expected success=true")
|
|
}
|
|
var f folderData
|
|
if err := json.Unmarshal(data, &f); err != nil {
|
|
panic(fmt.Sprintf("folderSeed unmarshal: %v", err))
|
|
}
|
|
return f.ID
|
|
}
|
|
|
|
// TestIntegration_Folder_Create verifies POST /api/v1/files/folders creates a folder.
|
|
func TestIntegration_Folder_Create(t *testing.T) {
|
|
env := testenv.NewTestEnv(t)
|
|
|
|
body := map[string]interface{}{"name": "test-folder-create"}
|
|
resp := folderDoRequest(env, http.MethodPost, "/api/v1/files/folders", body)
|
|
status, success, data, err := folderDecodeAll(env, resp)
|
|
if err != nil {
|
|
t.Fatalf("decode response: %v", err)
|
|
}
|
|
if status != http.StatusCreated {
|
|
t.Fatalf("expected status 201, got %d", status)
|
|
}
|
|
if !success {
|
|
t.Fatal("expected success=true")
|
|
}
|
|
|
|
var created folderData
|
|
if err := json.Unmarshal(data, &created); err != nil {
|
|
t.Fatalf("unmarshal created data: %v", err)
|
|
}
|
|
if created.ID <= 0 {
|
|
t.Fatalf("expected positive id, got %d", created.ID)
|
|
}
|
|
if created.Name != "test-folder-create" {
|
|
t.Fatalf("expected name=test-folder-create, got %s", created.Name)
|
|
}
|
|
}
|
|
|
|
// TestIntegration_Folder_List verifies GET /api/v1/files/folders returns a list.
|
|
func TestIntegration_Folder_List(t *testing.T) {
|
|
env := testenv.NewTestEnv(t)
|
|
|
|
// Seed two folders.
|
|
folderSeed(env, "list-folder-1")
|
|
folderSeed(env, "list-folder-2")
|
|
|
|
resp := env.DoRequest(http.MethodGet, "/api/v1/files/folders", nil)
|
|
status, success, data, err := folderDecodeAll(env, resp)
|
|
if err != nil {
|
|
t.Fatalf("decode response: %v", err)
|
|
}
|
|
if status != http.StatusOK {
|
|
t.Fatalf("expected status 200, got %d", status)
|
|
}
|
|
if !success {
|
|
t.Fatal("expected success=true")
|
|
}
|
|
|
|
var folders []folderData
|
|
if err := json.Unmarshal(data, &folders); err != nil {
|
|
t.Fatalf("unmarshal list data: %v", err)
|
|
}
|
|
if len(folders) < 2 {
|
|
t.Fatalf("expected at least 2 folders, got %d", len(folders))
|
|
}
|
|
}
|
|
|
|
// TestIntegration_Folder_Get verifies GET /api/v1/files/folders/:id returns folder details.
|
|
func TestIntegration_Folder_Get(t *testing.T) {
|
|
env := testenv.NewTestEnv(t)
|
|
id := folderSeed(env, "test-folder-get")
|
|
|
|
path := fmt.Sprintf("/api/v1/files/folders/%d", id)
|
|
resp := env.DoRequest(http.MethodGet, path, nil)
|
|
status, success, data, err := folderDecodeAll(env, resp)
|
|
if err != nil {
|
|
t.Fatalf("decode response: %v", err)
|
|
}
|
|
if status != http.StatusOK {
|
|
t.Fatalf("expected status 200, got %d", status)
|
|
}
|
|
if !success {
|
|
t.Fatal("expected success=true")
|
|
}
|
|
|
|
var f folderData
|
|
if err := json.Unmarshal(data, &f); err != nil {
|
|
t.Fatalf("unmarshal folder data: %v", err)
|
|
}
|
|
if f.ID != id {
|
|
t.Fatalf("expected id=%d, got %d", id, f.ID)
|
|
}
|
|
if f.Name != "test-folder-get" {
|
|
t.Fatalf("expected name=test-folder-get, got %s", f.Name)
|
|
}
|
|
}
|
|
|
|
// TestIntegration_Folder_Delete verifies DELETE /api/v1/files/folders/:id removes a folder.
|
|
func TestIntegration_Folder_Delete(t *testing.T) {
|
|
env := testenv.NewTestEnv(t)
|
|
id := folderSeed(env, "test-folder-delete")
|
|
|
|
path := fmt.Sprintf("/api/v1/files/folders/%d", id)
|
|
resp := env.DoRequest(http.MethodDelete, path, nil)
|
|
status, success, data, err := folderDecodeAll(env, resp)
|
|
if err != nil {
|
|
t.Fatalf("decode response: %v", err)
|
|
}
|
|
if status != http.StatusOK {
|
|
t.Fatalf("expected status 200, got %d", status)
|
|
}
|
|
if !success {
|
|
t.Fatal("expected success=true")
|
|
}
|
|
|
|
var msg folderMessageData
|
|
if err := json.Unmarshal(data, &msg); err != nil {
|
|
t.Fatalf("unmarshal message data: %v", err)
|
|
}
|
|
if msg.Message != "folder deleted" {
|
|
t.Fatalf("expected message 'folder deleted', got %q", msg.Message)
|
|
}
|
|
|
|
// Verify it's gone via GET → 404.
|
|
getResp := env.DoRequest(http.MethodGet, path, nil)
|
|
getStatus, getSuccess, _, _ := folderDecodeAll(env, getResp)
|
|
if getStatus != http.StatusNotFound {
|
|
t.Fatalf("expected status 404 after delete, got %d", getStatus)
|
|
}
|
|
if getSuccess {
|
|
t.Fatal("expected success=false after delete")
|
|
}
|
|
}
|