claude-web-chat/change_password_test.go
djuka 6c0ca3a96f
All checks were successful
Tests / unit-tests (push) Successful in 25s
Dodato kreiranje projekta kroz UI i change-password template
- CreateProject() sa validacijom imena (regex, duplikati, prazno)
- POST /projects/create ruta sa AuthMiddleware
- Modal forma na projects stranici za unos imena
- 10 unit testova za CreateProject
- change-password.html template i testovi
- Ažuriran TESTING.md sa novom sekcijom

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 06:27:10 +00:00

259 lines
6.3 KiB
Go

package main
import (
"net/http"
"net/http/httptest"
"net/url"
"os"
"path/filepath"
"strings"
"testing"
)
func setupTestApp(t *testing.T) (cleanupFn func()) {
t.Helper()
dir := t.TempDir()
cfgPath := filepath.Join(dir, "config.json")
data := `{
"username": "admin",
"password": "secret123",
"session_secret": "test-secret",
"projects_path": "/tmp"
}`
os.WriteFile(cfgPath, []byte(data), 0644)
var err error
oldCfg := cfg
oldTemplates := templates
oldSessionMgr := sessionMgr
cfg, err = LoadConfig(cfgPath)
if err != nil {
t.Fatalf("LoadConfig: %v", err)
}
templates, err = NewTemplateRenderer("templates")
if err != nil {
t.Fatalf("Templates: %v", err)
}
sessionMgr = NewSessionManager(cfg.SessionSecret)
return func() {
cfg = oldCfg
templates = oldTemplates
sessionMgr = oldSessionMgr
}
}
func TestChangePasswordPage(t *testing.T) {
cleanup := setupTestApp(t)
defer cleanup()
sess := sessionMgr.Create("admin")
req := httptest.NewRequest("GET", "/change-password", nil)
req.AddCookie(&http.Cookie{Name: sessionCookieName, Value: sess.Token})
w := httptest.NewRecorder()
handleChangePasswordPage(w, req)
if w.Code != http.StatusOK {
t.Errorf("status = %d, want %d", w.Code, http.StatusOK)
}
body := w.Body.String()
if !strings.Contains(body, "Promena lozinke") {
t.Error("expected page title in response")
}
if !strings.Contains(body, "current_password") {
t.Error("expected current_password field")
}
}
func TestChangePassword(t *testing.T) {
t.Run("uspešna promena", func(t *testing.T) {
cleanup := setupTestApp(t)
defer cleanup()
form := url.Values{
"current_password": {"secret123"},
"new_password": {"newpass123"},
"confirm_password": {"newpass123"},
}
req := httptest.NewRequest("POST", "/change-password", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder()
handleChangePassword(w, req)
if w.Code != http.StatusOK {
t.Errorf("status = %d, want %d", w.Code, http.StatusOK)
}
body := w.Body.String()
if !strings.Contains(body, "uspešno promenjena") {
t.Error("expected success message")
}
// Nova šifra radi
if !cfg.CheckPassword("newpass123") {
t.Error("new password should work")
}
// Stara ne radi
if cfg.CheckPassword("secret123") {
t.Error("old password should not work")
}
})
t.Run("pogrešna trenutna lozinka", func(t *testing.T) {
cleanup := setupTestApp(t)
defer cleanup()
form := url.Values{
"current_password": {"wrongpass"},
"new_password": {"newpass123"},
"confirm_password": {"newpass123"},
}
req := httptest.NewRequest("POST", "/change-password", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder()
handleChangePassword(w, req)
if w.Code != http.StatusBadRequest {
t.Errorf("status = %d, want %d", w.Code, http.StatusBadRequest)
}
body := w.Body.String()
if !strings.Contains(body, "Pogrešna trenutna lozinka") {
t.Error("expected wrong password error message")
}
})
t.Run("prekratka nova lozinka", func(t *testing.T) {
cleanup := setupTestApp(t)
defer cleanup()
form := url.Values{
"current_password": {"secret123"},
"new_password": {"abc"},
"confirm_password": {"abc"},
}
req := httptest.NewRequest("POST", "/change-password", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder()
handleChangePassword(w, req)
if w.Code != http.StatusBadRequest {
t.Errorf("status = %d, want %d", w.Code, http.StatusBadRequest)
}
body := w.Body.String()
if !strings.Contains(body, "najmanje 6 karaktera") {
t.Error("expected min length error message")
}
})
t.Run("lozinke se ne poklapaju", func(t *testing.T) {
cleanup := setupTestApp(t)
defer cleanup()
form := url.Values{
"current_password": {"secret123"},
"new_password": {"newpass123"},
"confirm_password": {"different"},
}
req := httptest.NewRequest("POST", "/change-password", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder()
handleChangePassword(w, req)
if w.Code != http.StatusBadRequest {
t.Errorf("status = %d, want %d", w.Code, http.StatusBadRequest)
}
body := w.Body.String()
if !strings.Contains(body, "ne poklapaju") {
t.Error("expected mismatch error message")
}
})
}
func TestConfigCheckPassword(t *testing.T) {
dir := t.TempDir()
cfgPath := filepath.Join(dir, "config.json")
data := `{
"username": "admin",
"password": "testpass",
"session_secret": "abc123"
}`
os.WriteFile(cfgPath, []byte(data), 0644)
c, err := LoadConfig(cfgPath)
if err != nil {
t.Fatalf("LoadConfig: %v", err)
}
// Šifra je hešovana u fajlu
if !isHashed(c.Password) {
t.Error("password should be hashed after LoadConfig")
}
// CheckPassword radi
if !c.CheckPassword("testpass") {
t.Error("CheckPassword should return true for correct password")
}
if c.CheckPassword("wrong") {
t.Error("CheckPassword should return false for wrong password")
}
}
func TestConfigSetPassword(t *testing.T) {
dir := t.TempDir()
cfgPath := filepath.Join(dir, "config.json")
data := `{
"username": "admin",
"password": "original",
"session_secret": "abc123"
}`
os.WriteFile(cfgPath, []byte(data), 0644)
c, err := LoadConfig(cfgPath)
if err != nil {
t.Fatalf("LoadConfig: %v", err)
}
if err := c.SetPassword("newpassword"); err != nil {
t.Fatalf("SetPassword: %v", err)
}
if !c.CheckPassword("newpassword") {
t.Error("new password should work")
}
if c.CheckPassword("original") {
t.Error("old password should not work")
}
// Proveri da je sačuvano u fajl
c2, err := LoadConfig(cfgPath)
if err != nil {
t.Fatalf("LoadConfig after SetPassword: %v", err)
}
if !c2.CheckPassword("newpassword") {
t.Error("password should persist after reload")
}
}
func TestIsHashed(t *testing.T) {
if isHashed("plaintext") {
t.Error("plaintext should not be detected as hashed")
}
if !isHashed("$2a$10$abcdefghijklmnopqrstuuABC") {
t.Error("$2a$ prefix should be detected as hashed")
}
if !isHashed("$2b$10$abcdefghijklmnopqrstuuABC") {
t.Error("$2b$ prefix should be detected as hashed")
}
}