session_manager_test.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. package state
  2. import (
  3. "context"
  4. "log/slog"
  5. "testing"
  6. "github.com/mk6i/retro-aim-server/wire"
  7. "github.com/stretchr/testify/assert"
  8. )
  9. func TestInMemorySessionManager_AddSession(t *testing.T) {
  10. sm := NewInMemorySessionManager(slog.Default())
  11. want1 := sm.AddSession("user-screen-name")
  12. have1 := sm.RetrieveSession(NewIdentScreenName("user-screen-name"))
  13. assert.Same(t, want1, have1)
  14. want2 := sm.AddSession("user-screen-name")
  15. have2 := sm.RetrieveSession(NewIdentScreenName("user-screen-name"))
  16. assert.Same(t, want2, have2)
  17. // ensure that the second session created with the same screen name as the
  18. // first session clobbers the previous session in the session manager store
  19. assert.NotSame(t, have1, have2)
  20. }
  21. func TestInMemorySessionManager_Remove_Existing(t *testing.T) {
  22. sm := NewInMemorySessionManager(slog.Default())
  23. user1Old := sm.AddSession("user-screen-name-1")
  24. user1New := sm.AddSession("user-screen-name-1")
  25. user2 := sm.AddSession("user-screen-name-2")
  26. sm.RemoveSession(user1New)
  27. if assert.Len(t, sm.AllSessions(), 1) {
  28. assert.NotContains(t, sm.AllSessions(), user1Old)
  29. assert.NotContains(t, sm.AllSessions(), user1New)
  30. assert.Contains(t, sm.AllSessions(), user2)
  31. }
  32. }
  33. func TestInMemorySessionManager_Remove_MissingSameScreenName(t *testing.T) {
  34. sm := NewInMemorySessionManager(slog.Default())
  35. user1Old := sm.AddSession("user-screen-name-1")
  36. user1New := sm.AddSession("user-screen-name-1")
  37. user2 := sm.AddSession("user-screen-name-2")
  38. sm.RemoveSession(user1Old)
  39. if assert.Len(t, sm.AllSessions(), 2) {
  40. assert.NotContains(t, sm.AllSessions(), user1Old)
  41. assert.Contains(t, sm.AllSessions(), user1New)
  42. assert.Contains(t, sm.AllSessions(), user2)
  43. }
  44. }
  45. func TestInMemorySessionManager_Empty(t *testing.T) {
  46. tests := []struct {
  47. name string
  48. given []DisplayScreenName
  49. want bool
  50. }{
  51. {
  52. name: "session manager is not empty",
  53. given: []DisplayScreenName{
  54. "user-screen-name-1",
  55. },
  56. want: false,
  57. },
  58. {
  59. name: "session manager is empty",
  60. given: []DisplayScreenName{},
  61. want: true,
  62. },
  63. }
  64. for _, tt := range tests {
  65. t.Run(tt.name, func(t *testing.T) {
  66. sm := NewInMemorySessionManager(slog.Default())
  67. for _, screenName := range tt.given {
  68. sm.AddSession(screenName)
  69. }
  70. have := sm.Empty()
  71. assert.Equal(t, tt.want, have)
  72. })
  73. }
  74. }
  75. func TestInMemorySessionManager_Retrieve(t *testing.T) {
  76. tests := []struct {
  77. name string
  78. given []DisplayScreenName
  79. lookupScreenName IdentScreenName
  80. wantScreenName IdentScreenName
  81. }{
  82. {
  83. name: "lookup finds match",
  84. given: []DisplayScreenName{
  85. "user-screen-name-1",
  86. "user-screen-name-2",
  87. },
  88. lookupScreenName: NewIdentScreenName("user-screen-name-2"),
  89. wantScreenName: NewIdentScreenName("user-screen-name-2"),
  90. },
  91. {
  92. name: "lookup does not find match",
  93. given: []DisplayScreenName{},
  94. lookupScreenName: NewIdentScreenName("user-screen-name-3"),
  95. wantScreenName: NewIdentScreenName(""),
  96. },
  97. }
  98. for _, tt := range tests {
  99. t.Run(tt.name, func(t *testing.T) {
  100. sm := NewInMemorySessionManager(slog.Default())
  101. for _, screenName := range tt.given {
  102. sm.AddSession(screenName)
  103. }
  104. have := sm.RetrieveSession(tt.lookupScreenName)
  105. if have == nil {
  106. assert.Empty(t, tt.wantScreenName)
  107. } else {
  108. assert.Equal(t, tt.wantScreenName, have.IdentScreenName())
  109. }
  110. })
  111. }
  112. }
  113. func TestInMemorySessionManager_RelayToScreenNames(t *testing.T) {
  114. sm := NewInMemorySessionManager(slog.Default())
  115. user1 := sm.AddSession("user-screen-name-1")
  116. user2 := sm.AddSession("user-screen-name-2")
  117. user3 := sm.AddSession("user-screen-name-3")
  118. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  119. recips := []IdentScreenName{
  120. NewIdentScreenName("user-screen-name-1"),
  121. NewIdentScreenName("user-screen-name-2"),
  122. }
  123. sm.RelayToScreenNames(context.Background(), recips, want)
  124. select {
  125. case have := <-user1.ReceiveMessage():
  126. assert.Equal(t, want, have)
  127. }
  128. select {
  129. case have := <-user2.ReceiveMessage():
  130. assert.Equal(t, want, have)
  131. }
  132. select {
  133. case <-user3.ReceiveMessage():
  134. assert.Fail(t, "user 3 should not receive a message")
  135. default:
  136. }
  137. }
  138. func TestInMemorySessionManager_Broadcast(t *testing.T) {
  139. sm := NewInMemorySessionManager(slog.Default())
  140. user1 := sm.AddSession("user-screen-name-1")
  141. user2 := sm.AddSession("user-screen-name-2")
  142. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  143. sm.RelayToAll(context.Background(), want)
  144. select {
  145. case have := <-user1.ReceiveMessage():
  146. assert.Equal(t, want, have)
  147. }
  148. select {
  149. case have := <-user2.ReceiveMessage():
  150. assert.Equal(t, want, have)
  151. }
  152. }
  153. func TestInMemorySessionManager_Broadcast_SkipClosedSession(t *testing.T) {
  154. sm := NewInMemorySessionManager(slog.Default())
  155. user1 := sm.AddSession("user-screen-name-1")
  156. user2 := sm.AddSession("user-screen-name-2")
  157. user2.Close()
  158. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  159. sm.RelayToAll(context.Background(), want)
  160. select {
  161. case have := <-user1.ReceiveMessage():
  162. assert.Equal(t, want, have)
  163. }
  164. select {
  165. case <-user2.ReceiveMessage():
  166. assert.Fail(t, "user 2 should not receive a message")
  167. default:
  168. }
  169. }
  170. func TestInMemorySessionManager_RelayToScreenName_SessionExists(t *testing.T) {
  171. sm := NewInMemorySessionManager(slog.Default())
  172. user1 := sm.AddSession("user-screen-name-1")
  173. user2 := sm.AddSession("user-screen-name-2")
  174. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  175. recip := NewIdentScreenName("user-screen-name-1")
  176. sm.RelayToScreenName(context.Background(), recip, want)
  177. select {
  178. case have := <-user1.ReceiveMessage():
  179. assert.Equal(t, want, have)
  180. }
  181. select {
  182. case <-user2.ReceiveMessage():
  183. assert.Fail(t, "user 2 should not receive a message")
  184. default:
  185. }
  186. }
  187. func TestInMemorySessionManager_RelayToScreenName_SessionNotExist(t *testing.T) {
  188. sm := NewInMemorySessionManager(slog.Default())
  189. user1 := sm.AddSession("user-screen-name-1")
  190. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  191. recip := NewIdentScreenName("user-screen-name-2")
  192. sm.RelayToScreenName(context.Background(), recip, want)
  193. select {
  194. case <-user1.ReceiveMessage():
  195. assert.Fail(t, "user 1 should not receive a message")
  196. default:
  197. }
  198. }
  199. func TestInMemorySessionManager_RelayToScreenName_SkipFullSession(t *testing.T) {
  200. sm := NewInMemorySessionManager(slog.Default())
  201. user1 := sm.AddSession("user-screen-name-1")
  202. msg := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  203. wantCount := 0
  204. for {
  205. if user1.RelayMessage(msg) == SessQueueFull {
  206. break
  207. }
  208. wantCount++
  209. }
  210. recip := NewIdentScreenName("user-screen-name-1")
  211. sm.RelayToScreenName(context.Background(), recip, msg)
  212. haveCount := 0
  213. loop:
  214. for {
  215. select {
  216. case <-user1.ReceiveMessage():
  217. haveCount++
  218. default:
  219. break loop
  220. }
  221. }
  222. assert.Equal(t, wantCount, haveCount)
  223. }
  224. func TestInMemoryChatSessionManager_RelayToAllExcept_HappyPath(t *testing.T) {
  225. sm := NewInMemoryChatSessionManager(slog.Default())
  226. cookie := "the-cookie"
  227. user1 := sm.AddSession(cookie, "user-screen-name-1")
  228. user2 := sm.AddSession(cookie, "user-screen-name-2")
  229. user3 := sm.AddSession(cookie, "user-screen-name-3")
  230. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  231. sm.RelayToAllExcept(context.Background(), cookie, user2.IdentScreenName(), want)
  232. select {
  233. case have := <-user1.ReceiveMessage():
  234. assert.Equal(t, want, have)
  235. }
  236. select {
  237. case <-user2.ReceiveMessage():
  238. assert.Fail(t, "user 2 should not receive a message")
  239. default:
  240. }
  241. select {
  242. case have := <-user3.ReceiveMessage():
  243. assert.Equal(t, want, have)
  244. }
  245. }
  246. func TestInMemoryChatSessionManager_AllSessions_RoomExists(t *testing.T) {
  247. sm := NewInMemoryChatSessionManager(slog.Default())
  248. user1 := sm.AddSession("the-cookie", "user-screen-name-1")
  249. user2 := sm.AddSession("the-cookie", "user-screen-name-2")
  250. sessions := sm.AllSessions("the-cookie")
  251. assert.Len(t, sessions, 2)
  252. lookup := make(map[*Session]bool)
  253. for _, session := range sessions {
  254. lookup[session] = true
  255. }
  256. assert.True(t, lookup[user1])
  257. assert.True(t, lookup[user2])
  258. }
  259. func TestInMemoryChatSessionManager_RelayToScreenName_SessionAndChatRoomExist(t *testing.T) {
  260. sm := NewInMemoryChatSessionManager(slog.Default())
  261. user1 := sm.AddSession("chat-room-1", "user-screen-name-1")
  262. user2 := sm.AddSession("chat-room-1", "user-screen-name-2")
  263. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  264. recip := NewIdentScreenName("user-screen-name-1")
  265. sm.RelayToScreenName(context.Background(), "chat-room-1", recip, want)
  266. select {
  267. case have := <-user1.ReceiveMessage():
  268. assert.Equal(t, want, have)
  269. }
  270. select {
  271. case <-user2.ReceiveMessage():
  272. assert.Fail(t, "user 2 should not receive a message")
  273. default:
  274. }
  275. }
  276. func TestInMemoryChatSessionManager_RemoveSession(t *testing.T) {
  277. sm := NewInMemoryChatSessionManager(slog.Default())
  278. user1 := sm.AddSession("chat-room-1", "user-screen-name-1")
  279. user2 := sm.AddSession("chat-room-1", "user-screen-name-2")
  280. assert.Len(t, sm.AllSessions("chat-room-1"), 2)
  281. sm.RemoveSession(user1)
  282. sm.RemoveSession(user2)
  283. assert.Empty(t, sm.AllSessions("chat-room-1"))
  284. }
  285. func TestInMemoryChatSessionManager_RemoveSession_DoubleLogin(t *testing.T) {
  286. sm := NewInMemoryChatSessionManager(slog.Default())
  287. user1 := sm.AddSession("chat-room-1", "user-screen-name-1")
  288. user2 := sm.AddSession("chat-room-1", "user-screen-name-1")
  289. assert.NotSame(t, user1, user2)
  290. assert.Len(t, sm.AllSessions("chat-room-1"), 1)
  291. sm.RemoveSession(user1)
  292. sm.RemoveSession(user2)
  293. assert.Empty(t, sm.AllSessions("chat-room-1"))
  294. }