mirror of
https://github.com/StarFleetCPTN/GoMFT.git
synced 2026-09-08 15:41:20 +02:00
feat: Enhance notification service configuration and refactor related components
- Updated notification service models to use pointers for boolean fields, allowing for better handling of enabled states. - Introduced helper methods for getting and setting enabled states in notification and auth provider models. - Refactored notification form templates to consolidate event trigger handling, improving code maintainability. - Added SSL verification configuration to the application settings, allowing users to skip SSL verification for outgoing notifications. - Enhanced the notification sending logic to respect the SSL verification setting. - Introduced new migration to alter boolean defaults in the database schema for better compatibility with the updated models. - Added unit tests for email and Rclone service functionalities to ensure reliability.
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
package email
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/starfleetcptn/gomft/internal/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func createTestConfig(enabled bool) *config.Config {
|
||||
return &config.Config{
|
||||
BaseURL: "http://localhost:8080",
|
||||
Email: config.EmailConfig{
|
||||
Enabled: enabled,
|
||||
Host: "smtp.example.com",
|
||||
Port: 587,
|
||||
Username: "user",
|
||||
Password: "password",
|
||||
FromEmail: "noreply@example.com",
|
||||
FromName: "GoMFT Test",
|
||||
RequireAuth: true,
|
||||
EnableTLS: true,
|
||||
ReplyTo: "support@example.com",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewService(t *testing.T) {
|
||||
cfg := createTestConfig(true)
|
||||
service := NewService(cfg)
|
||||
require.NotNil(t, service)
|
||||
assert.Equal(t, cfg, service.Config)
|
||||
}
|
||||
|
||||
func TestGeneratePasswordResetEmailHTML(t *testing.T) {
|
||||
cfg := createTestConfig(true)
|
||||
service := NewService(cfg)
|
||||
|
||||
testUsername := "testuser"
|
||||
testResetLink := "http://localhost:8080/reset-password?token=testtoken123"
|
||||
testAppName := "GoMFT"
|
||||
testYear := time.Now().Year()
|
||||
|
||||
data := map[string]interface{}{
|
||||
"Username": testUsername,
|
||||
"ResetLink": testResetLink,
|
||||
"AppName": testAppName,
|
||||
"Year": testYear,
|
||||
"ExpiresHours": 0.25,
|
||||
}
|
||||
|
||||
htmlContent, err := service.generatePasswordResetEmailHTML(data)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, htmlContent)
|
||||
|
||||
// Basic checks for content presence
|
||||
assert.Contains(t, htmlContent, "Reset Your Password")
|
||||
assert.Contains(t, htmlContent, fmt.Sprintf("Hello %s", testUsername))
|
||||
assert.Contains(t, htmlContent, testResetLink) // Check link appears (both in button and text)
|
||||
assert.Contains(t, htmlContent, fmt.Sprintf("href=\"%s\"", testResetLink))
|
||||
assert.Contains(t, htmlContent, fmt.Sprintf("© %d %s", testYear, testAppName))
|
||||
assert.Contains(t, htmlContent, "This link will expire in 15 minutes.")
|
||||
|
||||
// Test without username
|
||||
dataNoUser := map[string]interface{}{
|
||||
"ResetLink": testResetLink,
|
||||
"AppName": testAppName,
|
||||
"Year": testYear,
|
||||
"ExpiresHours": 0.25,
|
||||
}
|
||||
htmlContentNoUser, err := service.generatePasswordResetEmailHTML(dataNoUser)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, htmlContentNoUser, "Hello,") // Should just say Hello,
|
||||
assert.NotContains(t, htmlContentNoUser, fmt.Sprintf("Hello %s", testUsername))
|
||||
}
|
||||
|
||||
func TestGenerateTestEmailHTML(t *testing.T) {
|
||||
cfg := createTestConfig(true)
|
||||
service := NewService(cfg)
|
||||
|
||||
testSubject := "My Test Subject"
|
||||
testMessage := "This is the test message body."
|
||||
testAppName := "GoMFT"
|
||||
testYear := time.Now().Year()
|
||||
testCurrentTime := time.Now().Format(time.RFC1123Z) // Use the same format
|
||||
|
||||
data := map[string]interface{}{
|
||||
"Subject": testSubject,
|
||||
"Message": testMessage,
|
||||
"AppName": testAppName,
|
||||
"Year": testYear,
|
||||
"SMTPServer": cfg.Email.Host,
|
||||
"SMTPPort": cfg.Email.Port,
|
||||
"FromEmail": cfg.Email.FromEmail,
|
||||
"CurrentTime": testCurrentTime,
|
||||
}
|
||||
|
||||
htmlContent, err := service.generateTestEmailHTML(data)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, htmlContent)
|
||||
|
||||
// Basic checks for content presence
|
||||
assert.Contains(t, htmlContent, fmt.Sprintf("<title>%s</title>", testSubject))
|
||||
assert.Contains(t, htmlContent, fmt.Sprintf("<h1>%s</h1>", testSubject))
|
||||
assert.Contains(t, htmlContent, testMessage)
|
||||
assert.Contains(t, htmlContent, fmt.Sprintf("%s:%d", cfg.Email.Host, cfg.Email.Port))
|
||||
assert.Contains(t, htmlContent, cfg.Email.FromEmail)
|
||||
assert.Contains(t, htmlContent, testCurrentTime)
|
||||
assert.Contains(t, htmlContent, fmt.Sprintf("© %d %s", testYear, testAppName))
|
||||
}
|
||||
|
||||
func TestSendPasswordResetEmail_Disabled(t *testing.T) {
|
||||
cfg := createTestConfig(false) // Email disabled
|
||||
service := NewService(cfg)
|
||||
|
||||
toEmail := "test@example.com"
|
||||
username := "testuser"
|
||||
resetToken := "disabledtoken123"
|
||||
|
||||
err := service.SendPasswordResetEmail(toEmail, username, resetToken)
|
||||
require.Error(t, err)
|
||||
|
||||
expectedErrorSubstr := fmt.Sprintf("email service is disabled, reset link would be: %s/reset-password?token=%s",
|
||||
cfg.BaseURL, resetToken)
|
||||
assert.Contains(t, err.Error(), expectedErrorSubstr)
|
||||
}
|
||||
|
||||
func TestSendTestEmail_Disabled(t *testing.T) {
|
||||
cfg := createTestConfig(false) // Email disabled
|
||||
service := NewService(cfg)
|
||||
|
||||
toEmail := "test@example.com"
|
||||
|
||||
err := service.SendTestEmail(toEmail, "Test Subject", "Test Message")
|
||||
require.Error(t, err)
|
||||
assert.EqualError(t, err, "email service is disabled")
|
||||
}
|
||||
|
||||
// --- Placeholder/TODO for more complex tests ---
|
||||
|
||||
// TODO: TestSendPasswordResetEmail_Enabled - Requires mocking sendEmail or SMTP interactions
|
||||
// TODO: TestSendTestEmail_Enabled - Requires mocking sendEmail or SMTP interactions
|
||||
// TODO: TestSendEmail - Requires extensive mocking of net/smtp package
|
||||
|
||||
// Example structure for testing enabled path (without actual sending/mocking)
|
||||
// This verifies the function prepares the correct data before calling sendEmail
|
||||
func TestSendPasswordResetEmail_Enabled_DataPreparation(t *testing.T) {
|
||||
cfg := createTestConfig(true)
|
||||
service := NewService(cfg)
|
||||
|
||||
// We need a way to intercept the call to sendEmail or verify its inputs
|
||||
// For now, we just check that no error occurs up to that point
|
||||
// and that the HTML generation works (implicitly tested by TestGeneratePasswordResetEmailHTML)
|
||||
|
||||
toEmail := "recipient@example.com"
|
||||
username := "testuser-enabled"
|
||||
resetToken := "enabledtoken456"
|
||||
|
||||
// If generatePasswordResetEmailHTML works, this call should proceed
|
||||
// without error until the actual sendEmail call (which we aren't testing here)
|
||||
// A full test would mock sendEmail and verify the arguments passed to it.
|
||||
err := service.SendPasswordResetEmail(toEmail, username, resetToken)
|
||||
|
||||
// In a real scenario without mocking, this might fail if SMTP connection fails.
|
||||
// For this basic check, we assume HTML generation is the main potential failure point *before* sendEmail.
|
||||
// If TestGeneratePasswordResetEmailHTML passes, we expect no error *from generation*.
|
||||
// We cannot assert assert.NoError(t, err) reliably without mocking sendEmail.
|
||||
t.Logf("SendPasswordResetEmail (enabled) returned: %v (expected success or SMTP error)", err)
|
||||
// Asserting that the error, if any, is NOT related to template generation could be a weak check.
|
||||
if err != nil {
|
||||
assert.False(t, strings.Contains(err.Error(), "template"), "Error should be SMTP related, not template related")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendTestEmail_Enabled_DataPreparation(t *testing.T) {
|
||||
cfg := createTestConfig(true)
|
||||
service := NewService(cfg)
|
||||
|
||||
toEmail := "recipient@example.com"
|
||||
subject := "Specific Test Subject"
|
||||
message := "Specific test message."
|
||||
|
||||
// Test with specific subject and message
|
||||
err := service.SendTestEmail(toEmail, subject, message)
|
||||
t.Logf("SendTestEmail (enabled, specific) returned: %v (expected success or SMTP error)", err)
|
||||
if err != nil {
|
||||
assert.False(t, strings.Contains(err.Error(), "template"), "Error should be SMTP related, not template related")
|
||||
}
|
||||
|
||||
// Test with default subject and message
|
||||
errDefault := service.SendTestEmail(toEmail, "", "")
|
||||
t.Logf("SendTestEmail (enabled, default) returned: %v (expected success or SMTP error)", errDefault)
|
||||
if errDefault != nil {
|
||||
assert.False(t, strings.Contains(errDefault.Error(), "template"), "Error should be SMTP related, not template related")
|
||||
}
|
||||
// A full test would mock sendEmail and verify the subject/message passed (checking defaults).
|
||||
}
|
||||
Reference in New Issue
Block a user