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) w.Write([]byte("ok")) })) 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 ", } 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")) }