Files
atlas/test/integration_test.go
Othman H. Suseno a7ba6c83ea
Some checks failed
CI / test-build (push) Has been cancelled
switch to postgresql
2025-12-16 01:31:27 +07:00

180 lines
4.1 KiB
Go

package test
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"gitea.avt.data-center.id/othman.suseno/atlas/internal/httpapp"
)
// TestServer provides an integration test server
type TestServer struct {
App *httpapp.App
Server *httptest.Server
Client *http.Client
AuthToken string
}
// NewTestServer creates a new test server
func NewTestServer(t *testing.T) *TestServer {
// Use absolute paths or create templates directory for tests
templatesDir := "web/templates"
staticDir := "web/static"
app, err := httpapp.New(httpapp.Config{
Addr: ":0", // Use random port
TemplatesDir: templatesDir,
StaticDir: staticDir,
DatabaseConn: "", // Empty = in-memory mode (no database)
})
if err != nil {
t.Fatalf("create test app: %v", err)
}
server := httptest.NewServer(app.Router())
return &TestServer{
App: app,
Server: server,
Client: &http.Client{},
}
}
// Close shuts down the test server
func (ts *TestServer) Close() {
ts.Server.Close()
ts.App.StopScheduler()
}
// Login performs a login and stores the auth token
func (ts *TestServer) Login(t *testing.T, username, password string) {
reqBody := map[string]string{
"username": username,
"password": password,
}
body, _ := json.Marshal(reqBody)
req, err := http.NewRequest("POST", ts.Server.URL+"/api/v1/auth/login",
bytes.NewReader(body))
if err != nil {
t.Fatalf("create login request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := ts.Client.Do(req)
if err != nil {
t.Fatalf("login request: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Fatalf("login failed with status %d", resp.StatusCode)
}
var result map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
t.Fatalf("decode login response: %v", err)
}
if token, ok := result["token"].(string); ok {
ts.AuthToken = token
} else {
t.Fatal("no token in login response")
}
}
// Get performs an authenticated GET request
func (ts *TestServer) Get(t *testing.T, path string) *http.Response {
req, err := http.NewRequest("GET", ts.Server.URL+path, nil)
if err != nil {
t.Fatalf("create GET request: %v", err)
}
if ts.AuthToken != "" {
req.Header.Set("Authorization", "Bearer "+ts.AuthToken)
}
resp, err := ts.Client.Do(req)
if err != nil {
t.Fatalf("GET request: %v", err)
}
return resp
}
// Post performs an authenticated POST request
func (ts *TestServer) Post(t *testing.T, path string, body interface{}) *http.Response {
bodyBytes, err := json.Marshal(body)
if err != nil {
t.Fatalf("marshal request body: %v", err)
}
req, err := http.NewRequest("POST", ts.Server.URL+path, bytes.NewReader(bodyBytes))
if err != nil {
t.Fatalf("create POST request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
if ts.AuthToken != "" {
req.Header.Set("Authorization", "Bearer "+ts.AuthToken)
}
resp, err := ts.Client.Do(req)
if err != nil {
t.Fatalf("POST request: %v", err)
}
return resp
}
// TestHealthCheck tests the health check endpoint
func TestHealthCheck(t *testing.T) {
ts := NewTestServer(t)
defer ts.Close()
resp := ts.Get(t, "/healthz")
if resp.StatusCode != http.StatusOK {
t.Errorf("expected status 200, got %d", resp.StatusCode)
}
}
// TestLogin tests the login endpoint
func TestLogin(t *testing.T) {
ts := NewTestServer(t)
defer ts.Close()
// Test with default admin credentials
ts.Login(t, "admin", "admin")
if ts.AuthToken == "" {
t.Error("expected auth token after login")
}
}
// TestUnauthorizedAccess tests that protected endpoints require authentication
func TestUnauthorizedAccess(t *testing.T) {
ts := NewTestServer(t)
defer ts.Close()
resp := ts.Get(t, "/api/v1/pools")
if resp.StatusCode != http.StatusUnauthorized {
t.Errorf("expected status 401, got %d", resp.StatusCode)
}
}
// TestAuthenticatedAccess tests that authenticated requests work
func TestAuthenticatedAccess(t *testing.T) {
ts := NewTestServer(t)
defer ts.Close()
ts.Login(t, "admin", "admin")
resp := ts.Get(t, "/api/v1/pools")
if resp.StatusCode != http.StatusOK {
t.Errorf("expected status 200, got %d", resp.StatusCode)
}
}