feat: create standalone native fnOS repository

This commit is contained in:
2026-10-02 15:19:09 +08:00
parent 69f3c30fab
commit 6725fc131d
492 changed files with 94023 additions and 3 deletions
+96
View File
@@ -0,0 +1,96 @@
package api
import (
"bytes"
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"path/filepath"
"testing"
"time"
"github.com/havline/havline/internal/auth"
"github.com/havline/havline/internal/backup"
"github.com/havline/havline/internal/certificate"
"github.com/havline/havline/internal/config"
"github.com/havline/havline/internal/db"
"github.com/havline/havline/internal/discovery"
"github.com/havline/havline/internal/proxy"
"github.com/havline/havline/internal/service"
"github.com/havline/havline/internal/settings"
)
func TestAuthSetupAndLoginFlow(t *testing.T) {
conn, err := db.Open(filepath.Join(t.TempDir(), "havline.db"))
if err != nil {
t.Fatalf("open db: %v", err)
}
defer conn.Close()
if err := db.Migrate(context.Background(), conn, filepath.Join("..", "..", "migrations")); err != nil {
t.Fatalf("migrate: %v", err)
}
tmpDir := t.TempDir()
authSvc := auth.New(conn)
proxySvc := service.NewProxyService(config.Config{DataDir: tmpDir, NginxPIDFile: tmpDir + "/nginx.pid"}, conn, proxy.NewStore(conn), certificate.NewStore(conn), settings.NewStore(conn), nil)
handler := NewRouter(Deps{
Config: config.Config{DataDir: tmpDir, NginxPIDFile: tmpDir + "/nginx.pid"},
Auth: authSvc,
Proxy: proxySvc,
Backup: backup.New(tmpDir),
Discovery: discovery.New(),
StartedAt: time.Now().UTC().Format(time.RFC3339),
})
statusReq := httptest.NewRequest(http.MethodGet, "/api/auth/status", nil)
statusRec := httptest.NewRecorder()
handler.ServeHTTP(statusRec, statusReq)
if statusRec.Code != http.StatusOK {
t.Fatalf("status code: %d", statusRec.Code)
}
if err := authSvc.Setup(context.Background(), "admin", "password123"); err != nil {
t.Fatalf("setup admin: %v", err)
}
loginBody, _ := json.Marshal(map[string]string{
"username": "admin",
"password": "password123",
})
loginReq := httptest.NewRequest(http.MethodPost, "/api/auth/login", bytes.NewReader(loginBody))
loginRec := httptest.NewRecorder()
handler.ServeHTTP(loginRec, loginReq)
if loginRec.Code != http.StatusOK {
t.Fatalf("login status: %d body=%s", loginRec.Code, loginRec.Body.String())
}
cookie := loginRec.Result().Cookies()[0]
if cookie.Name != "havline_session" || cookie.HttpOnly == false {
t.Fatal("expected httponly session cookie")
}
authStatusReq := httptest.NewRequest(http.MethodGet, "/api/auth/status", nil)
authStatusReq.AddCookie(cookie)
authStatusRec := httptest.NewRecorder()
handler.ServeHTTP(authStatusRec, authStatusReq)
if authStatusRec.Code != http.StatusOK {
t.Fatalf("auth status code: %d", authStatusRec.Code)
}
var authStatus authStatusResponse
if err := json.Unmarshal(authStatusRec.Body.Bytes(), &authStatus); err != nil {
t.Fatalf("decode auth status: %v", err)
}
if !authStatus.Initialized || !authStatus.Authenticated {
t.Fatalf("expected authenticated status, got %+v", authStatus)
}
proxiesReq := httptest.NewRequest(http.MethodGet, "/api/proxies", nil)
proxiesReq.AddCookie(cookie)
proxiesRec := httptest.NewRecorder()
handler.ServeHTTP(proxiesRec, proxiesReq)
if proxiesRec.Code != http.StatusOK {
t.Fatalf("proxies status: %d", proxiesRec.Code)
}
}