ultisuite-backend/internal/mail/rules/engine_test.go
R3D347HR4Y 747e0d4bb4 Add CI workflow and unit tests for mail API
- Created a CI workflow in `.github/workflows/ci.yml` to run Go tests and verify database migrations.
- Added unit tests for the mail API in `internal/api/mail/handlers_test.go`, covering message listing, retrieval, sending, and label updating.
- Introduced a service interface for the mail handler in `internal/api/mail/service_iface.go`.
- Updated mail handler initialization to accept a service API in `internal/api/mail/handlers.go`.
- Implemented test authentication middleware for testing purposes in `internal/api/middleware/testauth.go`.
- Added various test cases for IMAP and SMTP functionalities, ensuring robust error handling and validation.
- Enhanced project documentation with checklist updates for testing and CI integration.
2026-05-22 17:02:37 +02:00

89 lines
2.9 KiB
Go

package rules
import (
"context"
"strings"
"testing"
)
func testMessage() *Message {
return &Message{
ID: "msg-1",
From: "Alice <alice@example.com>",
To: []string{"bob@example.com", "carol@example.com"},
Subject: "Invoice Q1",
BodyText: "Please review the attached invoice.",
HasAttachments: true,
}
}
func TestMatchCondition_fieldsAndOperators(t *testing.T) {
msg := testMessage()
tests := []struct {
name string
cond Condition
match bool
}{
{"from contains", Condition{Field: "from", Operator: "contains", Value: "alice@"}, true},
{"from equals case insensitive", Condition{Field: "from", Operator: "equals", Value: "alice <alice@example.com>"}, true},
{"to contains", Condition{Field: "to", Operator: "contains", Value: "carol@"}, true},
{"subject starts_with", Condition{Field: "subject", Operator: "starts_with", Value: "invoice"}, true},
{"body ends_with", Condition{Field: "body", Operator: "ends_with", Value: "invoice."}, true},
{"has_attachment true", Condition{Field: "has_attachment", Operator: "equals", Value: "true"}, true},
{"has_attachment false", Condition{Field: "has_attachment", Operator: "equals", Value: "false"}, false},
{"not_contains", Condition{Field: "subject", Operator: "not_contains", Value: "spam"}, true},
{"unknown field", Condition{Field: "unknown", Operator: "contains", Value: "x"}, false},
{"unknown operator", Condition{Field: "subject", Operator: "matches", Value: "Invoice"}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := matchCondition(tt.cond, msg); got != tt.match {
t.Fatalf("matchCondition() = %v, want %v", got, tt.match)
}
})
}
}
func TestMatchesAll(t *testing.T) {
msg := testMessage()
t.Run("all match", func(t *testing.T) {
conditions := []Condition{
{Field: "from", Operator: "contains", Value: "alice"},
{Field: "subject", Operator: "contains", Value: "invoice"},
}
if !matchesAll(conditions, msg) {
t.Fatal("matchesAll() = false, want true")
}
})
t.Run("one fails", func(t *testing.T) {
conditions := []Condition{
{Field: "from", Operator: "contains", Value: "alice"},
{Field: "subject", Operator: "equals", Value: "other"},
}
if matchesAll(conditions, msg) {
t.Fatal("matchesAll() = true, want false")
}
})
t.Run("empty conditions", func(t *testing.T) {
if !matchesAll(nil, msg) {
t.Fatal("matchesAll(nil) = false, want true")
}
})
}
func TestExecuteAction_unknownType(t *testing.T) {
e := &Engine{}
err := e.executeAction(context.Background(), Action{Type: "forward", Value: "x@example.com"}, &Message{ID: "msg-1"})
if err == nil {
t.Fatal("executeAction() error = nil, want unknown action type error")
}
if !strings.Contains(err.Error(), "unknown action type: forward") {
t.Fatalf("executeAction() error = %v, want unknown action type", err)
}
}