Files
2026-06-12 14:25:34 +02:00

187 lines
5.0 KiB
Go

package vm
import (
"context"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"testing"
"time"
"proxui/backend/internal/auth"
)
func TestListProjectVMsReturnsVisibleVMs(t *testing.T) {
repository := &stubRepository{
listFound: true,
vms: []VM{{
ID: "vm-1",
ProjectID: "project-1",
TenantID: "tenant-1",
Name: "web-1",
Status: "running",
MembershipRole: "viewer",
CreatedAt: time.Date(2026, 6, 11, 12, 0, 0, 0, time.UTC),
UpdatedAt: time.Date(2026, 6, 11, 12, 0, 0, 0, time.UTC),
}},
}
handler := NewHandler(repository)
req := requestWithPrincipal(http.MethodGet, "/projects/project-1/vms")
req.SetPathValue("projectID", "project-1")
rec := httptest.NewRecorder()
handler.ListProjectVMs(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
}
if repository.profileID != "profile-1" {
t.Fatalf("profileID = %q, want profile-1", repository.profileID)
}
if repository.projectID != "project-1" {
t.Fatalf("projectID = %q, want project-1", repository.projectID)
}
var response struct {
Data []VM `json:"data"`
}
if err := json.Unmarshal(rec.Body.Bytes(), &response); err != nil {
t.Fatalf("unmarshal response: %v", err)
}
if len(response.Data) != 1 {
t.Fatalf("len(data) = %d, want 1", len(response.Data))
}
if response.Data[0].ID != "vm-1" {
t.Fatalf("VM ID = %q, want vm-1", response.Data[0].ID)
}
}
func TestListProjectVMsReturnsEmptyArray(t *testing.T) {
handler := NewHandler(&stubRepository{listFound: true})
req := requestWithPrincipal(http.MethodGet, "/projects/project-1/vms")
req.SetPathValue("projectID", "project-1")
rec := httptest.NewRecorder()
handler.ListProjectVMs(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
}
if got := rec.Body.String(); got != "{\"data\":[]}\n" {
t.Fatalf("body = %q, want empty data array", got)
}
}
func TestListProjectVMsReturnsNotFoundForInaccessibleProject(t *testing.T) {
handler := NewHandler(&stubRepository{listFound: false})
req := requestWithPrincipal(http.MethodGet, "/projects/project-1/vms")
req.SetPathValue("projectID", "project-1")
rec := httptest.NewRecorder()
handler.ListProjectVMs(rec, req)
if rec.Code != http.StatusNotFound {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusNotFound)
}
}
func TestGetVMReturnsVisibleVM(t *testing.T) {
repository := &stubRepository{
getFound: true,
vm: VM{
ID: "vm-1",
TenantID: "tenant-1",
Name: "web-1",
Status: "running",
},
}
handler := NewHandler(repository)
req := requestWithPrincipal(http.MethodGet, "/vms/vm-1")
req.SetPathValue("vmID", "vm-1")
rec := httptest.NewRecorder()
handler.GetVM(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
}
if repository.vmID != "vm-1" {
t.Fatalf("vmID = %q, want vm-1", repository.vmID)
}
}
func TestGetVMReturnsNotFoundForInvisibleVM(t *testing.T) {
handler := NewHandler(&stubRepository{getFound: false})
req := requestWithPrincipal(http.MethodGet, "/vms/vm-1")
req.SetPathValue("vmID", "vm-1")
rec := httptest.NewRecorder()
handler.GetVM(rec, req)
if rec.Code != http.StatusNotFound {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusNotFound)
}
}
func TestGetVMReturnsServerError(t *testing.T) {
handler := NewHandler(&stubRepository{err: errors.New("db failed")})
req := requestWithPrincipal(http.MethodGet, "/vms/vm-1")
req.SetPathValue("vmID", "vm-1")
rec := httptest.NewRecorder()
handler.GetVM(rec, req)
if rec.Code != http.StatusInternalServerError {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusInternalServerError)
}
}
func requestWithPrincipal(method string, target string) *http.Request {
req := httptest.NewRequest(method, target, nil)
return req.WithContext(auth.ContextWithPrincipal(req.Context(), auth.Principal{
Subject: "profile-1",
Email: "user@example.test",
Role: "authenticated",
}))
}
type stubRepository struct {
profileID string
projectID string
vmID string
vms []VM
vm VM
listFound bool
getFound bool
err error
}
func (s *stubRepository) ListProjectVMs(_ context.Context, profileID string, projectID string) ([]VM, bool, error) {
s.profileID = profileID
s.projectID = projectID
return s.vms, s.listFound, s.err
}
func (s *stubRepository) GetVM(_ context.Context, profileID string, vmID string) (VM, bool, error) {
s.profileID = profileID
s.vmID = vmID
return s.vm, s.getFound, s.err
}
func (s *stubRepository) GetProjectInfo(_ context.Context, profileID string, projectID string) (ProjectInfo, bool, error) {
return ProjectInfo{}, false, nil
}
func (s *stubRepository) CheckQuota(_ context.Context, _ string) (QuotaInfo, error) {
return QuotaInfo{}, nil
}
func (s *stubRepository) ReserveNextVMID(_ context.Context, _ string) (int, error) {
return 0, nil
}
func (s *stubRepository) InsertVM(_ context.Context, _ InsertVMRecord) (VM, error) {
return VM{}, nil
}