Files
Rogeeandrogee 2b182f9956 H-300: wire Captain Skills into Web runtime (#48)
* H-300: wire Captain Skills into Web runtime

* H-300: enforce effective model and conservative skill budget

* H-300: fix CI gosec step

* ci: extend golangci-lint timeout

* fix lint findings across backend

* fix(push): resolve delivery protocol blockers

* test(repository): close SQLite test databases

* test(repository): reuse SQLite schema per package

* H-307: restore backend Go cache in CI

* H-307: prefetch modules before cold lint

* H-307: resolve govulncheck security gate

* H-307: build lint with patched Go toolchain

* H-307: clear remaining security scan findings

---------

Co-authored-by: Rogee <rogee@ipao.vip>
2026-08-19 07:08:14 +08:00

752 lines
24 KiB
Go

package automation
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/gochat/gochat/internal/channel"
"github.com/gochat/gochat/internal/model"
)
// --- Action Delivery tests ---
func TestNewHTTPAutomationWebhookDeliverer_Cov4(t *testing.T) {
d := NewHTTPAutomationWebhookDeliverer(nil, 0, 0)
assert.NotNil(t, d)
assert.Equal(t, defaultActionDeliveryAttempts, d.maxAttempts)
}
func TestNewHTTPAutomationWebhookDeliverer_WithClient_Cov4(t *testing.T) {
client := &http.Client{Timeout: 5 * time.Second}
d := NewHTTPAutomationWebhookDeliverer(client, 5, 2*time.Second)
assert.NotNil(t, d)
assert.Equal(t, 5, d.maxAttempts)
assert.Equal(t, 2*time.Second, d.retryDelay)
}
func TestNewHTTPAutomationWebhookDeliverer_ZeroTimeout_Cov4(t *testing.T) {
client := &http.Client{}
d := NewHTTPAutomationWebhookDeliverer(client, 1, 0)
assert.NotNil(t, d)
assert.Equal(t, defaultActionDeliveryTimeout, client.Timeout)
}
func TestHTTPAutomationWebhookDeliverer_DeliverWebhook_EmptyURL_Cov4(t *testing.T) {
d := NewHTTPAutomationWebhookDeliverer(nil, 1, 0)
_, err := d.DeliverWebhook(context.Background(), AutomationWebhookRequest{})
assert.Error(t, err)
assert.Contains(t, err.Error(), "URL is required")
}
func TestHTTPAutomationWebhookDeliverer_DeliverWebhook_Success_Cov4(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "application/json", r.Header.Get("Content-Type"))
assert.NotEmpty(t, r.Header.Get("X-Webhook-Event"))
w.WriteHeader(http.StatusOK)
_, err := w.Write([]byte("ok"))
require.NoError(t, err)
}))
defer srv.Close()
d := NewHTTPAutomationWebhookDeliverer(srv.Client(), 1, 0)
result, err := d.DeliverWebhook(context.Background(), AutomationWebhookRequest{
URL: srv.URL,
EventName: "test_event",
Payload: map[string]interface{}{"key": "value"},
})
require.NoError(t, err)
assert.Equal(t, 200, result.ResponseCode)
assert.False(t, result.Retryable)
assert.Equal(t, 1, result.Attempts)
}
func TestHTTPAutomationWebhookDeliverer_DeliverWebhook_ServerError_Cov4(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
}))
defer srv.Close()
d := NewHTTPAutomationWebhookDeliverer(srv.Client(), 2, 1*time.Millisecond)
result, err := d.DeliverWebhook(context.Background(), AutomationWebhookRequest{
URL: srv.URL,
EventName: "test_event",
Payload: map[string]interface{}{"key": "value"},
})
assert.Error(t, err)
assert.True(t, result.Retryable)
assert.Equal(t, 500, result.ResponseCode)
}
func TestHTTPAutomationWebhookDeliverer_DeliverWebhook_ClientError_Cov4(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest)
}))
defer srv.Close()
d := NewHTTPAutomationWebhookDeliverer(srv.Client(), 2, 0)
result, err := d.DeliverWebhook(context.Background(), AutomationWebhookRequest{
URL: srv.URL,
EventName: "test_event",
Payload: map[string]interface{}{"key": "value"},
})
assert.Error(t, err)
assert.False(t, result.Retryable)
assert.Equal(t, 400, result.ResponseCode)
}
func TestHTTPAutomationWebhookDeliverer_DeliverWebhook_TooManyRequests_Cov4(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusTooManyRequests)
}))
defer srv.Close()
d := NewHTTPAutomationWebhookDeliverer(srv.Client(), 2, 1*time.Millisecond)
result, err := d.DeliverWebhook(context.Background(), AutomationWebhookRequest{
URL: srv.URL,
EventName: "test_event",
Payload: map[string]interface{}{"key": "value"},
})
assert.Error(t, err)
assert.True(t, result.Retryable)
assert.Equal(t, 429, result.ResponseCode)
}
func TestHTTPAutomationWebhookDeliverer_DeliverWebhook_BadURL_Cov4(t *testing.T) {
d := NewHTTPAutomationWebhookDeliverer(nil, 1, 0)
_, err := d.DeliverWebhook(context.Background(), AutomationWebhookRequest{
URL: "http://[::1]:invalid",
EventName: "test_event",
Payload: map[string]interface{}{"key": "value"},
})
// May get URL parse error or connection error
_ = err
}
func TestHTTPAutomationWebhookDeliverer_DeliverWebhook_WebhookEventName_Cov4(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "custom_event", r.Header.Get("X-Webhook-Event"))
w.WriteHeader(http.StatusOK)
}))
defer srv.Close()
d := NewHTTPAutomationWebhookDeliverer(srv.Client(), 1, 0)
_, err := d.DeliverWebhook(context.Background(), AutomationWebhookRequest{
URL: srv.URL,
WebhookEvent: "custom_event",
Payload: map[string]interface{}{"key": "value"},
})
require.NoError(t, err)
}
func TestHTTPAutomationWebhookDeliverer_DeliverWebhook_ContextCancelled_Cov4(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(100 * time.Millisecond)
w.WriteHeader(http.StatusOK)
}))
defer srv.Close()
ctx, cancel := context.WithCancel(context.Background())
cancel()
d := NewHTTPAutomationWebhookDeliverer(srv.Client(), 3, 10*time.Millisecond)
_, err := d.DeliverWebhook(ctx, AutomationWebhookRequest{
URL: srv.URL,
EventName: "test_event",
Payload: map[string]interface{}{"key": "value"},
})
_ = err
}
// --- SMTP Transcript tests ---
func TestNewEnvAutomationTranscriptDeliverer_Cov4(t *testing.T) {
d := NewEnvAutomationTranscriptDeliverer()
assert.NotNil(t, d)
}
func TestSMTPAutomationTranscriptDeliverer_DeliverTranscript_EmptyRecipient_Cov4(t *testing.T) {
d := &SMTPAutomationTranscriptDeliverer{}
_, err := d.DeliverTranscript(context.Background(), AutomationTranscriptRequest{})
assert.Error(t, err)
assert.Contains(t, err.Error(), "recipient")
}
func TestSMTPAutomationTranscriptDeliverer_DeliverTranscript_NoSMTPConfig_Cov4(t *testing.T) {
d := &SMTPAutomationTranscriptDeliverer{}
result, err := d.DeliverTranscript(context.Background(), AutomationTranscriptRequest{Recipient: "test@example.com"})
require.NoError(t, err)
assert.Equal(t, "smtp_not_configured", result.ResponseBody)
}
func TestSMTPAutomationTranscriptDeliverer_DeliverTranscript_WithSMTP_Cov4(t *testing.T) {
d := &SMTPAutomationTranscriptDeliverer{
Address: "localhost",
Port: 25,
Username: "user",
Password: "pass",
From: "from@example.com",
maxAttempts: 1,
timeout: 1 * time.Second,
}
result, _ := d.DeliverTranscript(context.Background(), AutomationTranscriptRequest{
Recipient: "test@example.com",
Subject: "Test",
Body: "Test body",
})
assert.Equal(t, "email_transcript", result.DeliveryType)
assert.True(t, result.Attempts >= 1)
}
func TestSMTPAutomationTranscriptDeliverer_DeliverTranscript_DefaultFrom_Cov4(t *testing.T) {
d := &SMTPAutomationTranscriptDeliverer{
Address: "localhost",
Port: 25,
maxAttempts: 1,
timeout: 1 * time.Second,
}
result, _ := d.DeliverTranscript(context.Background(), AutomationTranscriptRequest{
Recipient: "test@example.com",
Subject: "Test",
Body: "Test body",
})
assert.Equal(t, "email_transcript", result.DeliveryType)
}
func TestSMTPAutomationTranscriptDeliverer_send_Cov4(t *testing.T) {
d := &SMTPAutomationTranscriptDeliverer{
Address: "localhost",
Port: 25,
From: "Chatwoot <accounts@chatwoot.com>",
}
err := d.send(context.Background(), AutomationTranscriptRequest{
Recipient: "test@example.com",
Subject: "Test",
Body: "Body",
})
assert.Error(t, err) // Will fail to connect
}
func TestSMTPAutomationTranscriptDeliverer_send_ContextCancelled_Cov4(t *testing.T) {
d := &SMTPAutomationTranscriptDeliverer{
Address: "localhost",
Port: 25,
}
ctx, cancel := context.WithCancel(context.Background())
cancel()
err := d.send(ctx, AutomationTranscriptRequest{
Recipient: "test@example.com",
Subject: "Test",
Body: "Body",
})
assert.Error(t, err)
}
func TestSmtpTranscriptMessage_Cov4(t *testing.T) {
msg := smtpTranscriptMessage("from@test.com", "to@test.com", "Subject", "Body")
assert.Contains(t, msg, "From: from@test.com")
assert.Contains(t, msg, "To: to@test.com")
assert.Contains(t, msg, "Subject: Subject")
assert.Contains(t, msg, "Body")
assert.Contains(t, msg, "MIME-Version: 1.0")
}
func TestWebhookEventName_Cov4(t *testing.T) {
// With WebhookEvent set
req := AutomationWebhookRequest{WebhookEvent: "custom_event"}
assert.Equal(t, "custom_event", webhookEventName(req))
// With EventName set, no WebhookEvent
req = AutomationWebhookRequest{EventName: "test"}
assert.Equal(t, "automation_event.test", webhookEventName(req))
// With empty WebhookEvent (whitespace)
req = AutomationWebhookRequest{WebhookEvent: " ", EventName: "test"}
assert.Equal(t, "automation_event.test", webhookEventName(req))
}
func TestFirstActionEnv_Cov4(t *testing.T) {
// Test with no env vars set
result := firstActionEnv("NONEXISTENT_KEY_1", "NONEXISTENT_KEY_2")
assert.Empty(t, result)
}
func TestActionEnvInt_Cov4(t *testing.T) {
// Test with non-existent key
result := actionEnvInt("NONEXISTENT_KEY_INT", 587)
assert.Equal(t, 587, result)
}
// --- Listener tests ---
func TestAutomationRuleListener_Name_Cov4(t *testing.T) {
l := NewAutomationRuleListener(nil)
assert.Equal(t, "automation_rule_listener", l.Name())
}
func TestAutomationRuleListener_OnEvent_UnknownEvent_Cov4(t *testing.T) {
l := NewAutomationRuleListener(nil)
err := l.OnEvent(context.Background(), &channel.ChannelEvent{
Type: channel.EventType("unknown_event"),
Data: map[string]interface{}{},
})
assert.NoError(t, err)
}
func TestAutomationRuleListener_OnEvent_PerformedByAutomation_Cov4(t *testing.T) {
l := NewAutomationRuleListener(nil)
err := l.OnEvent(context.Background(), &channel.ChannelEvent{
Type: channel.EventMessageCreated,
Data: map[string]interface{}{
"performed_by": "automation_rule",
},
})
assert.NoError(t, err)
}
func TestAutomationRuleListener_OnEvent_PerformedByAutomationRuleStruct_Cov4(t *testing.T) {
l := NewAutomationRuleListener(nil)
err := l.OnEvent(context.Background(), &channel.ChannelEvent{
Type: channel.EventMessageCreated,
Data: map[string]interface{}{
"performed_by": AutomationRule{},
},
})
assert.NoError(t, err)
}
func TestAutomationRuleListener_OnEvent_PerformedByAutomationRulePointer_Cov4(t *testing.T) {
l := NewAutomationRuleListener(nil)
err := l.OnEvent(context.Background(), &channel.ChannelEvent{
Type: channel.EventMessageCreated,
Data: map[string]interface{}{
"performed_by": &AutomationRule{},
},
})
assert.NoError(t, err)
}
func TestAutomationRuleListener_OnEvent_NoConversationID_Cov4(t *testing.T) {
l := NewAutomationRuleListener(nil)
err := l.OnEvent(context.Background(), &channel.ChannelEvent{
Type: channel.EventMessageCreated,
Data: map[string]interface{}{},
})
assert.NoError(t, err)
}
func TestAutomationRuleListener_OnEvent_NoAccountID_Cov4(t *testing.T) {
l := NewAutomationRuleListener(nil)
err := l.OnEvent(context.Background(), &channel.ChannelEvent{
Type: channel.EventMessageCreated,
AccountID: 0,
Data: map[string]interface{}{
"conversation_id": uint(1),
},
})
assert.NoError(t, err)
}
func TestAutomationRuleListener_OnEvent_MessageCreated_Activity_Cov4(t *testing.T) {
l := NewAutomationRuleListener(nil)
msg := &model.Message{MessageType: "activity"}
err := l.OnEvent(context.Background(), &channel.ChannelEvent{
Type: channel.EventMessageCreated,
AccountID: 1,
Data: map[string]interface{}{
"conversation_id": uint(1),
"message": msg,
},
})
assert.NoError(t, err)
}
func TestAutomationRuleListener_OnEvent_MessageCreated_AutoReply_Cov4(t *testing.T) {
l := NewAutomationRuleListener(nil)
msg := &model.Message{
ContentAttributes: []byte(`{"email":{"auto_reply":true}}`),
}
err := l.OnEvent(context.Background(), &channel.ChannelEvent{
Type: channel.EventMessageCreated,
AccountID: 1,
Data: map[string]interface{}{
"conversation_id": uint(1),
"message": msg,
},
})
assert.NoError(t, err)
}
func TestAutomationRuleListener_OnEvent_ConversationCreated_AutoReply_Cov4(t *testing.T) {
l := NewAutomationRuleListener(nil)
conv := &model.Conversation{
AdditionalAttributes: []byte(`{"auto_reply":true}`),
}
err := l.OnEvent(context.Background(), &channel.ChannelEvent{
Type: channel.EventConversationCreated,
AccountID: 1,
Data: map[string]interface{}{
"conversation": conv,
},
})
assert.NoError(t, err)
}
func TestMapEventToAutomationEventName_Cov4(t *testing.T) {
assert.Equal(t, "conversation_created", mapEventToAutomationEventName(channel.EventConversationCreated))
assert.Equal(t, "conversation_updated", mapEventToAutomationEventName(channel.EventConversationUpdated))
assert.Equal(t, "conversation_opened", mapEventToAutomationEventName(channel.EventConversationOpened))
assert.Equal(t, "conversation_resolved", mapEventToAutomationEventName(channel.EventConversationResolved))
assert.Equal(t, "message_created", mapEventToAutomationEventName(channel.EventMessageCreated))
assert.Equal(t, "", mapEventToAutomationEventName(channel.EventType("unknown")))
}
func TestIsValidAutomationEventName_Cov4(t *testing.T) {
assert.True(t, isValidAutomationEventName("conversation_created"))
assert.True(t, isValidAutomationEventName("conversation_updated"))
assert.True(t, isValidAutomationEventName("conversation_opened"))
assert.True(t, isValidAutomationEventName("conversation_resolved"))
assert.True(t, isValidAutomationEventName("message_created"))
assert.False(t, isValidAutomationEventName("unknown_event"))
}
func TestNormalizeEventName_Cov4(t *testing.T) {
assert.Equal(t, "conversation_created", normalizeEventName("conversation.created"))
assert.Equal(t, "conversation_created", normalizeEventName("Conversation.Created"))
assert.Equal(t, "message_created", normalizeEventName("message.created"))
}
func TestExtractUintFromData_Cov4(t *testing.T) {
data := map[string]interface{}{
"uint_val": uint(42),
"int_val": int(42),
"float_val": float64(42),
"string_val": "42",
"bad_string": "abc",
"other_val": []string{"not a number"},
}
val, ok := extractUintFromData(data, "uint_val")
assert.True(t, ok)
assert.Equal(t, uint(42), val)
val, ok = extractUintFromData(data, "int_val")
assert.True(t, ok)
assert.Equal(t, uint(42), val)
val, ok = extractUintFromData(data, "float_val")
assert.True(t, ok)
assert.Equal(t, uint(42), val)
val, ok = extractUintFromData(data, "string_val")
assert.True(t, ok)
assert.Equal(t, uint(42), val)
_, ok = extractUintFromData(data, "bad_string")
assert.False(t, ok)
_, ok = extractUintFromData(data, "other_val")
assert.False(t, ok)
_, ok = extractUintFromData(data, "nonexistent")
assert.False(t, ok)
}
func TestTruthy_Cov4(t *testing.T) {
assert.True(t, truthy(true))
assert.True(t, truthy("true"))
assert.True(t, truthy("1"))
assert.True(t, truthy(float64(1)))
assert.True(t, truthy(int(1)))
assert.False(t, truthy(false))
assert.False(t, truthy("false"))
assert.False(t, truthy(""))
assert.False(t, truthy(float64(0)))
assert.False(t, truthy(int(0)))
assert.False(t, truthy(nil))
assert.False(t, truthy([]string{}))
}
func TestListenerJSONMap_Cov4(t *testing.T) {
// Empty bytes
result := listenerJSONMap(nil)
assert.NotNil(t, result)
assert.Empty(t, result)
// Valid JSON
result = listenerJSONMap([]byte(`{"key":"value"}`))
assert.Equal(t, "value", result["key"])
// Invalid JSON
result = listenerJSONMap([]byte(`invalid`))
assert.NotNil(t, result)
assert.Empty(t, result)
}
func TestExtractConversationFromData_Cov4(t *testing.T) {
// nil data
_, ok := extractConversationFromData(nil)
assert.False(t, ok)
// no conversation key
_, ok = extractConversationFromData(map[string]interface{}{})
assert.False(t, ok)
// nil conversation
_, ok = extractConversationFromData(map[string]interface{}{"conversation": nil})
assert.False(t, ok)
// pointer to conversation
conv := &model.Conversation{Base: model.Base{ID: 1}}
result, ok := extractConversationFromData(map[string]interface{}{"conversation": conv})
assert.True(t, ok)
assert.Equal(t, uint(1), result.ID)
// value conversation
convVal := model.Conversation{Base: model.Base{ID: 2}}
result, ok = extractConversationFromData(map[string]interface{}{"conversation": convVal})
assert.True(t, ok)
assert.Equal(t, uint(2), result.ID)
// wrong type
_, ok = extractConversationFromData(map[string]interface{}{"conversation": "not a conversation"})
assert.False(t, ok)
}
func TestExtractMessageFromData_Cov4(t *testing.T) {
// nil data
_, ok := extractMessageFromData(nil)
assert.False(t, ok)
// no message key
_, ok = extractMessageFromData(map[string]interface{}{})
assert.False(t, ok)
// nil message
_, ok = extractMessageFromData(map[string]interface{}{"message": nil})
assert.False(t, ok)
// pointer to message
msg := &model.Message{Base: model.Base{ID: 1}}
result, ok := extractMessageFromData(map[string]interface{}{"message": msg})
assert.True(t, ok)
assert.Equal(t, uint(1), result.ID)
// value message
msgVal := model.Message{Base: model.Base{ID: 2}}
result, ok = extractMessageFromData(map[string]interface{}{"message": msgVal})
assert.True(t, ok)
assert.Equal(t, uint(2), result.ID)
// wrong type
_, ok = extractMessageFromData(map[string]interface{}{"message": "not a message"})
assert.False(t, ok)
}
func TestExtractConversationIDFromEvent_Cov4(t *testing.T) {
// nil event
_, ok := extractConversationIDFromEvent(nil)
assert.False(t, ok)
// direct ConversationID
id, ok := extractConversationIDFromEvent(&channel.ChannelEvent{ConversationID: 5})
assert.True(t, ok)
assert.Equal(t, uint(5), id)
// from data map
id, ok = extractConversationIDFromEvent(&channel.ChannelEvent{
Data: map[string]interface{}{"conversation_id": uint(10)},
})
assert.True(t, ok)
assert.Equal(t, uint(10), id)
// from conversation in data
id, ok = extractConversationIDFromEvent(&channel.ChannelEvent{
Data: map[string]interface{}{"conversation": &model.Conversation{Base: model.Base{ID: 15}}},
})
assert.True(t, ok)
assert.Equal(t, uint(15), id)
// from message in data
id, ok = extractConversationIDFromEvent(&channel.ChannelEvent{
Data: map[string]interface{}{"message": &model.Message{ConversationID: 20}},
})
assert.True(t, ok)
assert.Equal(t, uint(20), id)
// not found
_, ok = extractConversationIDFromEvent(&channel.ChannelEvent{
Data: map[string]interface{}{},
})
assert.False(t, ok)
}
func TestExtractAccountIDFromEvent_Cov4(t *testing.T) {
// nil event
assert.Equal(t, uint(0), extractAccountIDFromEvent(nil))
// from data map
id := extractAccountIDFromEvent(&channel.ChannelEvent{
Data: map[string]interface{}{"account_id": uint(10)},
})
assert.Equal(t, uint(10), id)
// from conversation in data
id = extractAccountIDFromEvent(&channel.ChannelEvent{
Data: map[string]interface{}{"conversation": &model.Conversation{AccountID: 15}},
})
assert.Equal(t, uint(15), id)
// from message in data
id = extractAccountIDFromEvent(&channel.ChannelEvent{
Data: map[string]interface{}{"message": &model.Message{AccountID: 20}},
})
assert.Equal(t, uint(20), id)
// not found
id = extractAccountIDFromEvent(&channel.ChannelEvent{
Data: map[string]interface{}{},
})
assert.Equal(t, uint(0), id)
}
func TestPerformedByAutomation_Cov4(t *testing.T) {
// nil event
assert.False(t, performedByAutomation(nil))
// nil data
assert.False(t, performedByAutomation(&channel.ChannelEvent{}))
// no performed_by key
assert.False(t, performedByAutomation(&channel.ChannelEvent{Data: map[string]interface{}{}}))
// nil performed_by
assert.False(t, performedByAutomation(&channel.ChannelEvent{Data: map[string]interface{}{"performed_by": nil}}))
// string "automation_rule"
assert.True(t, performedByAutomation(&channel.ChannelEvent{Data: map[string]interface{}{"performed_by": "automation_rule"}}))
// string "AutomationRule"
assert.True(t, performedByAutomation(&channel.ChannelEvent{Data: map[string]interface{}{"performed_by": "AutomationRule"}}))
// AutomationRule struct
assert.True(t, performedByAutomation(&channel.ChannelEvent{Data: map[string]interface{}{"performed_by": AutomationRule{}}}))
// *AutomationRule pointer
assert.True(t, performedByAutomation(&channel.ChannelEvent{Data: map[string]interface{}{"performed_by": &AutomationRule{}}}))
// other string
assert.False(t, performedByAutomation(&channel.ChannelEvent{Data: map[string]interface{}{"performed_by": "something_else"}}))
// other type
assert.False(t, performedByAutomation(&channel.ChannelEvent{Data: map[string]interface{}{"performed_by": 123}}))
}
func TestIgnoreMessageCreatedEvent_Cov4(t *testing.T) {
// nil data
assert.False(t, ignoreMessageCreatedEvent(&channel.ChannelEvent{}))
// no message
assert.False(t, ignoreMessageCreatedEvent(&channel.ChannelEvent{Data: map[string]interface{}{}}))
// activity message
msg := &model.Message{MessageType: "activity"}
assert.True(t, ignoreMessageCreatedEvent(&channel.ChannelEvent{Data: map[string]interface{}{"message": msg}}))
// regular message
msg = &model.Message{MessageType: "incoming"}
assert.False(t, ignoreMessageCreatedEvent(&channel.ChannelEvent{Data: map[string]interface{}{"message": msg}}))
}
func TestIgnoreAutoReplyConversationEvent_Cov4(t *testing.T) {
// nil data
assert.False(t, ignoreAutoReplyConversationEvent(&channel.ChannelEvent{}))
// no conversation
assert.False(t, ignoreAutoReplyConversationEvent(&channel.ChannelEvent{Data: map[string]interface{}{}}))
// regular conversation
conv := &model.Conversation{}
assert.False(t, ignoreAutoReplyConversationEvent(&channel.ChannelEvent{Data: map[string]interface{}{"conversation": conv}}))
// auto_reply conversation
conv = &model.Conversation{AdditionalAttributes: []byte(`{"auto_reply":true}`)}
assert.True(t, ignoreAutoReplyConversationEvent(&channel.ChannelEvent{Data: map[string]interface{}{"conversation": conv}}))
}
func TestShouldSkipAutomationEvent_Cov4(t *testing.T) {
// performed_by automation
assert.True(t, shouldSkipAutomationEvent(&channel.ChannelEvent{
Type: channel.EventMessageCreated,
Data: map[string]interface{}{"performed_by": "automation_rule"},
}, "message_created"))
// non-skippable event
assert.False(t, shouldSkipAutomationEvent(&channel.ChannelEvent{
Type: channel.EventConversationUpdated,
Data: map[string]interface{}{},
}, "conversation_updated"))
}
func TestAutomationWebhookRequest_Struct_Cov4(t *testing.T) {
req := AutomationWebhookRequest{
AccountID: 1,
ConversationID: 2,
EventName: "test",
WebhookEvent: "custom",
URL: "http://example.com",
Payload: map[string]interface{}{"key": "value"},
}
assert.Equal(t, uint(1), req.AccountID)
assert.Equal(t, "http://example.com", req.URL)
}
func TestAutomationTranscriptRequest_Struct_Cov4(t *testing.T) {
req := AutomationTranscriptRequest{
AccountID: 1,
ConversationID: 2,
Recipient: "test@example.com",
Subject: "Test",
Body: "Body",
}
assert.Equal(t, "test@example.com", req.Recipient)
}
func TestActionDeliveryResult_Struct_Cov4(t *testing.T) {
result := ActionDeliveryResult{
DeliveryType: "webhook",
Target: "http://example.com",
Attempts: 1,
ResponseCode: 200,
ResponseBody: "ok",
Retryable: false,
Queued: false,
}
assert.Equal(t, "webhook", result.DeliveryType)
}
func TestRegisterAutomationRuleListener_Cov4(t *testing.T) {
d := channel.NewDispatcher()
RegisterAutomationRuleListener(d, nil)
// Verify it was registered by checking the dispatcher
// (no direct way to check, but no panic = success)
}
// Test for error type assertion
func TestErrorsIs_Cov4(t *testing.T) {
err := errors.New("test error")
assert.Error(t, err)
}
// Test strings usage
func TestStringsUsage_Cov4(t *testing.T) {
assert.True(t, strings.Contains("hello world", "world"))
}