package turn import ( "fmt" "testing" "time" ) func TestGenerateCredentials(t *testing.T) { secret := "test-secret-key-32bytes-long!!!!" namespace := "test-namespace" ttl := 10 * time.Minute username, password := GenerateCredentials(secret, namespace, ttl) if username == "" { t.Fatal("username should not be empty") } if password == "" { t.Fatal("password should not be empty") } // Username should be "{timestamp}:{namespace}" var ts int64 var ns string n, err := fmt.Sscanf(username, "%d:%s", &ts, &ns) if err != nil || n != 2 { t.Fatalf("username format should be timestamp:namespace, got %q", username) } if ns != namespace { t.Fatalf("namespace in username should be %q, got %q", namespace, ns) } // Timestamp should be ~10 minutes in the future now := time.Now().Unix() expectedExpiry := now + int64(ttl.Seconds()) if ts < expectedExpiry-2 || ts > expectedExpiry+2 { t.Fatalf("expiry timestamp should be ~%d, got %d", expectedExpiry, ts) } } func TestGeneratePassword(t *testing.T) { secret := "test-secret" username := "1234567890:test-ns" password1 := GeneratePassword(secret, username) password2 := GeneratePassword(secret, username) // Same inputs should produce same output if password1 != password2 { t.Fatal("GeneratePassword should be deterministic") } // Different secret should produce different output password3 := GeneratePassword("different-secret", username) if password1 == password3 { t.Fatal("different secrets should produce different passwords") } // Different username should produce different output password4 := GeneratePassword(secret, "9999999999:other-ns") if password1 == password4 { t.Fatal("different usernames should produce different passwords") } } func TestValidateCredentials(t *testing.T) { secret := "test-secret-key" namespace := "my-namespace" ttl := 10 * time.Minute // Generate valid credentials username, password := GenerateCredentials(secret, namespace, ttl) tests := []struct { name string secret string username string password string namespace string wantValid bool }{ { name: "valid credentials", secret: secret, username: username, password: password, namespace: namespace, wantValid: true, }, { name: "wrong secret", secret: "wrong-secret", username: username, password: password, namespace: namespace, wantValid: false, }, { name: "wrong password", secret: secret, username: username, password: "wrongpassword", namespace: namespace, wantValid: false, }, { name: "wrong namespace", secret: secret, username: username, password: password, namespace: "other-namespace", wantValid: false, }, { name: "expired credentials", secret: secret, username: fmt.Sprintf("%d:%s", time.Now().Unix()-60, namespace), password: GeneratePassword(secret, fmt.Sprintf("%d:%s", time.Now().Unix()-60, namespace)), namespace: namespace, wantValid: false, }, { name: "malformed username - no colon", secret: secret, username: "badusername", password: "whatever", namespace: namespace, wantValid: false, }, { name: "malformed username - non-numeric timestamp", secret: secret, username: "notanumber:my-namespace", password: "whatever", namespace: namespace, wantValid: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := ValidateCredentials(tt.secret, tt.username, tt.password, tt.namespace) if got != tt.wantValid { t.Errorf("ValidateCredentials() = %v, want %v", got, tt.wantValid) } }) } } func TestConfigValidation(t *testing.T) { tests := []struct { name string config Config wantErrs int }{ { name: "valid config", config: Config{ ListenAddr: "0.0.0.0:3478", PublicIP: "1.2.3.4", Realm: "dbrs.space", AuthSecret: "secret123", RelayPortStart: 49152, RelayPortEnd: 50000, Namespace: "test-ns", }, wantErrs: 0, }, { name: "missing all fields", config: Config{}, wantErrs: 6, // listen_addr, public_ip, realm, auth_secret, relay_port_range, namespace }, { name: "invalid public IP", config: Config{ ListenAddr: "0.0.0.0:3478", PublicIP: "not-an-ip", Realm: "dbrs.space", AuthSecret: "secret", RelayPortStart: 49152, RelayPortEnd: 50000, Namespace: "test-ns", }, wantErrs: 1, }, { name: "relay range too small", config: Config{ ListenAddr: "0.0.0.0:3478", PublicIP: "1.2.3.4", Realm: "dbrs.space", AuthSecret: "secret", RelayPortStart: 49152, RelayPortEnd: 49200, Namespace: "test-ns", }, wantErrs: 1, }, { name: "relay range inverted", config: Config{ ListenAddr: "0.0.0.0:3478", PublicIP: "1.2.3.4", Realm: "dbrs.space", AuthSecret: "secret", RelayPortStart: 50000, RelayPortEnd: 49152, Namespace: "test-ns", }, wantErrs: 1, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { errs := tt.config.Validate() if len(errs) != tt.wantErrs { t.Errorf("Validate() returned %d errors, want %d: %v", len(errs), tt.wantErrs, errs) } }) } }