TestLookupConversationID_EmailThread simulates the production scenario: 1. Human sends first email → inbound stored with email_message_id, no conversation_id 2. Agent replies → outbound stored with provider_message_id (bare SES ID) and conversation_id 3. Human replies again → In-Reply-To references
(t *testing.T)
| 714 | // The lookup must match the second inbound's In-Reply-To against the outbound's |
| 715 | // provider_message_id using prefix matching, and return the conversation_id. |
| 716 | func TestLookupConversationID_EmailThread(t *testing.T) { |
| 717 | pool := testutil.TestDB(t) |
| 718 | store := identity.NewStore(pool) |
| 719 | ctx := context.Background() |
| 720 | |
| 721 | user, _ := store.CreateOrGetUser(ctx, "owner-thread@example.com", "Owner", "google-thread") |
| 722 | store.ClaimOrCreateDomain(ctx, "thread.example.com", user.ID) |
| 723 | agent, _ := store.CreateAgent(ctx, "bot@thread.example.com", "thread.example.com", "", "https://example.com/webhook", "", user.ID) |
| 724 | |
| 725 | // 1. First inbound email — no conversation_id yet |
| 726 | _, err := store.CreateInboundMessage(ctx, "", agent.ID, |
| 727 | "alice@gmail.com", "bot@thread.example.com", |
| 728 | "<CAMCKtby_first@mail.gmail.com>", "Hello", |
| 729 | "", // no conversation_id on first message |
| 730 | "pending", nil, nil, nil, false, "", nil, nil, nil, identity.InboundScreening{}) |
| 731 | if err != nil { |
| 732 | t.Fatalf("CreateInboundMessage: %v", err) |
| 733 | } |
| 734 | |
| 735 | // 2. Agent replies — mnexa sets conversation_id, SES returns bare Message-ID |
| 736 | mnexa_conv_id := "e0533ec4-af43-4dea-9cc7-be6fff5cf440" |
| 737 | _, err = store.CreateOutboundMessage(ctx, agent.ID, |
| 738 | []string{"alice@gmail.com"}, nil, nil, "Re: Hello", |
| 739 | "reply", "smtp", |
| 740 | "<010f019d4b3843be-53882e6f-46de-4221-a56a-ba993e8f83e8-000000>", // bare SES ID (no @region) |
| 741 | mnexa_conv_id, nil) |
| 742 | if err != nil { |
| 743 | t.Fatalf("CreateOutboundMessage: %v", err) |
| 744 | } |
| 745 | |
| 746 | // 3. Human replies — Gmail's In-Reply-To has the full SES Message-ID with @region |
| 747 | // References includes both the original inbound and the agent's reply |
| 748 | inReplyTo := "<010f019d4b3843be-53882e6f-46de-4221-a56a-ba993e8f83e8-000000@us-east-2.amazonses.com>" |
| 749 | references := "<CAMCKtby_first@mail.gmail.com>" |
| 750 | |
| 751 | lookupIDs := []string{inReplyTo, references} |
| 752 | got, err := store.LookupConversationID(ctx, agent.ID, lookupIDs) |
| 753 | if err != nil { |
| 754 | t.Fatalf("LookupConversationID failed: %v", err) |
| 755 | } |
| 756 | if got != mnexa_conv_id { |
| 757 | t.Errorf("LookupConversationID = %q, want %q", got, mnexa_conv_id) |
| 758 | } |
| 759 | } |
| 760 | |
| 761 | // TestLookupConversationID_ExactMatch verifies that exact matches on |
| 762 | // email_message_id and provider_message_id still work. |
nothing calls this directly
no test coverage detected