forked from baron/baron-sso
userfront&backend test coverage 추가
This commit is contained in:
27
backend/internal/utils/audit_test.go
Normal file
27
backend/internal/utils/audit_test.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package utils
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestParseAuditDetails(t *testing.T) {
|
||||
t.Run("empty details returns error", func(t *testing.T) {
|
||||
if _, err := ParseAuditDetails(""); err == nil {
|
||||
t.Fatalf("expected empty details error")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("invalid JSON returns error", func(t *testing.T) {
|
||||
if _, err := ParseAuditDetails("{invalid"); err == nil {
|
||||
t.Fatalf("expected invalid JSON error")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("valid JSON returns payload", func(t *testing.T) {
|
||||
payload, err := ParseAuditDetails(`{"actor":"admin","count":2}`)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if payload["actor"] != "admin" || payload["count"] != float64(2) {
|
||||
t.Fatalf("unexpected payload: %#v", payload)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -22,3 +22,48 @@ func TestResolveClientIP_PrefersPublicRealIPOverPrivateForwarded(t *testing.T) {
|
||||
t.Fatalf("expected public real IP, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveClientIP_PrefersPublicRemoteIPWhenHeadersArePrivate(t *testing.T) {
|
||||
got := ResolveClientIP("10.0.0.2", "192.168.0.10", "203.0.113.8:12345")
|
||||
if got != "203.0.113.8" {
|
||||
t.Fatalf("expected public remote IP, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveClientIP_FallsBackToRealIPWhenNoForwardedCandidates(t *testing.T) {
|
||||
got := ResolveClientIP("invalid", "192.168.0.10", "bad-remote")
|
||||
if got != "192.168.0.10" {
|
||||
t.Fatalf("expected normalized real IP, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveClientIP_ReturnsEmptyForInvalidInputs(t *testing.T) {
|
||||
got := ResolveClientIP("", "bad-real", "bad-remote")
|
||||
if got != "" {
|
||||
t.Fatalf("expected empty IP, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsPrivateOrReservedIP(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ip string
|
||||
expected bool
|
||||
}{
|
||||
{name: "invalid", ip: "not-an-ip", expected: false},
|
||||
{name: "public", ip: "203.0.113.8", expected: false},
|
||||
{name: "private ipv4", ip: "10.0.0.1", expected: true},
|
||||
{name: "loopback", ip: "127.0.0.1", expected: true},
|
||||
{name: "link local", ip: "169.254.1.1", expected: true},
|
||||
{name: "carrier grade nat", ip: "100.64.0.1", expected: true},
|
||||
{name: "unique local ipv6", ip: "fc00::1", expected: true},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if got := IsPrivateOrReservedIP(tc.ip); got != tc.expected {
|
||||
t.Fatalf("unexpected private state for %s: got=%v expected=%v", tc.ip, got, tc.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@ func TestValidatePasswordWithPolicy(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Nil Policy", func(t *testing.T) {
|
||||
err := ValidatePasswordWithPolicy(nil, "")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Too Short", func(t *testing.T) {
|
||||
err := ValidatePasswordWithPolicy(policy, "P123!")
|
||||
assert.Error(t, err)
|
||||
@@ -34,11 +39,29 @@ func TestValidatePasswordWithPolicy(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "소문자")
|
||||
})
|
||||
|
||||
t.Run("Missing Uppercase", func(t *testing.T) {
|
||||
err := ValidatePasswordWithPolicy(policy, "pass1234!")
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "대문자")
|
||||
})
|
||||
|
||||
t.Run("Missing Number", func(t *testing.T) {
|
||||
err := ValidatePasswordWithPolicy(policy, "Password!")
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "숫자")
|
||||
})
|
||||
|
||||
t.Run("Missing Symbol", func(t *testing.T) {
|
||||
err := ValidatePasswordWithPolicy(policy, "Pass1234")
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "특수문자")
|
||||
})
|
||||
|
||||
t.Run("Missing Minimum Character Types", func(t *testing.T) {
|
||||
err := ValidatePasswordWithPolicy(&domain.PasswordPolicy{MinLength: 4, MinCharacterTypes: 4}, "abcd")
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "4가지")
|
||||
})
|
||||
}
|
||||
|
||||
func TestGeneratePasswordWithPolicy(t *testing.T) {
|
||||
@@ -55,8 +78,51 @@ func TestGeneratePasswordWithPolicy(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, password, 16)
|
||||
|
||||
// Generated password must satisfy the policy
|
||||
err = ValidatePasswordWithPolicy(policy, password)
|
||||
assert.NoError(t, err, "Generated password '%s' does not satisfy policy", password)
|
||||
})
|
||||
|
||||
t.Run("Nil Policy Uses Default Length", func(t *testing.T) {
|
||||
password, err := GeneratePasswordWithPolicy(nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, password, 12)
|
||||
})
|
||||
|
||||
t.Run("Minimum Character Types Adds Optional Categories", func(t *testing.T) {
|
||||
policy := &domain.PasswordPolicy{
|
||||
MinLength: 4,
|
||||
Lowercase: true,
|
||||
MinCharacterTypes: 4,
|
||||
}
|
||||
|
||||
password, err := GeneratePasswordWithPolicy(policy)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, password, 4)
|
||||
assert.NoError(t, ValidatePasswordWithPolicy(policy, password))
|
||||
})
|
||||
|
||||
t.Run("Required Categories Raise Short Minimum Length", func(t *testing.T) {
|
||||
policy := &domain.PasswordPolicy{
|
||||
MinLength: 1,
|
||||
Lowercase: true,
|
||||
Uppercase: true,
|
||||
Number: true,
|
||||
NonAlphanumeric: true,
|
||||
}
|
||||
|
||||
password, err := GeneratePasswordWithPolicy(policy)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, password, 4)
|
||||
assert.NoError(t, ValidatePasswordWithPolicy(policy, password))
|
||||
})
|
||||
}
|
||||
|
||||
func TestPasswordPolicyRandomHelpersRejectInvalidInput(t *testing.T) {
|
||||
_, err := randomIndex(0)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = randomChar("")
|
||||
assert.Error(t, err)
|
||||
|
||||
assert.NoError(t, shuffleRunes([]rune("a")))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user