tgbot_client_draft_per_admin_test.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package tgbot
  2. import (
  3. "path/filepath"
  4. "testing"
  5. "github.com/mhsanaei/3x-ui/v3/internal/database"
  6. "github.com/mymmrac/telego"
  7. )
  8. // Regression test: keying the add-client wizard by chat alone left the two
  9. // admins of a group chat filling in one client between them.
  10. func TestAddClientDraftIsPerAdminInGroupChat(t *testing.T) {
  11. if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
  12. t.Fatalf("InitDB: %v", err)
  13. }
  14. t.Cleanup(func() { _ = database.CloseDB() })
  15. const (
  16. groupChat = int64(-1001234567890)
  17. adminA = int64(8101)
  18. adminB = int64(8202)
  19. )
  20. url, textsFor := draftTexts(t)
  21. swapTestBot(t, url)
  22. origRunning := isRunning
  23. t.Cleanup(func() {
  24. isRunning = origRunning
  25. userStateMgr.reset()
  26. })
  27. isRunning = true
  28. // Both admins tap in the same chat; only the sender tells them apart.
  29. tap := func(userID int64, data string) {
  30. t.Helper()
  31. (&Tgbot{}).answerCallback(&telego.CallbackQuery{
  32. ID: "q1",
  33. From: telego.User{ID: userID},
  34. Data: data,
  35. Message: &telego.Message{MessageID: 7, Chat: telego.Chat{ID: groupChat}},
  36. }, true)
  37. }
  38. tap(adminA, "add_client_to 1")
  39. emailA := cardEmail(t, lastDraftCard(t, textsFor(groupChat)))
  40. tap(adminB, "add_client_to 2")
  41. emailB := cardEmail(t, lastDraftCard(t, textsFor(groupChat)))
  42. if emailA == "" || emailA == emailB {
  43. t.Fatalf("both admins start with email %q, want one draft per admin", emailA)
  44. }
  45. // Admin A renders again, with admin B's wizard already past its start.
  46. tap(adminA, "add_client_default_traffic_exp")
  47. if got := cardEmail(t, lastDraftCard(t, textsFor(groupChat))); got != emailA {
  48. t.Errorf("admin A's card shows email %q, want its own %q from admin B's draft", got, emailA)
  49. }
  50. // The step they are each on is their own too: A's prompt must not put B into
  51. // the same step, or B's next message lands in A's wizard.
  52. tap(adminA, "add_client_ch_default_email")
  53. if st, ok := userStateMgr.get(chatUser{chatID: groupChat, userID: adminA}); !ok || st != "awaiting_email" {
  54. t.Errorf("admin A's step = %q (set: %v), want awaiting_email", st, ok)
  55. }
  56. if st, ok := userStateMgr.get(chatUser{chatID: groupChat, userID: adminB}); ok {
  57. t.Errorf("admin B's step = %q, want none: only the tapper's step may change", st)
  58. }
  59. }
  60. // The wizard's typed steps arrive as messages, and that handler is a closure no
  61. // test can drive, so pin the key it takes there: sender, not chat.
  62. func TestMessageActorSeparatesAdminsInOneChat(t *testing.T) {
  63. const (
  64. groupChat = int64(-1001234567890)
  65. adminA = int64(8101)
  66. adminB = int64(8202)
  67. )
  68. t.Cleanup(userStateMgr.reset)
  69. fromA := messageActor(telego.Message{Chat: telego.Chat{ID: groupChat}, From: &telego.User{ID: adminA}})
  70. fromB := messageActor(telego.Message{Chat: telego.Chat{ID: groupChat}, From: &telego.User{ID: adminB}})
  71. // A channel post carries no sender and must not land on an admin's step.
  72. fromChannel := messageActor(telego.Message{Chat: telego.Chat{ID: groupChat}})
  73. if want := (chatUser{chatID: groupChat, userID: adminA}); fromA != want {
  74. t.Errorf("message from admin A keyed as %+v, want %+v", fromA, want)
  75. }
  76. if fromA == fromB || fromA == fromChannel || fromB == fromChannel {
  77. t.Fatalf("keys collide: %+v, %+v, %+v", fromA, fromB, fromChannel)
  78. }
  79. userStateMgr.set(fromA, "awaiting_email")
  80. if st, ok := userStateMgr.get(fromB); ok {
  81. t.Errorf("admin B sees step %q: admin A's answer would land in B's wizard", st)
  82. }
  83. if st, ok := userStateMgr.get(fromChannel); ok {
  84. t.Errorf("a senderless post sees step %q", st)
  85. }
  86. if st, ok := userStateMgr.get(fromA); !ok || st != "awaiting_email" {
  87. t.Errorf("admin A's step = %q (set: %v), want awaiting_email", st, ok)
  88. }
  89. }