session_manager_test.go 7.3 KB

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