Initial commit: Custom Start Page application with authentication and DynamoDB storage
This commit is contained in:
159
internal/handlers/auth_handler_test.go
Normal file
159
internal/handlers/auth_handler_test.go
Normal file
@@ -0,0 +1,159 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"custom-start-page/internal/auth"
|
||||
)
|
||||
|
||||
// MockSessionStore is a mock implementation of SessionStore for testing
|
||||
type MockSessionStore struct {
|
||||
userID string
|
||||
shouldError bool
|
||||
}
|
||||
|
||||
func (m *MockSessionStore) CreateSession(w http.ResponseWriter, r *http.Request, userID string) error {
|
||||
m.userID = userID
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockSessionStore) GetUserID(r *http.Request) (string, error) {
|
||||
if m.shouldError {
|
||||
return "", http.ErrNoCookie
|
||||
}
|
||||
return m.userID, nil
|
||||
}
|
||||
|
||||
func (m *MockSessionStore) DestroySession(w http.ResponseWriter, r *http.Request) error {
|
||||
m.userID = ""
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockSessionStore) ValidateSession(r *http.Request) bool {
|
||||
return m.userID != ""
|
||||
}
|
||||
|
||||
// createMockTemplate creates a simple mock template for testing
|
||||
func createMockTemplate() *template.Template {
|
||||
tmpl := template.New("login.html")
|
||||
template.Must(tmpl.Parse(`<!DOCTYPE html><html><body>{{if .Error}}<div>{{.Error}}</div>{{end}}<a href="/auth/oauth/google">Login</a></body></html>`))
|
||||
return tmpl
|
||||
}
|
||||
|
||||
// TestHandleLogin_UnauthenticatedUser tests that unauthenticated users see the login page
|
||||
func TestHandleLogin_UnauthenticatedUser(t *testing.T) {
|
||||
// Setup
|
||||
mockSessionStore := &MockSessionStore{shouldError: true}
|
||||
oauthService := auth.NewOAuthService("test-client-id", "test-secret", "http://localhost/callback", auth.NewMemoryStateStore())
|
||||
userService := auth.NewUserService(nil) // nil repo for this test
|
||||
mockTemplate := createMockTemplate()
|
||||
handler := NewAuthHandlerWithTemplates(oauthService, userService, mockSessionStore, mockTemplate)
|
||||
|
||||
// Create request
|
||||
req := httptest.NewRequest(http.MethodGet, "/login", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
// Execute
|
||||
handler.HandleLogin(w, req)
|
||||
|
||||
// Assert
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status 200, got %d", w.Code)
|
||||
}
|
||||
|
||||
// Check that response contains login page elements
|
||||
body := w.Body.String()
|
||||
if body == "" {
|
||||
t.Error("Expected non-empty response body")
|
||||
}
|
||||
}
|
||||
|
||||
// TestHandleLogin_AuthenticatedUser tests that authenticated users are redirected to dashboard
|
||||
func TestHandleLogin_AuthenticatedUser(t *testing.T) {
|
||||
// Setup
|
||||
mockSessionStore := &MockSessionStore{userID: "test-user-123"}
|
||||
oauthService := auth.NewOAuthService("test-client-id", "test-secret", "http://localhost/callback", auth.NewMemoryStateStore())
|
||||
userService := auth.NewUserService(nil)
|
||||
mockTemplate := createMockTemplate()
|
||||
handler := NewAuthHandlerWithTemplates(oauthService, userService, mockSessionStore, mockTemplate)
|
||||
|
||||
// Create request
|
||||
req := httptest.NewRequest(http.MethodGet, "/login", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
// Execute
|
||||
handler.HandleLogin(w, req)
|
||||
|
||||
// Assert
|
||||
if w.Code != http.StatusTemporaryRedirect {
|
||||
t.Errorf("Expected status 307, got %d", w.Code)
|
||||
}
|
||||
|
||||
location := w.Header().Get("Location")
|
||||
if location != "/dashboard" {
|
||||
t.Errorf("Expected redirect to /dashboard, got %s", location)
|
||||
}
|
||||
}
|
||||
|
||||
// TestHandleLogin_WithError tests that error messages are displayed
|
||||
func TestHandleLogin_WithError(t *testing.T) {
|
||||
// Setup
|
||||
mockSessionStore := &MockSessionStore{shouldError: true}
|
||||
oauthService := auth.NewOAuthService("test-client-id", "test-secret", "http://localhost/callback", auth.NewMemoryStateStore())
|
||||
userService := auth.NewUserService(nil)
|
||||
mockTemplate := createMockTemplate()
|
||||
handler := NewAuthHandlerWithTemplates(oauthService, userService, mockSessionStore, mockTemplate)
|
||||
|
||||
// Create request with error parameter
|
||||
req := httptest.NewRequest(http.MethodGet, "/login?error=oauth_failed", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
// Execute
|
||||
handler.HandleLogin(w, req)
|
||||
|
||||
// Assert
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("Expected status 200, got %d", w.Code)
|
||||
}
|
||||
|
||||
// Check that response contains error message
|
||||
body := w.Body.String()
|
||||
if body == "" {
|
||||
t.Error("Expected non-empty response body")
|
||||
}
|
||||
}
|
||||
|
||||
// TestHandleLogout tests that logout destroys session and redirects to login
|
||||
func TestHandleLogout(t *testing.T) {
|
||||
// Setup
|
||||
mockSessionStore := &MockSessionStore{userID: "test-user-123"}
|
||||
oauthService := auth.NewOAuthService("test-client-id", "test-secret", "http://localhost/callback", auth.NewMemoryStateStore())
|
||||
userService := auth.NewUserService(nil)
|
||||
mockTemplate := createMockTemplate()
|
||||
handler := NewAuthHandlerWithTemplates(oauthService, userService, mockSessionStore, mockTemplate)
|
||||
|
||||
// Create request
|
||||
req := httptest.NewRequest(http.MethodPost, "/logout", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
// Execute
|
||||
handler.HandleLogout(w, req)
|
||||
|
||||
// Assert
|
||||
if w.Code != http.StatusTemporaryRedirect {
|
||||
t.Errorf("Expected status 307, got %d", w.Code)
|
||||
}
|
||||
|
||||
location := w.Header().Get("Location")
|
||||
if location != "/login" {
|
||||
t.Errorf("Expected redirect to /login, got %s", location)
|
||||
}
|
||||
|
||||
// Verify session was destroyed
|
||||
if mockSessionStore.userID != "" {
|
||||
t.Error("Expected session to be destroyed")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user