feat: implement ntfy-discord bridge in Go
- SSE subscription to ntfy with auto-reconnect - Discord webhook integration with embed formatting - Priority to color mapping, tag to emoji conversion - Native HashiCorp Vault support (Kubernetes + token auth) - Hot reload secrets via fsnotify or Vault polling - Prometheus metrics (/metrics endpoint) - Health/ready endpoints for Kubernetes probes - Comprehensive unit tests and fuzz tests - Multi-stage Docker build (~10MB scratch image) - CI/CD pipeline for Gitea Actions
This commit is contained in:
94
internal/vault/client_test.go
Normal file
94
internal/vault/client_test.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package vault
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConfig_Defaults(t *testing.T) {
|
||||
cfg := Config{
|
||||
Address: "http://vault.vault.svc.cluster.local:8200",
|
||||
AuthMethod: "kubernetes",
|
||||
Role: "ntfy-discord",
|
||||
MountPath: "secret",
|
||||
SecretPath: "ntfy-discord",
|
||||
}
|
||||
|
||||
if cfg.Address == "" {
|
||||
t.Error("Address should not be empty")
|
||||
}
|
||||
|
||||
if cfg.AuthMethod != "kubernetes" {
|
||||
t.Errorf("AuthMethod = %s, want kubernetes", cfg.AuthMethod)
|
||||
}
|
||||
|
||||
if cfg.MountPath != "secret" {
|
||||
t.Errorf("MountPath = %s, want secret", cfg.MountPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewClient_InvalidAddress(t *testing.T) {
|
||||
cfg := Config{
|
||||
Address: "not-a-valid-url",
|
||||
AuthMethod: "kubernetes",
|
||||
Role: "test",
|
||||
MountPath: "secret",
|
||||
SecretPath: "test",
|
||||
}
|
||||
|
||||
// This should fail because there's no Kubernetes token
|
||||
_, err := NewClient(cfg)
|
||||
if err == nil {
|
||||
t.Error("expected error for kubernetes auth without token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewClient_TokenAuth_NoToken(t *testing.T) {
|
||||
cfg := Config{
|
||||
Address: "http://localhost:8200",
|
||||
AuthMethod: "token",
|
||||
MountPath: "secret",
|
||||
SecretPath: "test",
|
||||
}
|
||||
|
||||
// Should fail because VAULT_TOKEN is not set
|
||||
_, err := NewClient(cfg)
|
||||
if err == nil {
|
||||
t.Error("expected error for token auth without VAULT_TOKEN")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewClient_UnsupportedAuthMethod(t *testing.T) {
|
||||
cfg := Config{
|
||||
Address: "http://localhost:8200",
|
||||
AuthMethod: "unsupported",
|
||||
MountPath: "secret",
|
||||
SecretPath: "test",
|
||||
}
|
||||
|
||||
_, err := NewClient(cfg)
|
||||
if err == nil {
|
||||
t.Error("expected error for unsupported auth method")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_Close_Nil(t *testing.T) {
|
||||
// Test that Close doesn't panic on a partially initialized client
|
||||
c := &Client{}
|
||||
|
||||
// Should not panic
|
||||
err := c.Close()
|
||||
if err != nil {
|
||||
t.Errorf("Close() error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfig_TokenPathDefault(t *testing.T) {
|
||||
cfg := Config{
|
||||
TokenPath: "",
|
||||
}
|
||||
|
||||
// Default token path should be empty (will be set in authKubernetes)
|
||||
if cfg.TokenPath != "" {
|
||||
t.Errorf("TokenPath = %s, want empty", cfg.TokenPath)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user