strict_keys_test.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package webapi
  2. import (
  3. "net/http"
  4. "net/http/httptest"
  5. "testing"
  6. "github.com/stretchr/testify/assert"
  7. )
  8. // Some clients read these response keys strictly, throwing on an absent key rather
  9. // than treating it as empty, and nothing surfaces that failure: an event parse is
  10. // dropped and a queued request retried forever. Each key below must therefore be
  11. // present even when its value is empty, zero or false — presence is the contract, not
  12. // the value. These tests keep a future `omitempty` from reintroducing the failure.
  13. // renderJSON sends payload through the default JSON path and returns the body.
  14. func renderJSON(t *testing.T, data any) string {
  15. t.Helper()
  16. rr := httptest.NewRecorder()
  17. SendOK(rr, httptest.NewRequest(http.MethodGet, "/x?f=json", nil), data, nil)
  18. return rr.Body.String()
  19. }
  20. func TestStrictKeys_IMEvents(t *testing.T) {
  21. t.Run("im carries imf and autoresponse when false", func(t *testing.T) {
  22. body := renderJSON(t, IMEvent{
  23. Source: UserInfo{AimID: "chattingchuck"},
  24. Message: "hi",
  25. Imf: imfPlainText,
  26. })
  27. assert.Contains(t, body, `"imf":"plain"`)
  28. assert.Contains(t, body, `"autoresponse":false`)
  29. })
  30. t.Run("offlineIM carries imf and autoresponse when false", func(t *testing.T) {
  31. body := renderJSON(t, OfflineIMEvent{
  32. AimID: "chattingchuck",
  33. Message: "hi",
  34. Imf: imfPlainText,
  35. })
  36. assert.Contains(t, body, `"imf":"plain"`)
  37. assert.Contains(t, body, `"autoresponse":false`)
  38. })
  39. }
  40. func TestStrictKeys_BuddyGroupID(t *testing.T) {
  41. // The zero id is the interesting case: omitempty here would drop the key for
  42. // the group the client is most likely to have, and cost it the whole roster.
  43. body := renderJSON(t, BuddyListData{Groups: []BuddyGroup{{
  44. Name: "Buddies", ID: 0, Buddies: []BuddyInfo{},
  45. }}})
  46. assert.Contains(t, body, `"id":0`)
  47. }
  48. func TestStrictKeys_PresenceUsers(t *testing.T) {
  49. // Each query fills in one field, and a match of none must still render that
  50. // field as an empty array rather than drop it: a client reading data.users or
  51. // data.groups strictly cannot tell an absent key from a failed request.
  52. populatedGroups := []BuddyGroupInfo{{Name: "Buddies", Buddies: []BuddyPresenceInfo{}}}
  53. t.Run("empty user result still renders the array", func(t *testing.T) {
  54. body := renderJSON(t, PresenceData{Users: []BuddyPresenceInfo{}})
  55. assert.Contains(t, body, `"users":[]`)
  56. })
  57. t.Run("empty group result still renders the array", func(t *testing.T) {
  58. body := renderJSON(t, PresenceData{Groups: []BuddyGroupInfo{}})
  59. assert.Contains(t, body, `"groups":[]`)
  60. })
  61. t.Run("buddy list query omits users", func(t *testing.T) {
  62. body := renderJSON(t, PresenceData{Groups: populatedGroups})
  63. assert.NotContains(t, body, `"users"`)
  64. })
  65. t.Run("presence query omits groups", func(t *testing.T) {
  66. body := renderJSON(t, PresenceData{Users: []BuddyPresenceInfo{}})
  67. assert.NotContains(t, body, `"groups"`)
  68. })
  69. }
  70. func TestStrictKeys_FetchEventsArray(t *testing.T) {
  71. // A nil slice renders as null, which throws exactly as an absent key does — and
  72. // a poll that throws is retried every 5s forever.
  73. body := renderJSON(t, &FetchEventsData{Events: []Event{}})
  74. assert.Contains(t, body, `"events":[]`)
  75. assert.NotContains(t, body, `"events":null`)
  76. }
  77. func TestStrictKeys_GetInfoUserData(t *testing.T) {
  78. // The web client reads loginId and displayName off userData unconditionally, so
  79. // both keys must survive a blank name.
  80. body := renderJSON(t, GetInfoData{})
  81. assert.Contains(t, body, `"loginId":""`)
  82. assert.Contains(t, body, `"displayName":""`)
  83. }