rogueserver/api/account/login_test.go
2025-09-16 15:01:00 -05:00

155 lines
5.0 KiB
Go

package account
import (
"database/sql"
"errors"
"testing"
)
func defaultMockStore() *mockDBAccountStore {
return &mockDBAccountStore{
FetchFunc: func(username string) ([]byte, []byte, error) {
return []byte("key"), []byte("salt"), nil
},
AddSessionFunc: func(username string, token []byte) error { return nil },
}
}
type mockDBAccountStore struct {
FetchFunc func(username string) ([]byte, []byte, error)
AddSessionFunc func(username string, token []byte) error
}
func (m *mockDBAccountStore) FetchAccountKeySaltFromUsername(username string) ([]byte, []byte, error) {
return m.FetchFunc(username)
}
func (m *mockDBAccountStore) AddAccountSession(username string, token []byte) error {
return m.AddSessionFunc(username, token)
}
func TestLogin(t *testing.T) {
t.Run("UsernameMinLength", func(t *testing.T) {
store := defaultMockStore()
_, err := Login(store, "a", "password123")
if err == nil {
t.Errorf("expected error due to password mismatch or DB, got nil")
}
})
t.Run("UsernameMaxLength", func(t *testing.T) {
uname := "abcdefghijklmnop"
store := defaultMockStore()
_, err := Login(store, uname, "password123")
if err == nil {
t.Errorf("expected error due to password mismatch or DB, got nil")
}
})
t.Run("UsernameTooLong", func(t *testing.T) {
uname := "abcdefghijklmnopq"
store := defaultMockStore()
_, err := Login(store, uname, "password123")
if err == nil || err.Error() != "invalid username" {
t.Errorf("expected invalid username error for too long username, got: %v", err)
}
})
t.Run("UsernameWithInvalidChars", func(t *testing.T) {
store := defaultMockStore()
_, err := Login(store, "user!@#", "password123")
if err == nil || err.Error() != "invalid username" {
t.Errorf("expected invalid username error for special chars, got: %v", err)
}
})
t.Run("EmptyUsername", func(t *testing.T) {
store := defaultMockStore()
_, err := Login(store, "", "password123")
if err == nil || err.Error() != "invalid username" {
t.Errorf("expected invalid username error for empty username, got: %v", err)
}
})
t.Run("EmptyPassword", func(t *testing.T) {
store := defaultMockStore()
_, err := Login(store, "validuser", "")
if err == nil || err.Error() != "invalid password" {
t.Errorf("expected invalid password error for empty password, got: %v", err)
}
})
t.Run("MinPasswordLength", func(t *testing.T) {
store := defaultMockStore()
_, err := Login(store, "validuser", "123456")
if err == nil {
t.Errorf("expected error due to password mismatch or DB, got nil")
}
})
t.Run("PasswordWithSpecialChars", func(t *testing.T) {
store := defaultMockStore()
_, err := Login(store, "validuser", "p@$$w0rd!")
if err == nil {
t.Errorf("expected error due to password mismatch or DB, got nil")
}
})
t.Run("DBUnexpectedError", func(t *testing.T) {
store := defaultMockStore()
store.FetchFunc = func(username string) ([]byte, []byte, error) {
return nil, nil, errors.New("some db error")
}
_, err := Login(store, "validuser", "password123")
if err == nil || err.Error() != "some db error" {
t.Errorf("expected DB error to propagate, got: %v", err)
}
})
t.Run("InvalidUsername", func(t *testing.T) {
store := defaultMockStore()
_, err := Login(store, "!invaliduser", "password123")
if err == nil || err.Error() != "invalid username" {
t.Errorf("expected invalid username error, got: %v", err)
}
})
t.Run("ShortPassword", func(t *testing.T) {
store := defaultMockStore()
_, err := Login(store, "validuser", "123")
if err == nil || err.Error() != "invalid password" {
t.Errorf("expected invalid password error, got: %v", err)
}
})
t.Run("AccountDoesNotExist", func(t *testing.T) {
store := defaultMockStore()
store.FetchFunc = func(username string) ([]byte, []byte, error) {
return nil, nil, sql.ErrNoRows
}
_, err := Login(store, "nonexistent", "password123")
if err == nil || err.Error() != "account doesn't exist" {
t.Errorf("expected account doesn't exist error, got: %v", err)
}
})
t.Run("PasswordMismatch", func(t *testing.T) {
correctSalt := []byte("somesalt")
correctKey := []byte("correctkey")
store := defaultMockStore()
store.FetchFunc = func(username string) ([]byte, []byte, error) {
return correctKey, correctSalt, nil
}
_, err := Login(store, "validuser", "wrongpassword")
if err == nil || err.Error() != "password doesn't match" {
t.Errorf("expected password doesn't match error, got: %v", err)
}
})
t.Run("Success", func(t *testing.T) {
correctSalt := []byte("somesalt")
password := "goodpassword"
correctKey := deriveArgon2IDKey([]byte(password), correctSalt)
store := defaultMockStore()
store.FetchFunc = func(username string) ([]byte, []byte, error) {
return correctKey, correctSalt, nil
}
store.AddSessionFunc = func(username string, token []byte) error {
return nil
}
resp, err := Login(store, "validuser", password)
if err != nil {
t.Errorf("expected success, got error: %v", err)
}
if resp.Token == "" {
t.Errorf("expected token to be set on success")
}
})
}