- 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.
89 lines
2.9 KiB
Go
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)
|
|
}
|
|
}
|