164 lines
3.8 KiB
Go
164 lines
3.8 KiB
Go
|
|
package challenge
|
||
|
|
|
||
|
|
import (
|
||
|
|
"errors"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestNewConfig(t *testing.T) {
|
||
|
|
tests := []struct {
|
||
|
|
name string
|
||
|
|
opts []configOption
|
||
|
|
wantErr bool
|
||
|
|
expectedErr error
|
||
|
|
validate func(*Config) error
|
||
|
|
}{
|
||
|
|
{
|
||
|
|
name: "default config",
|
||
|
|
opts: nil,
|
||
|
|
wantErr: false,
|
||
|
|
validate: func(c *Config) error {
|
||
|
|
if c.DefaultDifficulty != 4 {
|
||
|
|
return errors.New("expected default difficulty 4")
|
||
|
|
}
|
||
|
|
if c.RandomBytes != 6 {
|
||
|
|
return errors.New("expected random bytes 6")
|
||
|
|
}
|
||
|
|
if len(c.HMACSecret) == 0 {
|
||
|
|
return errors.New("expected HMAC secret to be generated")
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "custom difficulty",
|
||
|
|
opts: []configOption{WithDefaultDifficulty(8)},
|
||
|
|
wantErr: false,
|
||
|
|
validate: func(c *Config) error {
|
||
|
|
if c.DefaultDifficulty != 8 {
|
||
|
|
return errors.New("expected custom difficulty 8")
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "invalid random bytes - too low",
|
||
|
|
opts: []configOption{WithRandomBytes(0)},
|
||
|
|
wantErr: true,
|
||
|
|
expectedErr: ErrInvalidConfig,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "invalid random bytes - too high",
|
||
|
|
opts: []configOption{WithRandomBytes(50)},
|
||
|
|
wantErr: true,
|
||
|
|
expectedErr: ErrInvalidConfig,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "invalid difficulty - min too low",
|
||
|
|
opts: []configOption{WithMinDifficulty(0)},
|
||
|
|
wantErr: true,
|
||
|
|
expectedErr: ErrInvalidConfig,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "invalid difficulty - max less than min",
|
||
|
|
opts: []configOption{
|
||
|
|
WithMinDifficulty(5),
|
||
|
|
WithMaxDifficulty(3),
|
||
|
|
},
|
||
|
|
wantErr: true,
|
||
|
|
expectedErr: ErrInvalidConfig,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "invalid difficulty - default out of range",
|
||
|
|
opts: []configOption{
|
||
|
|
WithMinDifficulty(5),
|
||
|
|
WithMaxDifficulty(10),
|
||
|
|
WithDefaultDifficulty(15),
|
||
|
|
},
|
||
|
|
wantErr: true,
|
||
|
|
expectedErr: ErrInvalidConfig,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "empty HMAC secret",
|
||
|
|
opts: []configOption{WithHMACSecret(nil)},
|
||
|
|
wantErr: true,
|
||
|
|
expectedErr: ErrInvalidConfig,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "negative TTL",
|
||
|
|
opts: []configOption{WithChallengeTTL(-time.Minute)},
|
||
|
|
wantErr: true,
|
||
|
|
expectedErr: ErrInvalidConfig,
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tt := range tests {
|
||
|
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
|
config, err := NewConfig(tt.opts...)
|
||
|
|
|
||
|
|
if tt.wantErr {
|
||
|
|
if err == nil {
|
||
|
|
t.Fatal("expected error but got none")
|
||
|
|
}
|
||
|
|
if !errors.Is(err, tt.expectedErr) {
|
||
|
|
t.Fatalf("expected error %v, got %v", tt.expectedErr, err)
|
||
|
|
}
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if tt.validate != nil {
|
||
|
|
if err := tt.validate(config); err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestConfigOptions(t *testing.T) {
|
||
|
|
secret := []byte("test-secret")
|
||
|
|
config, err := NewConfig(
|
||
|
|
WithDefaultDifficulty(6),
|
||
|
|
WithMaxDifficulty(12),
|
||
|
|
WithMinDifficulty(2),
|
||
|
|
WithChallengeTTL(10*time.Minute),
|
||
|
|
WithHMACSecret(secret),
|
||
|
|
WithResource("api"),
|
||
|
|
WithRandomBytes(8),
|
||
|
|
WithLoadAdjustmentBits(2),
|
||
|
|
WithFailurePenaltyBits(3),
|
||
|
|
WithMaxFailurePenaltyBits(9),
|
||
|
|
)
|
||
|
|
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("unexpected error: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if config.DefaultDifficulty != 6 {
|
||
|
|
t.Errorf("expected DefaultDifficulty 6, got %d", config.DefaultDifficulty)
|
||
|
|
}
|
||
|
|
if config.MaxDifficulty != 12 {
|
||
|
|
t.Errorf("expected MaxDifficulty 12, got %d", config.MaxDifficulty)
|
||
|
|
}
|
||
|
|
if config.MinDifficulty != 2 {
|
||
|
|
t.Errorf("expected MinDifficulty 2, got %d", config.MinDifficulty)
|
||
|
|
}
|
||
|
|
if config.ChallengeTTL != 10*time.Minute {
|
||
|
|
t.Errorf("expected ChallengeTTL 10m, got %v", config.ChallengeTTL)
|
||
|
|
}
|
||
|
|
if string(config.HMACSecret) != string(secret) {
|
||
|
|
t.Errorf("expected HMACSecret %s, got %s", secret, config.HMACSecret)
|
||
|
|
}
|
||
|
|
if config.Resource != "api" {
|
||
|
|
t.Errorf("expected Resource 'api', got %s", config.Resource)
|
||
|
|
}
|
||
|
|
if config.RandomBytes != 8 {
|
||
|
|
t.Errorf("expected RandomBytes 8, got %d", config.RandomBytes)
|
||
|
|
}
|
||
|
|
}
|