session_manager_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. package state
  2. import (
  3. "context"
  4. "log/slog"
  5. "sync"
  6. "testing"
  7. "github.com/mk6i/retro-aim-server/wire"
  8. "github.com/stretchr/testify/assert"
  9. )
  10. func TestInMemorySessionManager_AddSession(t *testing.T) {
  11. sm := NewInMemorySessionManager(slog.Default())
  12. ctx := context.Background()
  13. sess1, err := sm.AddSession(ctx, "user-screen-name")
  14. assert.NoError(t, err)
  15. sess1.SetSignonComplete()
  16. go func() {
  17. <-sess1.Closed()
  18. sm.RemoveSession(sess1)
  19. }()
  20. sess2, err := sm.AddSession(ctx, "user-screen-name")
  21. assert.NoError(t, err)
  22. sess2.SetSignonComplete()
  23. assert.NotSame(t, sess1, sess2)
  24. assert.Contains(t, sm.AllSessions(), sess2)
  25. }
  26. func TestInMemorySessionManager_AddSession_Timeout(t *testing.T) {
  27. sm := NewInMemorySessionManager(slog.Default())
  28. ctx, cancel := context.WithCancel(context.Background())
  29. sess1, err := sm.AddSession(ctx, "user-screen-name")
  30. assert.NoError(t, err)
  31. sess1.SetSignonComplete()
  32. go func() {
  33. <-sess1.Closed()
  34. cancel()
  35. }()
  36. sess2, err := sm.AddSession(ctx, "user-screen-name")
  37. assert.Nil(t, sess2)
  38. assert.ErrorIs(t, err, context.Canceled)
  39. }
  40. func TestInMemorySessionManager_AddSession_SessionConflict(t *testing.T) {
  41. sm := NewInMemorySessionManager(slog.Default())
  42. ctx := context.Background()
  43. sess1, err := sm.AddSession(ctx, "user-screen-name")
  44. assert.NoError(t, err)
  45. sess1.SetSignonComplete()
  46. go func() {
  47. <-sess1.Closed()
  48. rec, ok := sm.store[NewIdentScreenName("user-screen-name")]
  49. if assert.True(t, ok) {
  50. close(rec.removed)
  51. }
  52. }()
  53. sess2, err := sm.AddSession(ctx, "user-screen-name")
  54. assert.Nil(t, sess2)
  55. assert.ErrorIs(t, err, errSessConflict)
  56. }
  57. func TestInMemorySessionManager_Remove_Existing(t *testing.T) {
  58. sm := NewInMemorySessionManager(slog.Default())
  59. user1Old, err := sm.AddSession(context.Background(), "user-screen-name-1")
  60. assert.NoError(t, err)
  61. sm.RemoveSession(user1Old)
  62. user1New, err := sm.AddSession(context.Background(), "user-screen-name-1")
  63. assert.NoError(t, err)
  64. user1New.SetSignonComplete()
  65. user2, err := sm.AddSession(context.Background(), "user-screen-name-2")
  66. assert.NoError(t, err)
  67. user2.SetSignonComplete()
  68. sm.RemoveSession(user1New)
  69. if assert.Len(t, sm.AllSessions(), 1) {
  70. assert.NotContains(t, sm.AllSessions(), user1Old)
  71. assert.NotContains(t, sm.AllSessions(), user1New)
  72. assert.Contains(t, sm.AllSessions(), user2)
  73. }
  74. }
  75. func TestInMemorySessionManager_Remove_MissingSameScreenName(t *testing.T) {
  76. sm := NewInMemorySessionManager(slog.Default())
  77. user1Old, err := sm.AddSession(context.Background(), "user-screen-name-1")
  78. assert.NoError(t, err)
  79. sm.RemoveSession(user1Old)
  80. user1New, err := sm.AddSession(context.Background(), "user-screen-name-1")
  81. assert.NoError(t, err)
  82. user1New.SetSignonComplete()
  83. user2, err := sm.AddSession(context.Background(), "user-screen-name-2")
  84. assert.NoError(t, err)
  85. user2.SetSignonComplete()
  86. sm.RemoveSession(user1Old)
  87. if assert.Len(t, sm.AllSessions(), 2) {
  88. assert.NotContains(t, sm.AllSessions(), user1Old)
  89. assert.Contains(t, sm.AllSessions(), user1New)
  90. assert.Contains(t, sm.AllSessions(), user2)
  91. }
  92. }
  93. func TestInMemorySessionManager_Empty(t *testing.T) {
  94. tests := []struct {
  95. name string
  96. given []DisplayScreenName
  97. want bool
  98. }{
  99. {
  100. name: "session manager is not empty",
  101. given: []DisplayScreenName{
  102. "user-screen-name-1",
  103. },
  104. want: false,
  105. },
  106. {
  107. name: "session manager is empty",
  108. given: []DisplayScreenName{},
  109. want: true,
  110. },
  111. }
  112. for _, tt := range tests {
  113. t.Run(tt.name, func(t *testing.T) {
  114. sm := NewInMemorySessionManager(slog.Default())
  115. for _, screenName := range tt.given {
  116. sess, err := sm.AddSession(context.Background(), screenName)
  117. assert.NoError(t, err)
  118. sess.SetSignonComplete()
  119. }
  120. have := sm.Empty()
  121. assert.Equal(t, tt.want, have)
  122. })
  123. }
  124. }
  125. func TestInMemorySessionManager_Retrieve(t *testing.T) {
  126. tests := []struct {
  127. name string
  128. given []DisplayScreenName
  129. lookupScreenName IdentScreenName
  130. wantScreenName IdentScreenName
  131. }{
  132. {
  133. name: "lookup finds match",
  134. given: []DisplayScreenName{
  135. "user-screen-name-1",
  136. "user-screen-name-2",
  137. },
  138. lookupScreenName: NewIdentScreenName("user-screen-name-2"),
  139. wantScreenName: NewIdentScreenName("user-screen-name-2"),
  140. },
  141. {
  142. name: "lookup does not find match",
  143. given: []DisplayScreenName{},
  144. lookupScreenName: NewIdentScreenName("user-screen-name-3"),
  145. wantScreenName: NewIdentScreenName(""),
  146. },
  147. }
  148. for _, tt := range tests {
  149. t.Run(tt.name, func(t *testing.T) {
  150. sm := NewInMemorySessionManager(slog.Default())
  151. for _, screenName := range tt.given {
  152. sess, err := sm.AddSession(context.Background(), screenName)
  153. assert.NoError(t, err)
  154. sess.SetSignonComplete()
  155. }
  156. have := sm.RetrieveSession(tt.lookupScreenName)
  157. if have == nil {
  158. assert.Empty(t, tt.wantScreenName)
  159. } else {
  160. assert.Equal(t, tt.wantScreenName, have.IdentScreenName())
  161. }
  162. })
  163. }
  164. }
  165. func TestInMemorySessionManager_RelayToScreenNames(t *testing.T) {
  166. sm := NewInMemorySessionManager(slog.Default())
  167. user1, err := sm.AddSession(context.Background(), "user-screen-name-1")
  168. assert.NoError(t, err)
  169. user1.SetSignonComplete()
  170. user2, err := sm.AddSession(context.Background(), "user-screen-name-2")
  171. assert.NoError(t, err)
  172. user2.SetSignonComplete()
  173. user3, err := sm.AddSession(context.Background(), "user-screen-name-3")
  174. assert.NoError(t, err)
  175. user3.SetSignonComplete()
  176. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  177. recips := []IdentScreenName{
  178. NewIdentScreenName("user-screen-name-1"),
  179. NewIdentScreenName("user-screen-name-2"),
  180. }
  181. sm.RelayToScreenNames(context.Background(), recips, want)
  182. select {
  183. case have := <-user1.ReceiveMessage():
  184. assert.Equal(t, want, have)
  185. }
  186. select {
  187. case have := <-user2.ReceiveMessage():
  188. assert.Equal(t, want, have)
  189. }
  190. select {
  191. case <-user3.ReceiveMessage():
  192. assert.Fail(t, "user 3 should not receive a message")
  193. default:
  194. }
  195. }
  196. func TestInMemorySessionManager_Broadcast(t *testing.T) {
  197. sm := NewInMemorySessionManager(slog.Default())
  198. user1, err := sm.AddSession(context.Background(), "user-screen-name-1")
  199. assert.NoError(t, err)
  200. user1.SetSignonComplete()
  201. user2, err := sm.AddSession(context.Background(), "user-screen-name-2")
  202. assert.NoError(t, err)
  203. user2.SetSignonComplete()
  204. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  205. sm.RelayToAll(context.Background(), want)
  206. select {
  207. case have := <-user1.ReceiveMessage():
  208. assert.Equal(t, want, have)
  209. }
  210. select {
  211. case have := <-user2.ReceiveMessage():
  212. assert.Equal(t, want, have)
  213. }
  214. }
  215. func TestInMemorySessionManager_Broadcast_SkipClosedSession(t *testing.T) {
  216. sm := NewInMemorySessionManager(slog.Default())
  217. user1, err := sm.AddSession(context.Background(), "user-screen-name-1")
  218. assert.NoError(t, err)
  219. user1.SetSignonComplete()
  220. user2, err := sm.AddSession(context.Background(), "user-screen-name-2")
  221. assert.NoError(t, err)
  222. user2.SetSignonComplete()
  223. user2.Close()
  224. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  225. sm.RelayToAll(context.Background(), want)
  226. select {
  227. case have := <-user1.ReceiveMessage():
  228. assert.Equal(t, want, have)
  229. }
  230. select {
  231. case <-user2.ReceiveMessage():
  232. assert.Fail(t, "user 2 should not receive a message")
  233. default:
  234. }
  235. }
  236. func TestInMemorySessionManager_RelayToScreenName_SessionExists(t *testing.T) {
  237. sm := NewInMemorySessionManager(slog.Default())
  238. user1, err := sm.AddSession(context.Background(), "user-screen-name-1")
  239. assert.NoError(t, err)
  240. user1.SetSignonComplete()
  241. user2, err := sm.AddSession(context.Background(), "user-screen-name-2")
  242. assert.NoError(t, err)
  243. user2.SetSignonComplete()
  244. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  245. recip := NewIdentScreenName("user-screen-name-1")
  246. sm.RelayToScreenName(context.Background(), recip, want)
  247. select {
  248. case have := <-user1.ReceiveMessage():
  249. assert.Equal(t, want, have)
  250. }
  251. select {
  252. case <-user2.ReceiveMessage():
  253. assert.Fail(t, "user 2 should not receive a message")
  254. default:
  255. }
  256. }
  257. func TestInMemorySessionManager_RelayToScreenName_SessionNotExist(t *testing.T) {
  258. sm := NewInMemorySessionManager(slog.Default())
  259. user1, err := sm.AddSession(context.Background(), "user-screen-name-1")
  260. assert.NoError(t, err)
  261. user1.SetSignonComplete()
  262. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  263. recip := NewIdentScreenName("user-screen-name-2")
  264. sm.RelayToScreenName(context.Background(), recip, want)
  265. select {
  266. case <-user1.ReceiveMessage():
  267. assert.Fail(t, "user 1 should not receive a message")
  268. default:
  269. }
  270. }
  271. func TestInMemorySessionManager_RelayToScreenName_SkipFullSession(t *testing.T) {
  272. sm := NewInMemorySessionManager(slog.Default())
  273. user1, err := sm.AddSession(context.Background(), "user-screen-name-1")
  274. assert.NoError(t, err)
  275. user1.SetSignonComplete()
  276. msg := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  277. wantCount := 0
  278. for {
  279. if user1.RelayMessage(msg) == SessQueueFull {
  280. break
  281. }
  282. wantCount++
  283. }
  284. recip := NewIdentScreenName("user-screen-name-1")
  285. sm.RelayToScreenName(context.Background(), recip, msg)
  286. haveCount := 0
  287. loop:
  288. for {
  289. select {
  290. case <-user1.ReceiveMessage():
  291. haveCount++
  292. default:
  293. break loop
  294. }
  295. }
  296. assert.Equal(t, wantCount, haveCount)
  297. }
  298. func TestInMemoryChatSessionManager_RelayToAllExcept_HappyPath(t *testing.T) {
  299. sm := NewInMemoryChatSessionManager(slog.Default())
  300. cookie := "the-cookie"
  301. user1, err := sm.AddSession(context.Background(), cookie, "user-screen-name-1")
  302. assert.NoError(t, err)
  303. user1.SetSignonComplete()
  304. user2, err := sm.AddSession(context.Background(), cookie, "user-screen-name-2")
  305. assert.NoError(t, err)
  306. user2.SetSignonComplete()
  307. user3, err := sm.AddSession(context.Background(), cookie, "user-screen-name-3")
  308. assert.NoError(t, err)
  309. user3.SetSignonComplete()
  310. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  311. sm.RelayToAllExcept(context.Background(), cookie, user2.IdentScreenName(), want)
  312. select {
  313. case have := <-user1.ReceiveMessage():
  314. assert.Equal(t, want, have)
  315. }
  316. select {
  317. case <-user2.ReceiveMessage():
  318. assert.Fail(t, "user 2 should not receive a message")
  319. default:
  320. }
  321. select {
  322. case have := <-user3.ReceiveMessage():
  323. assert.Equal(t, want, have)
  324. }
  325. }
  326. func TestInMemoryChatSessionManager_AllSessions_RoomExists(t *testing.T) {
  327. sm := NewInMemoryChatSessionManager(slog.Default())
  328. user1, err := sm.AddSession(context.Background(), "the-cookie", "user-screen-name-1")
  329. assert.NoError(t, err)
  330. user1.SetSignonComplete()
  331. user2, err := sm.AddSession(context.Background(), "the-cookie", "user-screen-name-2")
  332. assert.NoError(t, err)
  333. user2.SetSignonComplete()
  334. sessions := sm.AllSessions("the-cookie")
  335. assert.Len(t, sessions, 2)
  336. lookup := make(map[*Session]bool)
  337. for _, session := range sessions {
  338. lookup[session] = true
  339. }
  340. assert.True(t, lookup[user1])
  341. assert.True(t, lookup[user2])
  342. }
  343. func TestInMemoryChatSessionManager_RelayToScreenName_SessionAndChatRoomExist(t *testing.T) {
  344. sm := NewInMemoryChatSessionManager(slog.Default())
  345. user1, err := sm.AddSession(context.Background(), "chat-room-1", "user-screen-name-1")
  346. assert.NoError(t, err)
  347. user1.SetSignonComplete()
  348. user2, err := sm.AddSession(context.Background(), "chat-room-1", "user-screen-name-2")
  349. assert.NoError(t, err)
  350. user2.SetSignonComplete()
  351. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  352. recip := NewIdentScreenName("user-screen-name-1")
  353. sm.RelayToScreenName(context.Background(), "chat-room-1", recip, want)
  354. select {
  355. case have := <-user1.ReceiveMessage():
  356. assert.Equal(t, want, have)
  357. }
  358. select {
  359. case <-user2.ReceiveMessage():
  360. assert.Fail(t, "user 2 should not receive a message")
  361. default:
  362. }
  363. }
  364. func TestInMemoryChatSessionManager_RemoveSession(t *testing.T) {
  365. sm := NewInMemoryChatSessionManager(slog.Default())
  366. user1, err := sm.AddSession(context.Background(), "chat-room-1", "user-screen-name-1")
  367. assert.NoError(t, err)
  368. user1.SetSignonComplete()
  369. user2, err := sm.AddSession(context.Background(), "chat-room-1", "user-screen-name-2")
  370. assert.NoError(t, err)
  371. user2.SetSignonComplete()
  372. assert.Len(t, sm.AllSessions("chat-room-1"), 2)
  373. sm.RemoveSession(user1)
  374. sm.RemoveSession(user2)
  375. assert.Empty(t, sm.AllSessions("chat-room-1"))
  376. }
  377. func TestInMemoryChatSessionManager_RemoveSession_DoubleLogin(t *testing.T) {
  378. sm := NewInMemoryChatSessionManager(slog.Default())
  379. chatSess1, err := sm.AddSession(context.Background(), "chat-room-1", "user-screen-name-1")
  380. assert.NoError(t, err)
  381. chatSess1.SetSignonComplete()
  382. wg := &sync.WaitGroup{}
  383. wg.Add(1)
  384. go func() {
  385. // add the session again. this call blocks until RemoveSession makes
  386. // room for the new session
  387. chatSess2, err := sm.AddSession(context.Background(), "chat-room-1", "user-screen-name-1")
  388. assert.NoError(t, err)
  389. assert.NotNil(t, chatSess2)
  390. chatSess2.SetSignonComplete()
  391. assert.Equal(t, chatSess1.DisplayScreenName(), chatSess2.DisplayScreenName())
  392. wg.Done()
  393. }()
  394. // wait for AddSession() to block
  395. for sm.mapMutex.TryRLock() {
  396. sm.mapMutex.RUnlock()
  397. }
  398. // AddSession() is blocked waiting for the log. this should unblock
  399. // AddSession()
  400. sm.RemoveSession(chatSess1)
  401. wg.Wait()
  402. }
  403. func TestInMemoryChatSessionManager_RemoveUserFromAllChats(t *testing.T) {
  404. sm := NewInMemoryChatSessionManager(slog.Default())
  405. user1 := NewIdentScreenName("user-screen-name-1")
  406. user1sess, err := sm.AddSession(context.Background(), "chat-room-1", "user-screen-name-1")
  407. assert.NoError(t, err)
  408. user1sess.SetSignonComplete()
  409. user2sess, err := sm.AddSession(context.Background(), "chat-room-1", "user-screen-name-2")
  410. assert.NoError(t, err)
  411. user2sess.SetSignonComplete()
  412. assert.Len(t, sm.AllSessions("chat-room-1"), 2)
  413. sm.RemoveUserFromAllChats(user1)
  414. lookup := make(map[*Session]bool)
  415. for _, session := range sm.AllSessions("chat-room-1") {
  416. lookup[session] = true
  417. }
  418. assert.False(t, lookup[user1sess])
  419. assert.True(t, lookup[user2sess])
  420. }
  421. func TestInMemorySessionManager_RelayToAll_SkipIncompleteSignon(t *testing.T) {
  422. sm := NewInMemorySessionManager(slog.Default())
  423. user1, err := sm.AddSession(context.Background(), "user-screen-name-1")
  424. assert.NoError(t, err)
  425. user1.SetSignonComplete()
  426. user2, err := sm.AddSession(context.Background(), "user-screen-name-2")
  427. assert.NoError(t, err)
  428. // user2 has not completed signon
  429. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  430. sm.RelayToAll(context.Background(), want)
  431. select {
  432. case have := <-user1.ReceiveMessage():
  433. assert.Equal(t, want, have)
  434. }
  435. select {
  436. case <-user2.ReceiveMessage():
  437. assert.Fail(t, "user 2 should not receive a message because signon is incomplete")
  438. default:
  439. }
  440. }
  441. func TestInMemorySessionManager_RetrieveSession_IncompleteSignon(t *testing.T) {
  442. sm := NewInMemorySessionManager(slog.Default())
  443. user1, err := sm.AddSession(context.Background(), "user-screen-name-1")
  444. assert.NoError(t, err)
  445. // user1 has not completed signon
  446. sess := sm.RetrieveSession(NewIdentScreenName("user-screen-name-1"))
  447. assert.Nil(t, sess, "should return nil for session with incomplete signon")
  448. user1.SetSignonComplete()
  449. sess = sm.RetrieveSession(NewIdentScreenName("user-screen-name-1"))
  450. assert.NotNil(t, sess, "should return session after signon is complete")
  451. assert.Equal(t, user1, sess)
  452. }
  453. func TestInMemorySessionManager_RetrieveSession_CompleteSignon(t *testing.T) {
  454. sm := NewInMemorySessionManager(slog.Default())
  455. user1, err := sm.AddSession(context.Background(), "user-screen-name-1")
  456. assert.NoError(t, err)
  457. user1.SetSignonComplete()
  458. sess := sm.RetrieveSession(NewIdentScreenName("user-screen-name-1"))
  459. assert.NotNil(t, sess)
  460. assert.Equal(t, user1, sess)
  461. }
  462. func TestInMemorySessionManager_RelayToScreenNames_SkipIncompleteSignon(t *testing.T) {
  463. sm := NewInMemorySessionManager(slog.Default())
  464. user1, err := sm.AddSession(context.Background(), "user-screen-name-1")
  465. assert.NoError(t, err)
  466. user1.SetSignonComplete()
  467. user2, err := sm.AddSession(context.Background(), "user-screen-name-2")
  468. assert.NoError(t, err)
  469. // user2 has not completed signon
  470. user3, err := sm.AddSession(context.Background(), "user-screen-name-3")
  471. assert.NoError(t, err)
  472. user3.SetSignonComplete()
  473. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  474. recips := []IdentScreenName{
  475. NewIdentScreenName("user-screen-name-1"),
  476. NewIdentScreenName("user-screen-name-2"), // incomplete signon
  477. NewIdentScreenName("user-screen-name-3"),
  478. }
  479. sm.RelayToScreenNames(context.Background(), recips, want)
  480. select {
  481. case have := <-user1.ReceiveMessage():
  482. assert.Equal(t, want, have)
  483. }
  484. select {
  485. case <-user2.ReceiveMessage():
  486. assert.Fail(t, "user 2 should not receive a message because signon is incomplete")
  487. default:
  488. }
  489. select {
  490. case have := <-user3.ReceiveMessage():
  491. assert.Equal(t, want, have)
  492. }
  493. }
  494. func TestInMemorySessionManager_AllSessions_SkipIncompleteSignon(t *testing.T) {
  495. sm := NewInMemorySessionManager(slog.Default())
  496. user1, err := sm.AddSession(context.Background(), "user-screen-name-1")
  497. assert.NoError(t, err)
  498. user1.SetSignonComplete()
  499. user2, err := sm.AddSession(context.Background(), "user-screen-name-2")
  500. assert.NoError(t, err)
  501. // user2 has not completed signon
  502. user3, err := sm.AddSession(context.Background(), "user-screen-name-3")
  503. assert.NoError(t, err)
  504. user3.SetSignonComplete()
  505. sessions := sm.AllSessions()
  506. assert.Len(t, sessions, 2, "should only return sessions with complete signon")
  507. lookup := make(map[*Session]bool)
  508. for _, session := range sessions {
  509. lookup[session] = true
  510. }
  511. assert.True(t, lookup[user1], "user1 should be included (complete signon)")
  512. assert.False(t, lookup[user2], "user2 should not be included (incomplete signon)")
  513. assert.True(t, lookup[user3], "user3 should be included (complete signon)")
  514. }
  515. func TestInMemorySessionManager_RelayToScreenName_IncompleteSignon(t *testing.T) {
  516. sm := NewInMemorySessionManager(slog.Default())
  517. user1, err := sm.AddSession(context.Background(), "user-screen-name-1")
  518. assert.NoError(t, err)
  519. // user1 has not completed signon
  520. want := wire.SNACMessage{Frame: wire.SNACFrame{FoodGroup: wire.ICBM}}
  521. recip := NewIdentScreenName("user-screen-name-1")
  522. sm.RelayToScreenName(context.Background(), recip, want)
  523. select {
  524. case <-user1.ReceiveMessage():
  525. assert.Fail(t, "user 1 should not receive a message because signon is incomplete")
  526. default:
  527. }
  528. }