feat: add vm read endpoints
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
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 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
|
||||
}
|
||||
Reference in New Issue
Block a user