package auth import ( "database/sql" "html/template" "net/http" "net/http/httptest" "net/url" "strings" "testing" "time" "github.com/DATA-DOG/go-sqlmock" "github.com/alexedwards/scs/v2" "golang.org/x/crypto/bcrypt" ) func TestHandleLogin(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer func() { _ = db.Close() }() service := NewService(db) sessionManager := scs.New() templates := template.Must(template.New("login.html").Parse("{{.Error}}")) handlers := NewHandlers(service, sessionManager, templates, nil) // Setup mock user password := "password" hash, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) rows := sqlmock.NewRows([]string{"id", "username", "password_hash", "created_at"}). AddRow(1, "testuser", string(hash), time.Now()) mock.ExpectQuery("SELECT id, username, password_hash, created_at FROM users WHERE username = ?"). WithArgs("testuser"). WillReturnRows(rows) // Create request form := url.Values{} form.Add("username", "testuser") form.Add("password", "password") req := httptest.NewRequest("POST", "/login", strings.NewReader(form.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") // Wrap request with session middleware ctx, _ := sessionManager.Load(req.Context(), "") req = req.WithContext(ctx) rr := httptest.NewRecorder() handlers.HandleLogin(rr, req) if status := rr.Code; status != http.StatusSeeOther { t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusSeeOther) } if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("there were unfulfilled expectations: %s", err) } } func TestHandleLogin_InvalidCredentials(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer func() { _ = db.Close() }() service := NewService(db) sessionManager := scs.New() templates := template.Must(template.New("login.html").Parse("{{.Error}}")) handlers := NewHandlers(service, sessionManager, templates, nil) mock.ExpectQuery("SELECT id, username, password_hash, created_at FROM users WHERE username = ?"). WithArgs("testuser"). WillReturnError(sql.ErrNoRows) // Create request form := url.Values{} form.Add("username", "testuser") form.Add("password", "wrongpassword") req := httptest.NewRequest("POST", "/login", strings.NewReader(form.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") // Wrap request with session middleware ctx, _ := sessionManager.Load(req.Context(), "") req = req.WithContext(ctx) rr := httptest.NewRecorder() handlers.HandleLogin(rr, req) if status := rr.Code; status != http.StatusUnauthorized { t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusUnauthorized) } if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("there were unfulfilled expectations: %s", err) } }