feat(search): index provider webhooks
This commit is contained in:
@@ -35,6 +35,27 @@ type recordingListener struct {
|
||||
events []*channel.ChannelEvent
|
||||
}
|
||||
|
||||
type recordingIncomingSearchIndexer struct {
|
||||
contacts []model.Contact
|
||||
conversations []model.Conversation
|
||||
messages []model.Message
|
||||
}
|
||||
|
||||
func (r *recordingIncomingSearchIndexer) IndexContact(ctx context.Context, contact *model.Contact) error {
|
||||
r.contacts = append(r.contacts, *contact)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *recordingIncomingSearchIndexer) IndexConversation(ctx context.Context, conversation *model.Conversation) error {
|
||||
r.conversations = append(r.conversations, *conversation)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *recordingIncomingSearchIndexer) IndexMessage(ctx context.Context, message *model.Message) error {
|
||||
r.messages = append(r.messages, *message)
|
||||
return nil
|
||||
}
|
||||
|
||||
type webhookAutomationDBProvider struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
@@ -175,8 +196,9 @@ func TestIncomingPersisterQueuesMessageStatusUpdateWithWorker(t *testing.T) {
|
||||
dispatcher := channel.NewDispatcher()
|
||||
listener := &recordingListener{}
|
||||
dispatcher.Register(listener)
|
||||
indexer := &recordingIncomingSearchIndexer{}
|
||||
wp := worker.NewWorkerPoolWithOptions(db, worker.WithQueues("low"))
|
||||
persister := NewIncomingPersister(db, dispatcher)
|
||||
persister := NewIncomingPersister(db, dispatcher).SetSearchIndexer(indexer)
|
||||
|
||||
msg := &channel.IncomingMessage{
|
||||
ChannelType: channel.ChannelTelegram,
|
||||
@@ -232,6 +254,9 @@ func TestIncomingPersisterQueuesMessageStatusUpdateWithWorker(t *testing.T) {
|
||||
if !listenerSaw(listener, channel.EventMessageStatusUpdated) {
|
||||
t.Fatalf("expected message.status_updated event, got %#v", listener.events)
|
||||
}
|
||||
if len(indexer.messages) != 2 || indexer.messages[1].ID != updated.ID || indexer.messages[1].Status != string(model.MessageStatusDelivered) {
|
||||
t.Fatalf("expected delivered message to be indexed, got %#v", indexer.messages)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIncomingPersisterStatusJobDoesNotDowngradeRead(t *testing.T) {
|
||||
@@ -250,7 +275,8 @@ func TestIncomingPersisterStatusJobDoesNotDowngradeRead(t *testing.T) {
|
||||
t.Fatalf("create message: %v", err)
|
||||
}
|
||||
wp := worker.NewWorkerPoolWithOptions(db, worker.WithQueues("low"))
|
||||
persister := NewIncomingPersister(db).SetWorkerPool(wp)
|
||||
indexer := &recordingIncomingSearchIndexer{}
|
||||
persister := NewIncomingPersister(db).SetSearchIndexer(indexer).SetWorkerPool(wp)
|
||||
|
||||
if err := persister.UpdateMessageStatus(t.Context(), &inbox, "provider-read-1", model.MessageStatusDelivered, nil); err != nil {
|
||||
t.Fatalf("enqueue downgrade: %v", err)
|
||||
@@ -330,7 +356,8 @@ func TestIncomingPersisterQueuesContactMessagesStatusUpdateWithWorker(t *testing
|
||||
alreadyRead := createWebhookStatusMessage(t, db, inbox, conversation, "read-before", model.MessageStatusRead, cutoff.Add(-20*time.Second))
|
||||
afterCutoff := createWebhookStatusMessage(t, db, inbox, conversation, "sent-after", model.MessageStatusSent, cutoff.Add(time.Minute))
|
||||
wp := worker.NewWorkerPoolWithOptions(db, worker.WithQueues("low"))
|
||||
persister := NewIncomingPersister(db).SetWorkerPool(wp)
|
||||
indexer := &recordingIncomingSearchIndexer{}
|
||||
persister := NewIncomingPersister(db).SetSearchIndexer(indexer).SetWorkerPool(wp)
|
||||
|
||||
if err := persister.UpdateContactConversationMessagesStatus(t.Context(), &inbox, "meta-user-1", model.MessageStatusRead, &cutoff); err != nil {
|
||||
t.Fatalf("enqueue contact read: %v", err)
|
||||
@@ -355,6 +382,9 @@ func TestIncomingPersisterQueuesContactMessagesStatusUpdateWithWorker(t *testing
|
||||
if deliveryCount != 3 {
|
||||
t.Fatalf("expected 3 read delivery statuses, got %d", deliveryCount)
|
||||
}
|
||||
if len(indexer.messages) != 3 {
|
||||
t.Fatalf("expected 3 updated messages to be indexed, got %#v", indexer.messages)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIncomingPersisterCreatesConversationMessageAndDedupes(t *testing.T) {
|
||||
@@ -363,7 +393,8 @@ func TestIncomingPersisterCreatesConversationMessageAndDedupes(t *testing.T) {
|
||||
dispatcher := channel.NewDispatcher()
|
||||
listener := &recordingListener{}
|
||||
dispatcher.Register(listener)
|
||||
persister := NewIncomingPersister(db, dispatcher)
|
||||
indexer := &recordingIncomingSearchIndexer{}
|
||||
persister := NewIncomingPersister(db, dispatcher).SetSearchIndexer(indexer)
|
||||
|
||||
msg := &channel.IncomingMessage{
|
||||
ChannelType: channel.ChannelTelegram,
|
||||
@@ -387,6 +418,9 @@ func TestIncomingPersisterCreatesConversationMessageAndDedupes(t *testing.T) {
|
||||
if result.Message.Content != "hello" || result.Message.SourceID != "tg-msg-1" {
|
||||
t.Fatalf("unexpected message: %#v", result.Message)
|
||||
}
|
||||
if len(indexer.contacts) != 1 || len(indexer.conversations) != 1 || len(indexer.messages) != 1 {
|
||||
t.Fatalf("expected first incoming result indexed, contacts=%#v conversations=%#v messages=%#v", indexer.contacts, indexer.conversations, indexer.messages)
|
||||
}
|
||||
|
||||
duplicate, err := persister.PersistIncoming(t.Context(), &inbox, msg)
|
||||
if err != nil {
|
||||
@@ -395,6 +429,9 @@ func TestIncomingPersisterCreatesConversationMessageAndDedupes(t *testing.T) {
|
||||
if duplicate == nil || !duplicate.Duplicate {
|
||||
t.Fatalf("expected duplicate result, got %#v", duplicate)
|
||||
}
|
||||
if len(indexer.messages) != 1 {
|
||||
t.Fatalf("expected duplicate to skip indexing, got %#v", indexer.messages)
|
||||
}
|
||||
|
||||
msg.SourceID = "tg-msg-2"
|
||||
msg.Content = "second"
|
||||
@@ -405,6 +442,9 @@ func TestIncomingPersisterCreatesConversationMessageAndDedupes(t *testing.T) {
|
||||
if second.Contact.ID != result.Contact.ID || second.Conversation.ID != result.Conversation.ID {
|
||||
t.Fatalf("expected contact/conversation reuse: first=%#v second=%#v", result, second)
|
||||
}
|
||||
if len(indexer.messages) != 2 || indexer.messages[1].ID != second.Message.ID {
|
||||
t.Fatalf("expected second incoming message indexed, got %#v", indexer.messages)
|
||||
}
|
||||
|
||||
var messageCount int64
|
||||
if err := db.Model(&model.Message{}).Where("inbox_id = ?", inbox.ID).Count(&messageCount).Error; err != nil {
|
||||
@@ -426,8 +466,9 @@ func TestIncomingPersisterQueuesIncomingMessageWithWorker(t *testing.T) {
|
||||
dispatcher := channel.NewDispatcher()
|
||||
listener := &recordingListener{}
|
||||
dispatcher.Register(listener)
|
||||
indexer := &recordingIncomingSearchIndexer{}
|
||||
wp := worker.NewWorkerPool(db)
|
||||
persister := NewIncomingPersister(db, dispatcher).SetWorkerPool(wp)
|
||||
persister := NewIncomingPersister(db, dispatcher).SetSearchIndexer(indexer).SetWorkerPool(wp)
|
||||
|
||||
msg := &channel.IncomingMessage{
|
||||
ChannelType: channel.ChannelTelegram,
|
||||
@@ -464,6 +505,9 @@ func TestIncomingPersisterQueuesIncomingMessageWithWorker(t *testing.T) {
|
||||
t.Fatalf("process incoming job processed=%v err=%v", processed, err)
|
||||
}
|
||||
assertPersistedMessage(t, db, inbox.ID, "tg-inbound-job-1", "persist me later")
|
||||
if len(indexer.messages) != 1 || indexer.messages[0].SourceID != "tg-inbound-job-1" {
|
||||
t.Fatalf("expected durable incoming message to be indexed, got %#v", indexer.messages)
|
||||
}
|
||||
for _, eventType := range []channel.EventType{channel.EventContactCreated, channel.EventConversationCreated, channel.EventConversationOpened, channel.EventMessageCreated, channel.EventMessageIncoming} {
|
||||
if !listenerSaw(listener, eventType) {
|
||||
t.Fatalf("expected event %s, got %#v", eventType, listener.events)
|
||||
|
||||
Reference in New Issue
Block a user