(t *testing.T)
| 446 | } |
| 447 | |
| 448 | func TestInboundMessageRoundTripsToCcLists(t *testing.T) { |
| 449 | pool := testutil.TestDB(t) |
| 450 | store := identity.NewStore(pool) |
| 451 | ctx := context.Background() |
| 452 | |
| 453 | user, _ := store.CreateOrGetUser(ctx, "tcc-owner@example.com", "Owner", "google-tcc") |
| 454 | store.ClaimOrCreateDomain(ctx, "tcc.example.com", user.ID) |
| 455 | a, _ := store.CreateAgent(ctx, "bot-a@tcc.example.com", "tcc.example.com", "", "https://example.com/webhook", "", user.ID) |
| 456 | |
| 457 | to := []string{"bot-a@tcc.example.com", "bot-b@tcc.example.com"} |
| 458 | cc := []string{"watcher@example.com", "audit@example.com"} |
| 459 | // Two addresses to exercise the multi-value path; RFC 5322 § 3.6.2 |
| 460 | // permits more than one Reply-To. Single-value is the common case |
| 461 | // and is covered transitively by other tests that pass nil here. |
| 462 | replyTo := []string{"real-user@example.com", "delegate@example.com"} |
| 463 | |
| 464 | msg, err := store.CreateInboundMessage(ctx, "", a.ID, "alice@gmail.com", "bot-a@tcc.example.com", "<x@gmail.com>", "Group thread", "", "", nil, nil, nil, false, "", to, cc, replyTo, identity.InboundScreening{}) |
| 465 | if err != nil { |
| 466 | t.Fatalf("CreateInboundMessage: %v", err) |
| 467 | } |
| 468 | |
| 469 | got, err := store.GetInboundMessage(ctx, msg.ID) |
| 470 | if err != nil { |
| 471 | t.Fatalf("GetInboundMessage: %v", err) |
| 472 | } |
| 473 | if !reflect.DeepEqual(got.ToRecipients, to) { |
| 474 | t.Errorf("ToRecipients = %v, want %v", got.ToRecipients, to) |
| 475 | } |
| 476 | if !reflect.DeepEqual(got.CC, cc) { |
| 477 | t.Errorf("CC = %v, want %v", got.CC, cc) |
| 478 | } |
| 479 | if !reflect.DeepEqual(got.ReplyTo, replyTo) { |
| 480 | t.Errorf("ReplyTo = %v, want %v", got.ReplyTo, replyTo) |
| 481 | } |
| 482 | |
| 483 | // Also exercise the consumer-facing read path (GET /messages/{id}) |
| 484 | // — different SELECT columns, easy to drift independently. |
| 485 | gotDetail, err := store.GetMessageWithContent(ctx, msg.ID, a.ID) |
| 486 | if err != nil { |
| 487 | t.Fatalf("GetMessageWithContent: %v", err) |
| 488 | } |
| 489 | if !reflect.DeepEqual(gotDetail.ReplyTo, replyTo) { |
| 490 | t.Errorf("GetMessageWithContent ReplyTo = %v, want %v", gotDetail.ReplyTo, replyTo) |
| 491 | } |
| 492 | |
| 493 | // And the list path (GET /messages) — yet another SELECT. |
| 494 | msgs, err := store.GetMessagesByAgent(ctx, identity.MessageListFilter{ |
| 495 | AgentID: a.ID, |
| 496 | Status: "all", |
| 497 | Direction: "inbound", |
| 498 | Limit: 10, |
| 499 | }) |
| 500 | if err != nil { |
| 501 | t.Fatalf("GetMessagesByAgent: %v", err) |
| 502 | } |
| 503 | var found *identity.Message |
| 504 | for i := range msgs { |
| 505 | if msgs[i].ID == msg.ID { |
nothing calls this directly
no test coverage detected