session_manager_test.go 8.9 KB

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