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") } } }