From 56981405f019966bf8bb7e39aaed9d0d0732613c Mon Sep 17 00:00:00 2001 From: Asif Mohammad Mollah Date: Wed, 5 Nov 2025 12:03:18 +0400 Subject: [PATCH] provider setup test added for invalid inputs --- providers/discord.go | 6 + providers/google.go | 6 + providers/gotify.go | 9 + providers/provider_test.go | 338 +++++++++++++++++++++++++++++++++++-- providers/redis.go | 9 + providers/slack.go | 9 + providers/smtp.go | 21 +++ providers/telegram.go | 9 + 8 files changed, 393 insertions(+), 14 deletions(-) diff --git a/providers/discord.go b/providers/discord.go index 1ef8eb8..09d71af 100644 --- a/providers/discord.go +++ b/providers/discord.go @@ -47,6 +47,12 @@ func (agent *DiscordProvider) Reply(threadId string, message string, option mode } func (agent *DiscordProvider) setup(env *config.Config) error { + if env == nil { + return fmt.Errorf("config is required") + } + if env.WebHookURL == "" { + return fmt.Errorf("webhook_url is required for Discord provider") + } agent.config = env return nil } diff --git a/providers/google.go b/providers/google.go index 622f731..305a414 100644 --- a/providers/google.go +++ b/providers/google.go @@ -66,6 +66,12 @@ func (agent *GoogleProvider) Reply(threadId string, message string, option model } func (agent *GoogleProvider) setup(env *config.Config) error { + if env == nil { + return fmt.Errorf("config is required") + } + if env.WebHookURL == "" { + return fmt.Errorf("webhook_url is required for Google provider") + } agent.config = env return nil } diff --git a/providers/gotify.go b/providers/gotify.go index 73cd168..92ae81a 100644 --- a/providers/gotify.go +++ b/providers/gotify.go @@ -67,6 +67,15 @@ func (agent *GotifyProvider) Reply(threadId string, message string, option model } func (agent *GotifyProvider) setup(env *config.Config) error { + if env == nil { + return fmt.Errorf("config is required") + } + if env.GotifyURL == "" { + return fmt.Errorf("gotify_url is required for Gotify provider") + } + if env.GotifyToken == "" { + return fmt.Errorf("gotify_token is required for Gotify provider") + } agent.config = env return nil } diff --git a/providers/provider_test.go b/providers/provider_test.go index d948df1..54c5572 100644 --- a/providers/provider_test.go +++ b/providers/provider_test.go @@ -224,30 +224,38 @@ func TestSlackProvider_Reply(t *testing.T) { func TestNewProvider(t *testing.T) { tests := []struct { name string - provider string + config *config.Config expectError bool }{ { - name: "valid slack provider", - provider: "slack", - expectError: false, // Slack provider should be registered + name: "valid slack provider", + config: &config.Config{ + Provider: "slack", + Token: "test-token", + ChannelId: "C1234567890", + }, + expectError: false, }, { - name: "valid discord provider", - provider: "discord", + name: "valid discord provider", + config: &config.Config{ + Provider: "discord", + WebHookURL: "https://discord.com/api/webhooks/test", + }, expectError: false, }, { - name: "invalid provider", - provider: "invalid", + name: "invalid provider", + config: &config.Config{ + Provider: "invalid", + }, expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - cfg := &config.Config{Provider: tt.provider} - provider, err := NewProvider(cfg) + provider, err := NewProvider(tt.config) if tt.expectError { if err == nil { @@ -385,24 +393,24 @@ func TestSlackProvider_Setup(t *testing.T) { config: &config.Config{ ChannelId: "C1234567890", }, - expectError: false, // Slack provider doesn't validate config in setup + expectError: true, }, { name: "missing channel", config: &config.Config{ Token: "test-token", }, - expectError: false, // Slack provider doesn't validate config in setup + expectError: true, }, { name: "nil config", config: nil, - expectError: false, // Slack provider doesn't validate config in setup + expectError: true, }, { name: "empty config", config: &config.Config{}, - expectError: false, + expectError: true, }, } @@ -426,6 +434,308 @@ func TestSlackProvider_Setup(t *testing.T) { } } +func TestDiscordProvider_Post(t *testing.T) { + tests := []struct { + name string + message string + mockResponse interface{} + mockStatusCode int + expectError bool + mockTransportError error + }{ + { + name: "successful post", + message: "test message", + mockResponse: `{"ok": true}`, + mockStatusCode: http.StatusOK, + expectError: false, + }, + { + name: "discord api error", + message: "test message", + mockResponse: `{"message": "Invalid webhook"}`, + mockStatusCode: http.StatusBadRequest, + expectError: false, // HTTP call succeeds, but API returns error + }, + { + name: "network connection error", + message: "test message", + mockTransportError: &http.ProtocolError{ErrorString: "connection refused"}, + expectError: true, + }, + { + name: "empty message", + message: "", + mockResponse: `{"ok": true}`, + mockStatusCode: http.StatusOK, + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockTransport := &MockTransport{ + RoundTripFunc: func(req *http.Request) (*http.Response, error) { + if tt.mockTransportError != nil { + return nil, tt.mockTransportError + } + + if tt.name != "network connection error" { + if req.Method != "POST" { + t.Errorf("expected POST request, got %s", req.Method) + } + if req.Header.Get("Content-Type") != "application/json" { + t.Errorf("expected application/json, got %s", req.Header.Get("Content-Type")) + } + } + + var body bytes.Buffer + if tt.mockResponse != nil { + switch resp := tt.mockResponse.(type) { + case string: + body.WriteString(resp) + } + } + + return &http.Response{ + StatusCode: tt.mockStatusCode, + Body: io.NopCloser(&body), + Header: make(http.Header), + }, nil + }, + } + + originalClient := http.DefaultClient + http.DefaultClient = &http.Client{Transport: mockTransport} + defer func() { http.DefaultClient = originalClient }() + + cfg := &config.Config{ + WebHookURL: "https://discord.com/api/webhooks/test", + } + provider := &DiscordProvider{config: cfg} + + option := models.Option{} + result, err := provider.Post(tt.message, option) + + if tt.expectError { + if err == nil { + t.Error("expected error but got none") + } + } else { + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if result == nil { + t.Error("expected result but got nil") + } + } + }) + } +} + +func TestDiscordProvider_Setup(t *testing.T) { + tests := []struct { + name string + config *config.Config + expectError bool + }{ + { + name: "valid discord config", + config: &config.Config{ + WebHookURL: "https://discord.com/api/webhooks/test", + }, + expectError: false, + }, + { + name: "missing webhook url", + config: &config.Config{}, + expectError: true, + }, + { + name: "nil config", + config: nil, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + provider := &DiscordProvider{} + err := provider.setup(tt.config) + + if tt.expectError && err == nil { + t.Error("expected error but got none") + } + if !tt.expectError && err != nil { + t.Errorf("unexpected error: %v", err) + } + + if !tt.expectError && tt.config != nil && provider.config != tt.config { + t.Error("config was not set properly") + } + }) + } +} + +func TestTelegramProvider_Post(t *testing.T) { + tests := []struct { + name string + message string + mockResponse interface{} + mockStatusCode int + expectError bool + mockTransportError error + }{ + { + name: "successful post", + message: "test message", + mockResponse: `{"ok": true}`, + mockStatusCode: http.StatusOK, + expectError: false, + }, + { + name: "telegram api error", + message: "test message", + mockResponse: `{"ok": false, "description": "Bad Request"}`, + mockStatusCode: http.StatusOK, + expectError: false, + }, + { + name: "network connection error", + message: "test message", + mockTransportError: &http.ProtocolError{ErrorString: "connection refused"}, + expectError: true, + }, + { + name: "empty message", + message: "", + mockResponse: `{"ok": true}`, + mockStatusCode: http.StatusOK, + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockTransport := &MockTransport{ + RoundTripFunc: func(req *http.Request) (*http.Response, error) { + if tt.mockTransportError != nil { + return nil, tt.mockTransportError + } + + if tt.name != "network connection error" { + if req.Method != "POST" { + t.Errorf("expected POST request, got %s", req.Method) + } + if req.Header.Get("Content-Type") != "application/json" { + t.Errorf("expected application/json, got %s", req.Header.Get("Content-Type")) + } + } + + var body bytes.Buffer + if tt.mockResponse != nil { + switch resp := tt.mockResponse.(type) { + case string: + body.WriteString(resp) + } + } + + return &http.Response{ + StatusCode: tt.mockStatusCode, + Body: io.NopCloser(&body), + Header: make(http.Header), + }, nil + }, + } + + originalClient := http.DefaultClient + http.DefaultClient = &http.Client{Transport: mockTransport} + defer func() { http.DefaultClient = originalClient }() + + cfg := &config.Config{ + Token: "test-token", + ChatId: "123456789", + } + provider := &TelegramProvider{config: cfg} + + option := models.Option{} + result, err := provider.Post(tt.message, option) + + if tt.expectError { + if err == nil { + t.Error("expected error but got none") + } + } else { + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if result == nil { + t.Error("expected result but got nil") + } + } + }) + } +} + +func TestTelegramProvider_Setup(t *testing.T) { + tests := []struct { + name string + config *config.Config + expectError bool + }{ + { + name: "valid telegram config", + config: &config.Config{ + Token: "test-token", + ChatId: "123456789", + }, + expectError: false, + }, + { + name: "missing token", + config: &config.Config{ + ChatId: "123456789", + }, + expectError: true, + }, + { + name: "missing chat id", + config: &config.Config{ + Token: "test-token", + }, + expectError: true, + }, + { + name: "nil config", + config: nil, + expectError: true, + }, + { + name: "empty config", + config: &config.Config{}, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + provider := &TelegramProvider{} + err := provider.setup(tt.config) + + if tt.expectError && err == nil { + t.Error("expected error but got none") + } + if !tt.expectError && err != nil { + t.Errorf("unexpected error: %v", err) + } + + if !tt.expectError && tt.config != nil && provider.config != tt.config { + t.Error("config was not set properly") + } + }) + } +} + // Helper functions for creating pointers func stringPtr(s string) *string { return &s diff --git a/providers/redis.go b/providers/redis.go index dbc68d8..17c8af5 100644 --- a/providers/redis.go +++ b/providers/redis.go @@ -43,6 +43,15 @@ func (agent *RedisProvider) Reply(threadId string, message string, option models } func (agent *RedisProvider) setup(env *config.Config) error { + if env == nil { + return fmt.Errorf("config is required") + } + if env.ConnectionURL == "" { + return fmt.Errorf("connection_url is required for Redis provider") + } + if env.ChannelId == "" { + return fmt.Errorf("channel_id is required for Redis provider") + } agent.config = env return nil } diff --git a/providers/slack.go b/providers/slack.go index 6bd5855..bd4346c 100644 --- a/providers/slack.go +++ b/providers/slack.go @@ -68,6 +68,15 @@ func (agent *SlackProvider) Reply(threadId string, message string, option models } func (agent *SlackProvider) setup(env *config.Config) error { + if env == nil { + return fmt.Errorf("config is required") + } + if env.Token == "" { + return fmt.Errorf("token is required for Slack provider") + } + if env.ChannelId == "" { + return fmt.Errorf("channel_id is required for Slack provider") + } agent.config = env return nil } diff --git a/providers/smtp.go b/providers/smtp.go index 2204ad6..b577d4c 100644 --- a/providers/smtp.go +++ b/providers/smtp.go @@ -148,6 +148,27 @@ func (agent *SMTPProvider) Reply(threadId string, message string, option models. } func (agent *SMTPProvider) setup(env *config.Config) error { + if env == nil { + return fmt.Errorf("config is required") + } + if env.SMTPHost == "" { + return fmt.Errorf("smtp_host is required for SMTP provider") + } + if env.SMTPPort == "" { + return fmt.Errorf("smtp_port is required for SMTP provider") + } + if env.SMTPUser == "" { + return fmt.Errorf("smtp_user is required for SMTP provider") + } + if env.SMTPPassword == "" { + return fmt.Errorf("smtp_password is required for SMTP provider") + } + if env.SMTPFrom == "" && env.SMTPUser == "" { + return fmt.Errorf("smtp_from or smtp_user is required for SMTP provider") + } + if env.SMTPTo == "" { + return fmt.Errorf("smtp_to is required for SMTP provider") + } agent.config = env return nil } diff --git a/providers/telegram.go b/providers/telegram.go index 8ff199c..22f2f4b 100644 --- a/providers/telegram.go +++ b/providers/telegram.go @@ -72,6 +72,15 @@ func (agent *TelegramProvider) Reply(threadId string, message string, option mod } func (agent *TelegramProvider) setup(env *config.Config) error { + if env == nil { + return fmt.Errorf("config is required") + } + if env.Token == "" { + return fmt.Errorf("token is required for Telegram provider") + } + if env.ChatId == "" { + return fmt.Errorf("chat_id is required for Telegram provider") + } agent.config = env return nil }