Просмотр исходного кода

plumb context across all layers

Mike 1 год назад
Родитель
Сommit
ffa6e14bc8
89 измененных файлов с 3531 добавлено и 3350 удалено
  1. 22 19
      .mockery.yaml
  2. 18 0
      cmd/server/factory.go
  3. 14 13
      foodgroup/admin.go
  4. 29 28
      foodgroup/admin_test.go
  5. 15 30
      foodgroup/auth.go
  6. 20 20
      foodgroup/auth_test.go
  7. 7 7
      foodgroup/bart.go
  8. 17 16
      foodgroup/bart_test.go
  9. 28 28
      foodgroup/buddy.go
  10. 120 107
      foodgroup/buddy_test.go
  11. 5 5
      foodgroup/chat_nav.go
  12. 5 5
      foodgroup/chat_nav_test.go
  13. 15 15
      foodgroup/feedbag.go
  14. 25 24
      foodgroup/feedbag_test.go
  15. 59 50
      foodgroup/helpers_test.go
  16. 9 8
      foodgroup/icbm.go
  17. 43 42
      foodgroup/icbm_test.go
  18. 18 18
      foodgroup/icq.go
  19. 39 38
      foodgroup/icq_test.go
  20. 17 16
      foodgroup/locate.go
  21. 30 30
      foodgroup/locate_test.go
  22. 136 125
      foodgroup/mock_account_manager_test.go
  23. 0 137
      foodgroup/mock_bart_manager_test.go
  24. 205 0
      foodgroup/mock_buddy_icon_manager_test.go
  25. 0 211
      foodgroup/mock_buddy_list_retriever_test.go
  26. 43 38
      foodgroup/mock_chat_room_registry_test.go
  27. 375 0
      foodgroup/mock_client_side_buddy_list_manager_test.go
  28. 66 59
      foodgroup/mock_feedbag_manager_test.go
  29. 77 70
      foodgroup/mock_icq_user_finder_test.go
  30. 68 60
      foodgroup/mock_icq_user_updater_test.go
  31. 0 366
      foodgroup/mock_local_buddy_list_manager_test.go
  32. 39 34
      foodgroup/mock_offline_message_manager_test.go
  33. 127 116
      foodgroup/mock_profile_manager_test.go
  34. 155 0
      foodgroup/mock_relationship_fetcher_test.go
  35. 28 24
      foodgroup/mock_user_manager_manager_test.go
  36. 6 6
      foodgroup/odir.go
  37. 7 6
      foodgroup/odir_test.go
  38. 20 14
      foodgroup/oservice.go
  39. 11 11
      foodgroup/oservice_test.go
  40. 15 14
      foodgroup/permit_deny.go
  41. 39 39
      foodgroup/permit_deny_test.go
  42. 235 73
      foodgroup/types.go
  43. 2 2
      foodgroup/user_lookup.go
  44. 3 2
      foodgroup/user_lookup_test.go
  45. 28 18
      server/http/helpers_test.go
  46. 32 32
      server/http/mgmt_api.go
  47. 42 40
      server/http/mgmt_api_test.go
  48. 0 254
      server/http/mock_AccountManager.go
  49. 260 0
      server/http/mock_account_manager_test.go
  50. 0 90
      server/http/mock_bart_retriever_test.go
  51. 95 0
      server/http/mock_buddy_icon_retriever_test.go
  52. 0 207
      server/http/mock_chat_account_retriever_test.go
  53. 13 10
      server/http/mock_chat_room_creator_test.go
  54. 17 14
      server/http/mock_chat_room_retriever_test.go
  55. 84 76
      server/http/mock_directory_manager_test.go
  56. 22 19
      server/http/mock_feedbag_retriever_test.go
  57. 17 14
      server/http/mock_profile_retriever_test.go
  58. 65 58
      server/http/mock_user_manager_test.go
  59. 92 32
      server/http/types.go
  60. 1 1
      server/oscar/admin.go
  61. 13 13
      server/oscar/auth.go
  62. 4 3
      server/oscar/auth_test.go
  63. 6 6
      server/oscar/bos.go
  64. 0 0
      server/oscar/handler/mock_admin_service_test.go
  65. 0 0
      server/oscar/handler/mock_bart_service_test.go
  66. 0 0
      server/oscar/handler/mock_buddy_service_test.go
  67. 0 0
      server/oscar/handler/mock_chat_nav_service_test.go
  68. 0 0
      server/oscar/handler/mock_chat_service_test.go
  69. 0 0
      server/oscar/handler/mock_feedbag_service_test.go
  70. 0 0
      server/oscar/handler/mock_icbm_service_test.go
  71. 0 0
      server/oscar/handler/mock_locate_service_test.go
  72. 0 0
      server/oscar/handler/mock_oservice_service_test.go
  73. 0 0
      server/oscar/handler/mock_permit_deny_service_test.go
  74. 15 0
      server/oscar/helpers_test.go
  75. 5 3
      server/oscar/mock_BuddyListRegistry.go
  76. 60 56
      server/oscar/mock_auth_test.go
  77. 5 5
      server/toc/cmd_client.go
  78. 6 6
      server/toc/cmd_client_test.go
  79. 10 0
      server/toc/helpers_test.go
  80. 60 56
      server/toc/mock_auth_service_test.go
  81. 24 20
      server/toc/mock_buddy_list_registry_test.go
  82. 8 8
      server/toc/mock_buddy_service_test.go
  83. 28 24
      server/toc/mock_toc_config_store_test.go
  84. 19 9
      server/toc/types.go
  85. 5 4
      state/relationship.go
  86. 9 8
      state/relationship_test.go
  87. 0 6
      state/session_manager.go
  88. 137 196
      state/user_store.go
  89. 137 136
      state/user_store_test.go

+ 22 - 19
.mockery.yaml

@@ -25,12 +25,15 @@ packages:
           filename: "mock_user_manager_test.go"
   github.com/mk6i/retro-aim-server/server/http:
     interfaces:
+      AccountManager:
+        config:
+          filename: "mock_account_manager_test.go"
       AccountRetriever:
         config:
-          filename: "mock_chat_account_retriever_test.go"
-      BARTRetriever:
+          filename: "mock_account_retriever_test.go"
+      BuddyIconRetriever:
         config:
-          filename: "mock_bart_retriever_test.go"
+          filename: "mock_buddy_icon_retriever_test.go"
       ChatRoomCreator:
         config:
           filename: "mock_chat_room_creator_test.go"
@@ -62,40 +65,40 @@ packages:
     interfaces:
       AdminService:
         config:
-          filename: "mock_admin_test.go"
+          filename: "mock_admin_service_test.go"
       BARTService:
         config:
-          filename: "mock_bart_test.go"
+          filename: "mock_bart_service_test.go"
       BuddyService:
         config:
-          filename: "mock_buddy_test.go"
+          filename: "mock_buddy_service_test.go"
       ChatNavService:
         config:
-          filename: "mock_chat_nav_test.go"
+          filename: "mock_chat_nav_service_test.go"
       ChatService:
         config:
-          filename: "mock_chat_test.go"
+          filename: "mock_chat_service_test.go"
       FeedbagService:
         config:
-          filename: "mock_feedbag_test.go"
+          filename: "mock_feedbag_service_test.go"
       ICBMService:
         config:
-          filename: "mock_icbm_test.go"
+          filename: "mock_icbm_service_test.go"
       ICQService:
         config:
           filename: "mock_icq_service_test.go"
       LocateService:
         config:
-          filename: "mock_locate_test.go"
+          filename: "mock_locate_service_test.go"
       ODirService:
         config:
           filename: "mock_odir_service_test.go"
       OServiceService:
         config:
-          filename: "mock_oservice_test.go"
+          filename: "mock_oservice_service_test.go"
       PermitDenyService:
         config:
-          filename: "mock_permit_deny_test.go"
+          filename: "mock_permit_deny_service_test.go"
       UserLookupService:
         config:
           filename: "mock_user_lookup_service_test.go"
@@ -104,15 +107,15 @@ packages:
       AccountManager:
         config:
           filename: "mock_account_manager_test.go"
-      BARTManager:
+      BuddyIconManager:
         config:
-          filename: "mock_bart_manager_test.go"
+          filename: "mock_buddy_icon_manager_test.go"
       buddyBroadcaster:
         config:
           filename: "mock_buddy_broadcaster_test.go"
-      BuddyListRetriever:
+      RelationshipFetcher:
         config:
-          filename: "mock_buddy_list_retriever_test.go"
+          filename: "mock_relationship_fetcher_test.go"
       ChatMessageRelayer:
         config:
           filename: "mock_chat_message_relayer_test.go"
@@ -137,9 +140,9 @@ packages:
       LegacyBuddyListManager:
         config:
           filename: "mock_legacy_buddy_list_manager_test.go"
-      LocalBuddyListManager:
+      ClientSideBuddyListManager:
         config:
-          filename: "mock_local_buddy_list_manager_test.go"
+          filename: "mock_client_side_buddy_list_manager_test.go"
       MessageRelayer:
         config:
           filename: "mock_message_relayer_test.go"

+ 18 - 0
cmd/server/factory.go

@@ -65,6 +65,7 @@ func Admin(deps Container) oscar.AdminServer {
 	logger := deps.logger.With("svc", "ADMIN")
 
 	adminService := foodgroup.NewAdminService(
+		deps.sqLiteUserStore,
 		deps.sqLiteUserStore,
 		deps.sqLiteUserStore,
 		deps.inMemorySessionManager,
@@ -87,6 +88,7 @@ func Admin(deps Container) oscar.AdminServer {
 		deps.inMemorySessionManager,
 		deps.sqLiteUserStore,
 		deps.inMemorySessionManager,
+		deps.sqLiteUserStore,
 	)
 
 	return oscar.AdminServer{
@@ -123,6 +125,7 @@ func Alert(deps Container) oscar.BOSServer {
 		sessionManager,
 		deps.sqLiteUserStore,
 		sessionManager,
+		deps.sqLiteUserStore,
 	)
 
 	return oscar.BOSServer{
@@ -188,6 +191,7 @@ func BART(deps Container) oscar.BOSServer {
 		sessionManager,
 		deps.sqLiteUserStore,
 		sessionManager,
+		deps.sqLiteUserStore,
 	)
 
 	return oscar.BOSServer{
@@ -229,6 +233,7 @@ func BOS(deps Container) oscar.BOSServer {
 		deps.sqLiteUserStore,
 		deps.sqLiteUserStore,
 		deps.inMemorySessionManager,
+		deps.sqLiteUserStore,
 	)
 	chatNavService := foodgroup.NewChatNavService(logger, deps.sqLiteUserStore)
 	feedbagService := foodgroup.NewFeedbagService(
@@ -240,12 +245,14 @@ func BOS(deps Container) oscar.BOSServer {
 		deps.inMemorySessionManager,
 	)
 	permitDenyService := foodgroup.NewPermitDenyService(
+		deps.sqLiteUserStore,
 		deps.sqLiteUserStore,
 		deps.sqLiteUserStore,
 		deps.inMemorySessionManager,
 		deps.inMemorySessionManager,
 	)
 	icbmService := foodgroup.NewICBMService(
+		deps.sqLiteUserStore,
 		deps.inMemorySessionManager,
 		deps.sqLiteUserStore,
 		deps.sqLiteUserStore,
@@ -254,6 +261,7 @@ func BOS(deps Container) oscar.BOSServer {
 	icqService := foodgroup.NewICQService(deps.inMemorySessionManager, deps.sqLiteUserStore, deps.sqLiteUserStore,
 		logger, deps.inMemorySessionManager, deps.sqLiteUserStore)
 	locateService := foodgroup.NewLocateService(
+		deps.sqLiteUserStore,
 		deps.inMemorySessionManager,
 		deps.sqLiteUserStore,
 		deps.sqLiteUserStore,
@@ -267,6 +275,7 @@ func BOS(deps Container) oscar.BOSServer {
 		deps.sqLiteUserStore,
 		deps.sqLiteUserStore,
 		deps.inMemorySessionManager,
+		deps.sqLiteUserStore,
 	)
 	userLookupService := foodgroup.NewUserLookupService(deps.sqLiteUserStore)
 
@@ -319,6 +328,7 @@ func Chat(deps Container) oscar.ChatServer {
 		deps.chatSessionManager,
 		deps.sqLiteUserStore,
 		sessionManager,
+		deps.sqLiteUserStore,
 	)
 
 	return oscar.ChatServer{
@@ -355,6 +365,7 @@ func ChatNav(deps Container) oscar.BOSServer {
 		sessionManager,
 		deps.sqLiteUserStore,
 		sessionManager,
+		deps.sqLiteUserStore,
 	)
 
 	return oscar.BOSServer{
@@ -422,6 +433,7 @@ func TOC(deps Container) toc.Server {
 		ListenAddr: net.JoinHostPort(deps.cfg.TOCHost, deps.cfg.TOCPort),
 		BOSProxy: toc.OSCARProxy{
 			AdminService: foodgroup.NewAdminService(
+				deps.sqLiteUserStore,
 				deps.sqLiteUserStore,
 				deps.sqLiteUserStore,
 				deps.inMemorySessionManager,
@@ -444,16 +456,19 @@ func TOC(deps Container) toc.Server {
 				deps.sqLiteUserStore,
 				deps.sqLiteUserStore,
 				deps.inMemorySessionManager,
+				deps.sqLiteUserStore,
 			),
 			CookieBaker:      deps.hmacCookieBaker,
 			DirSearchService: foodgroup.NewODirService(logger, deps.sqLiteUserStore),
 			ICBMService: foodgroup.NewICBMService(
+				deps.sqLiteUserStore,
 				deps.inMemorySessionManager,
 				deps.sqLiteUserStore,
 				deps.sqLiteUserStore,
 				deps.inMemorySessionManager,
 			),
 			LocateService: foodgroup.NewLocateService(
+				deps.sqLiteUserStore,
 				deps.inMemorySessionManager,
 				deps.sqLiteUserStore,
 				deps.sqLiteUserStore,
@@ -468,8 +483,10 @@ func TOC(deps Container) toc.Server {
 				deps.sqLiteUserStore,
 				deps.sqLiteUserStore,
 				deps.inMemorySessionManager,
+				deps.sqLiteUserStore,
 			),
 			PermitDenyService: foodgroup.NewPermitDenyService(
+				deps.sqLiteUserStore,
 				deps.sqLiteUserStore,
 				deps.sqLiteUserStore,
 				deps.inMemorySessionManager,
@@ -485,6 +502,7 @@ func TOC(deps Container) toc.Server {
 				deps.chatSessionManager,
 				deps.sqLiteUserStore,
 				sessionManager,
+				deps.sqLiteUserStore,
 			),
 			ChatNavService: foodgroup.NewChatNavService(logger, deps.sqLiteUserStore),
 		},

+ 14 - 13
foodgroup/admin.go

@@ -13,14 +13,15 @@ import (
 // NewAdminService creates an instance of AdminService.
 func NewAdminService(
 	accountManager AccountManager,
-	buddyListRetriever BuddyListRetriever,
+	buddyIconManager BuddyIconManager,
+	relationshipFetcher RelationshipFetcher,
 	messageRelayer MessageRelayer,
 	sessionRetriever SessionRetriever,
 	logger *slog.Logger,
 ) *AdminService {
 	return &AdminService{
 		accountManager:   accountManager,
-		buddyBroadcaster: newBuddyNotifier(buddyListRetriever, messageRelayer, sessionRetriever),
+		buddyBroadcaster: newBuddyNotifier(buddyIconManager, relationshipFetcher, messageRelayer, sessionRetriever),
 		messageRelayer:   messageRelayer,
 		logger:           logger,
 	}
@@ -52,21 +53,21 @@ func (s AdminService) ConfirmRequest(ctx context.Context, sess *state.Session, f
 		}
 	}
 
-	_, err := s.accountManager.EmailAddressByName(sess.IdentScreenName())
+	_, err := s.accountManager.EmailAddress(ctx, sess.IdentScreenName())
 	if errors.Is(err, state.ErrNoEmailAddress) {
 		return getAdminConfirmReply(wire.AdminAcctConfirmStatusServerError), nil
 	} else if err != nil {
 		return wire.SNACMessage{}, err
 	}
 
-	accountConfirmed, err := s.accountManager.ConfirmStatusByName(sess.IdentScreenName())
+	accountConfirmed, err := s.accountManager.ConfirmStatus(ctx, sess.IdentScreenName())
 	if err != nil {
 		return wire.SNACMessage{}, err
 	}
 	if accountConfirmed {
 		return getAdminConfirmReply(wire.AdminAcctConfirmStatusAlreadyConfirmed), nil
 	}
-	if err := s.accountManager.UpdateConfirmStatus(true, sess.IdentScreenName()); err != nil {
+	if err := s.accountManager.UpdateConfirmStatus(ctx, sess.IdentScreenName(), true); err != nil {
 		return wire.SNACMessage{}, err
 	}
 	sess.ClearUserInfoFlag(wire.OServiceUserFlagUnconfirmed)
@@ -77,7 +78,7 @@ func (s AdminService) ConfirmRequest(ctx context.Context, sess *state.Session, f
 }
 
 // InfoQuery returns the requested information about the account
-func (s AdminService) InfoQuery(_ context.Context, sess *state.Session, frame wire.SNACFrame, body wire.SNAC_0x07_0x02_AdminInfoQuery) (wire.SNACMessage, error) {
+func (s AdminService) InfoQuery(ctx context.Context, sess *state.Session, frame wire.SNACFrame, body wire.SNAC_0x07_0x02_AdminInfoQuery) (wire.SNACMessage, error) {
 	// getAdminInfoReply returns an AdminInfoReply SNAC
 	var getAdminInfoReply = func(tlvList wire.TLVList) wire.SNACMessage {
 		return wire.SNACMessage{
@@ -98,7 +99,7 @@ func (s AdminService) InfoQuery(_ context.Context, sess *state.Session, frame wi
 	tlvList := wire.TLVList{}
 
 	if _, hasRegStatus := body.TLVRestBlock.Bytes(wire.AdminTLVRegistrationStatus); hasRegStatus {
-		regStatus, err := s.accountManager.RegStatusByName(sess.IdentScreenName())
+		regStatus, err := s.accountManager.RegStatus(ctx, sess.IdentScreenName())
 		if err != nil {
 			return wire.SNACMessage{}, err
 		}
@@ -107,7 +108,7 @@ func (s AdminService) InfoQuery(_ context.Context, sess *state.Session, frame wi
 	}
 
 	if _, hasEmail := body.TLVRestBlock.Bytes(wire.AdminTLVEmailAddress); hasEmail {
-		e, err := s.accountManager.EmailAddressByName(sess.IdentScreenName())
+		e, err := s.accountManager.EmailAddress(ctx, sess.IdentScreenName())
 		if errors.Is(err, state.ErrNoEmailAddress) {
 			tlvList.Append(wire.NewTLVBE(wire.AdminTLVEmailAddress, ""))
 		} else if err != nil {
@@ -205,7 +206,7 @@ func (s AdminService) InfoChangeRequest(ctx context.Context, sess *state.Session
 			tlvList.Append(wire.NewTLVBE(wire.AdminTLVUrl, ""))
 			return getAdminChangeReply(tlvList), nil
 		}
-		if err := s.accountManager.UpdateDisplayScreenName(proposedName); err != nil {
+		if err := s.accountManager.UpdateDisplayScreenName(ctx, proposedName); err != nil {
 			return wire.SNACMessage{}, err
 		}
 		sess.SetDisplayScreenName(proposedName)
@@ -233,7 +234,7 @@ func (s AdminService) InfoChangeRequest(ctx context.Context, sess *state.Session
 			return getAdminChangeReply(tlvList), nil
 
 		}
-		if err := s.accountManager.UpdateEmailAddress(e, sess.IdentScreenName()); err != nil {
+		if err := s.accountManager.UpdateEmailAddress(ctx, sess.IdentScreenName(), e); err != nil {
 			return wire.SNACMessage{}, err
 		}
 		tlvList.Append(wire.NewTLVBE(wire.AdminTLVEmailAddress, e.Address))
@@ -246,7 +247,7 @@ func (s AdminService) InfoChangeRequest(ctx context.Context, sess *state.Session
 			wire.AdminInfoRegStatusFullDisclosure,
 			wire.AdminInfoRegStatusLimitDisclosure,
 			wire.AdminInfoRegStatusNoDisclosure:
-			if err := s.accountManager.UpdateRegStatus(regStatus, sess.IdentScreenName()); err != nil {
+			if err := s.accountManager.UpdateRegStatus(ctx, sess.IdentScreenName(), regStatus); err != nil {
 				return wire.SNACMessage{}, err
 			}
 			tlvList.Append(wire.NewTLVBE(wire.AdminTLVRegistrationStatus, regStatus))
@@ -267,7 +268,7 @@ func (s AdminService) InfoChangeRequest(ctx context.Context, sess *state.Session
 			return getAdminChangeReply(tlvList), nil
 		}
 
-		u, err := s.accountManager.User(sess.IdentScreenName())
+		u, err := s.accountManager.User(ctx, sess.IdentScreenName())
 		if err != nil || u == nil {
 			if err != nil {
 				s.logger.ErrorContext(ctx, "accountManager.User: runtime error", "err", err)
@@ -283,7 +284,7 @@ func (s AdminService) InfoChangeRequest(ctx context.Context, sess *state.Session
 			return getAdminChangeReply(tlvList), nil
 		}
 
-		if err := s.accountManager.SetUserPassword(sess.IdentScreenName(), newPass); err != nil {
+		if err := s.accountManager.SetUserPassword(ctx, sess.IdentScreenName(), newPass); err != nil {
 			if errors.Is(err, state.ErrPasswordInvalid) {
 				tlvList.Append(wire.NewTLVBE(wire.AdminTLVErrorCode, wire.AdminInfoErrorInvalidPasswordLength))
 			} else {

+ 29 - 28
foodgroup/admin_test.go

@@ -1,6 +1,7 @@
 package foodgroup
 
 import (
+	"context"
 	"io"
 	"log/slog"
 	"net/mail"
@@ -55,7 +56,7 @@ func TestAdminService_ConfirmRequest(t *testing.T) {
 			},
 			mockParams: mockParams{
 				accountManagerParams: accountManagerParams{
-					accountManagerEmailAddressByNameParams: accountManagerEmailAddressByNameParams{
+					accountManagerEmailAddressParams: accountManagerEmailAddressParams{
 						{
 
 							screenName: state.NewIdentScreenName("chattingchuck"),
@@ -65,7 +66,7 @@ func TestAdminService_ConfirmRequest(t *testing.T) {
 							err: nil,
 						},
 					},
-					accountManagerConfirmStatusByNameParams: accountManagerConfirmStatusByNameParams{
+					accountManagerConfirmStatusParams: accountManagerConfirmStatusParams{
 						{
 							screenName:    state.NewIdentScreenName("chattingchuck"),
 							confirmStatus: false,
@@ -112,7 +113,7 @@ func TestAdminService_ConfirmRequest(t *testing.T) {
 			},
 			mockParams: mockParams{
 				accountManagerParams: accountManagerParams{
-					accountManagerEmailAddressByNameParams: accountManagerEmailAddressByNameParams{
+					accountManagerEmailAddressParams: accountManagerEmailAddressParams{
 						{
 
 							screenName: state.NewIdentScreenName("chattingchuck"),
@@ -122,7 +123,7 @@ func TestAdminService_ConfirmRequest(t *testing.T) {
 							err: nil,
 						},
 					},
-					accountManagerConfirmStatusByNameParams: accountManagerConfirmStatusByNameParams{
+					accountManagerConfirmStatusParams: accountManagerConfirmStatusParams{
 						{
 							screenName:    state.NewIdentScreenName("chattingchuck"),
 							confirmStatus: true,
@@ -155,7 +156,7 @@ func TestAdminService_ConfirmRequest(t *testing.T) {
 			},
 			mockParams: mockParams{
 				accountManagerParams: accountManagerParams{
-					accountManagerEmailAddressByNameParams: accountManagerEmailAddressByNameParams{
+					accountManagerEmailAddressParams: accountManagerEmailAddressParams{
 						{
 
 							screenName:   state.NewIdentScreenName("chattingchuck"),
@@ -174,19 +175,19 @@ func TestAdminService_ConfirmRequest(t *testing.T) {
 			accountManager := newMockAccountManager(t)
 			buddyBroadcaster := newMockbuddyBroadcaster(t)
 
-			for _, params := range tc.mockParams.accountManagerParams.accountManagerEmailAddressByNameParams {
+			for _, params := range tc.mockParams.accountManagerParams.accountManagerEmailAddressParams {
 				accountManager.EXPECT().
-					EmailAddressByName(params.screenName).
+					EmailAddress(matchContext(), params.screenName).
 					Return(params.emailAddress, params.err)
 			}
-			for _, params := range tc.mockParams.accountManagerParams.accountManagerConfirmStatusByNameParams {
+			for _, params := range tc.mockParams.accountManagerParams.accountManagerConfirmStatusParams {
 				accountManager.EXPECT().
-					ConfirmStatusByName(params.screenName).
+					ConfirmStatus(matchContext(), params.screenName).
 					Return(params.confirmStatus, params.err)
 			}
 			for _, params := range tc.mockParams.accountManagerParams.accountManagerUpdateConfirmStatusParams {
 				accountManager.EXPECT().
-					UpdateConfirmStatus(params.confirmStatus, params.screenName).
+					UpdateConfirmStatus(matchContext(), params.screenName, params.confirmStatus).
 					Return(params.err)
 			}
 			for _, params := range tc.mockParams.broadcastBuddyArrivedParams {
@@ -199,7 +200,7 @@ func TestAdminService_ConfirmRequest(t *testing.T) {
 				accountManager:   accountManager,
 				buddyBroadcaster: buddyBroadcaster,
 			}
-			outputSNAC, err := svc.ConfirmRequest(nil, tc.userSession, tc.inputSNAC.Frame)
+			outputSNAC, err := svc.ConfirmRequest(context.Background(), tc.userSession, tc.inputSNAC.Frame)
 			assert.ErrorIs(t, err, tc.expectErr)
 			if tc.expectErr != nil {
 				return
@@ -260,7 +261,7 @@ func TestAdminService_InfoQuery(t *testing.T) {
 			},
 			mockParams: mockParams{
 				accountManagerParams: accountManagerParams{
-					accountManagerRegStatusByNameParams: accountManagerRegStatusByNameParams{
+					accountManagerRegStatusParams: accountManagerRegStatusParams{
 						{
 							screenName: state.NewIdentScreenName("chattingchuck"),
 							regStatus:  wire.AdminInfoRegStatusLimitDisclosure,
@@ -303,7 +304,7 @@ func TestAdminService_InfoQuery(t *testing.T) {
 			},
 			mockParams: mockParams{
 				accountManagerParams: accountManagerParams{
-					accountManagerEmailAddressByNameParams: accountManagerEmailAddressByNameParams{
+					accountManagerEmailAddressParams: accountManagerEmailAddressParams{
 						{
 							screenName: state.NewIdentScreenName("chattingchuck"),
 							emailAddress: &mail.Address{
@@ -348,7 +349,7 @@ func TestAdminService_InfoQuery(t *testing.T) {
 			},
 			mockParams: mockParams{
 				accountManagerParams: accountManagerParams{
-					accountManagerEmailAddressByNameParams: accountManagerEmailAddressByNameParams{
+					accountManagerEmailAddressParams: accountManagerEmailAddressParams{
 						{
 							screenName:   state.NewIdentScreenName("chattingchuck"),
 							emailAddress: nil,
@@ -425,15 +426,15 @@ func TestAdminService_InfoQuery(t *testing.T) {
 			accountManager := newMockAccountManager(t)
 			buddyBroadcaster := newMockbuddyBroadcaster(t)
 
-			for _, params := range tc.mockParams.accountManagerParams.accountManagerRegStatusByNameParams {
+			for _, params := range tc.mockParams.accountManagerParams.accountManagerRegStatusParams {
 				accountManager.EXPECT().
-					RegStatusByName(params.screenName).
+					RegStatus(matchContext(), params.screenName).
 					Return(params.regStatus, params.err)
 			}
 
-			for _, params := range tc.mockParams.accountManagerParams.accountManagerEmailAddressByNameParams {
+			for _, params := range tc.mockParams.accountManagerParams.accountManagerEmailAddressParams {
 				accountManager.EXPECT().
-					EmailAddressByName(params.screenName).
+					EmailAddress(matchContext(), params.screenName).
 					Return(params.emailAddress, params.err)
 			}
 
@@ -442,7 +443,7 @@ func TestAdminService_InfoQuery(t *testing.T) {
 				accountManager:   accountManager,
 				buddyBroadcaster: buddyBroadcaster,
 			}
-			outputSNAC, err := svc.InfoQuery(nil, tc.userSession, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x02_AdminInfoQuery))
+			outputSNAC, err := svc.InfoQuery(context.Background(), tc.userSession, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x02_AdminInfoQuery))
 			assert.ErrorIs(t, err, tc.expectErr)
 			if tc.expectErr != nil {
 				return
@@ -644,7 +645,7 @@ func TestAdminService_InfoChangeRequest_ScreenName(t *testing.T) {
 
 			for _, params := range tc.mockParams.accountManagerParams.accountManagerUpdateDisplayScreenNameParams {
 				accountManager.EXPECT().
-					UpdateDisplayScreenName(params.displayScreenName).
+					UpdateDisplayScreenName(matchContext(), params.displayScreenName).
 					Return(params.err)
 			}
 
@@ -665,7 +666,7 @@ func TestAdminService_InfoChangeRequest_ScreenName(t *testing.T) {
 				buddyBroadcaster: mockBuddyBroadcaster,
 				messageRelayer:   messageRelayer,
 			}
-			outputSNAC, err := svc.InfoChangeRequest(nil, tc.userSession, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x04_AdminInfoChangeRequest))
+			outputSNAC, err := svc.InfoChangeRequest(context.Background(), tc.userSession, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x04_AdminInfoChangeRequest))
 			assert.ErrorIs(t, err, tc.expectErr)
 			if tc.expectErr != nil {
 				return
@@ -822,7 +823,7 @@ func TestAdminService_InfoChangeRequest_EmailAddress(t *testing.T) {
 
 			for _, params := range tc.mockParams.accountManagerParams.accountManagerUpdateEmailAddressParams {
 				accountManager.EXPECT().
-					UpdateEmailAddress(params.emailAddress, params.screenName).
+					UpdateEmailAddress(matchContext(), params.screenName, params.emailAddress).
 					Return(params.err)
 			}
 
@@ -831,7 +832,7 @@ func TestAdminService_InfoChangeRequest_EmailAddress(t *testing.T) {
 				buddyBroadcaster: buddyBroadcaster,
 				messageRelayer:   messageRelayer,
 			}
-			outputSNAC, err := svc.InfoChangeRequest(nil, tc.userSession, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x04_AdminInfoChangeRequest))
+			outputSNAC, err := svc.InfoChangeRequest(context.Background(), tc.userSession, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x04_AdminInfoChangeRequest))
 			assert.ErrorIs(t, err, tc.expectErr)
 			if tc.expectErr != nil {
 				return
@@ -946,7 +947,7 @@ func TestAdminService_InfoChangeRequest_RegStatus(t *testing.T) {
 
 			for _, params := range tc.mockParams.accountManagerParams.accountManagerUpdateRegStatusParams {
 				accountManager.EXPECT().
-					UpdateRegStatus(params.regStatus, params.screenName).
+					UpdateRegStatus(context.Background(), params.screenName, params.regStatus).
 					Return(params.err)
 			}
 
@@ -955,7 +956,7 @@ func TestAdminService_InfoChangeRequest_RegStatus(t *testing.T) {
 				buddyBroadcaster: buddyBroadcaster,
 				messageRelayer:   messageRelayer,
 			}
-			outputSNAC, err := svc.InfoChangeRequest(nil, tc.userSession, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x04_AdminInfoChangeRequest))
+			outputSNAC, err := svc.InfoChangeRequest(context.Background(), tc.userSession, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x04_AdminInfoChangeRequest))
 			assert.ErrorIs(t, err, tc.expectErr)
 			if tc.expectErr != nil {
 				return
@@ -1338,12 +1339,12 @@ func TestAdminService_InfoChangeRequest_Password(t *testing.T) {
 			accountManager := newMockAccountManager(t)
 			for _, params := range tc.mockParams.accountManagerUserParams {
 				accountManager.EXPECT().
-					User(params.screenName).
+					User(matchContext(), params.screenName).
 					Return(params.result, params.err)
 			}
 			for _, params := range tc.mockParams.accountManagerSetUserPasswordParams {
 				accountManager.EXPECT().
-					SetUserPassword(params.screenName, params.password).
+					SetUserPassword(matchContext(), params.screenName, params.password).
 					Return(params.err)
 			}
 
@@ -1351,7 +1352,7 @@ func TestAdminService_InfoChangeRequest_Password(t *testing.T) {
 				accountManager: accountManager,
 				logger:         slog.Default(),
 			}
-			outputSNAC, err := svc.InfoChangeRequest(nil, tc.userSession, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x04_AdminInfoChangeRequest))
+			outputSNAC, err := svc.InfoChangeRequest(context.Background(), tc.userSession, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x04_AdminInfoChangeRequest))
 			assert.ErrorIs(t, err, tc.expectErr)
 			if tc.expectErr != nil {
 				return

+ 15 - 30
foodgroup/auth.go

@@ -97,7 +97,7 @@ func (s AuthService) RegisterBOSSession(ctx context.Context, authCookie []byte)
 		return nil, err
 	}
 
-	u, err := s.userManager.User(c.ScreenName.IdentScreenName())
+	u, err := s.userManager.User(ctx, c.ScreenName.IdentScreenName())
 	if err != nil {
 		return nil, fmt.Errorf("failed to retrieve user: %w", err)
 	}
@@ -114,7 +114,7 @@ func (s AuthService) RegisterBOSSession(ctx context.Context, authCookie []byte)
 	}
 
 	// set the unconfirmed user info flag if this account is unconfirmed
-	if confirmed, err := s.accountManager.ConfirmStatusByName(sess.IdentScreenName()); err != nil {
+	if confirmed, err := s.accountManager.ConfirmStatus(ctx, sess.IdentScreenName()); err != nil {
 		return nil, fmt.Errorf("error setting unconfirmed user flag: %w", err)
 	} else if !confirmed {
 		sess.SetUserInfoFlag(wire.OServiceUserFlagUnconfirmed)
@@ -137,7 +137,7 @@ func (s AuthService) RegisterBOSSession(ctx context.Context, authCookie []byte)
 }
 
 // RetrieveBOSSession returns a user's existing session
-func (s AuthService) RetrieveBOSSession(authCookie []byte) (*state.Session, error) {
+func (s AuthService) RetrieveBOSSession(ctx context.Context, authCookie []byte) (*state.Session, error) {
 	buf, err := s.cookieBaker.Crack(authCookie)
 	if err != nil {
 		return nil, err
@@ -148,7 +148,7 @@ func (s AuthService) RetrieveBOSSession(authCookie []byte) (*state.Session, erro
 		return nil, err
 	}
 
-	u, err := s.userManager.User(c.ScreenName.IdentScreenName())
+	u, err := s.userManager.User(ctx, c.ScreenName.IdentScreenName())
 	if err != nil {
 		return nil, fmt.Errorf("failed to retrieve user: %w", err)
 	}
@@ -178,10 +178,7 @@ func (s AuthService) SignoutChat(ctx context.Context, sess *state.Session) {
 // request. The client uses the auth key to salt the MD5 password hash provided
 // in the subsequent login request. If the account is valid, return
 // SNAC(0x17,0x07), otherwise return SNAC(0x17,0x03).
-func (s AuthService) BUCPChallenge(
-	bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest,
-	newUUIDFn func() uuid.UUID,
-) (wire.SNACMessage, error) {
+func (s AuthService) BUCPChallenge(ctx context.Context, bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest, newUUIDFn func() uuid.UUID) (wire.SNACMessage, error) {
 
 	screenName, exists := bodyIn.String(wire.LoginTLVTagsScreenName)
 	if !exists {
@@ -190,7 +187,7 @@ func (s AuthService) BUCPChallenge(
 
 	var authKey string
 
-	user, err := s.userManager.User(state.NewIdentScreenName(screenName))
+	user, err := s.userManager.User(ctx, state.NewIdentScreenName(screenName))
 	if err != nil {
 		return wire.SNACMessage{}, err
 	}
@@ -240,12 +237,9 @@ func (s AuthService) BUCPChallenge(
 // (wire.LoginTLVTagsReconnectHere) and an authorization cookie
 // (wire.LoginTLVTagsAuthorizationCookie). Else, an error code is set
 // (wire.LoginTLVTagsErrorSubcode).
-func (s AuthService) BUCPLogin(
-	bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest,
-	newUserFn func(screenName state.DisplayScreenName) (state.User, error),
-) (wire.SNACMessage, error) {
+func (s AuthService) BUCPLogin(ctx context.Context, bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(screenName state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error) {
 
-	block, err := s.login(bodyIn.TLVList, newUserFn)
+	block, err := s.login(ctx, bodyIn.TLVList, newUserFn)
 	if err != nil {
 		return wire.SNACMessage{}, err
 	}
@@ -271,11 +265,8 @@ func (s AuthService) BUCPLogin(
 // (wire.LoginTLVTagsReconnectHere) and an authorization cookie
 // (wire.LoginTLVTagsAuthorizationCookie). Else, an error code is set
 // (wire.LoginTLVTagsErrorSubcode).
-func (s AuthService) FLAPLogin(
-	frame wire.FLAPSignonFrame,
-	newUserFn func(screenName state.DisplayScreenName) (state.User, error),
-) (wire.TLVRestBlock, error) {
-	return s.login(frame.TLVList, newUserFn)
+func (s AuthService) FLAPLogin(ctx context.Context, frame wire.FLAPSignonFrame, newUserFn func(screenName state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error) {
+	return s.login(ctx, frame.TLVList, newUserFn)
 }
 
 // loginProperties represents the properties sent by the client at login.
@@ -334,17 +325,14 @@ func (l *loginProperties) fromTLV(list wire.TLVList) error {
 
 // login validates a user's credentials and creates their session. it returns
 // metadata used in both BUCP and FLAP authentication responses.
-func (s AuthService) login(
-	tlv wire.TLVList,
-	newUserFn func(screenName state.DisplayScreenName) (state.User, error),
-) (wire.TLVRestBlock, error) {
+func (s AuthService) login(ctx context.Context, tlv wire.TLVList, newUserFn func(screenName state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error) {
 
 	props := loginProperties{}
 	if err := props.fromTLV(tlv); err != nil {
 		return wire.TLVRestBlock{}, err
 	}
 
-	user, err := s.userManager.User(props.screenName.IdentScreenName())
+	user, err := s.userManager.User(ctx, props.screenName.IdentScreenName())
 	if err != nil {
 		return wire.TLVRestBlock{}, err
 	}
@@ -353,7 +341,7 @@ func (s AuthService) login(
 		// user not found
 		if s.config.DisableAuth {
 			// auth disabled, create the user
-			return s.createUser(props, newUserFn)
+			return s.createUser(ctx, props, newUserFn)
 		}
 		// auth enabled, return separate login errors for ICQ and AIM
 		loginErr := wire.LoginErrInvalidUsernameOrPassword
@@ -392,10 +380,7 @@ func (s AuthService) login(
 	return s.loginSuccessResponse(props)
 }
 
-func (s AuthService) createUser(
-	props loginProperties,
-	newUserFn func(screenName state.DisplayScreenName) (state.User, error),
-) (wire.TLVRestBlock, error) {
+func (s AuthService) createUser(ctx context.Context, props loginProperties, newUserFn func(screenName state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error) {
 
 	var err error
 	if props.screenName.IsUIN() {
@@ -420,7 +405,7 @@ func (s AuthService) createUser(
 		return wire.TLVRestBlock{}, err
 	}
 
-	err = s.userManager.InsertUser(newUser)
+	err = s.userManager.InsertUser(ctx, newUser)
 	if err != nil {
 		return wire.TLVRestBlock{}, err
 	}

+ 20 - 20
foodgroup/auth_test.go

@@ -637,12 +637,12 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 			userManager := newMockUserManager(t)
 			for _, params := range tc.mockParams.userManagerParams.getUserParams {
 				userManager.EXPECT().
-					User(params.screenName).
+					User(matchContext(), params.screenName).
 					Return(params.result, params.err)
 			}
 			for _, params := range tc.mockParams.insertUserParams {
 				userManager.EXPECT().
-					InsertUser(params.user).
+					InsertUser(matchContext(), params.user).
 					Return(params.err)
 			}
 			cookieBaker := newMockCookieBaker(t)
@@ -657,7 +657,7 @@ func TestAuthService_BUCPLoginRequest(t *testing.T) {
 				cookieBaker: cookieBaker,
 				userManager: userManager,
 			}
-			outputSNAC, err := svc.BUCPLogin(tc.inputSNAC, tc.newUserFn)
+			outputSNAC, err := svc.BUCPLogin(context.Background(), tc.inputSNAC, tc.newUserFn)
 			assert.ErrorIs(t, err, tc.wantErr)
 			assert.Equal(t, tc.expectOutput, outputSNAC)
 		})
@@ -1096,12 +1096,12 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 			userManager := newMockUserManager(t)
 			for _, params := range tc.mockParams.userManagerParams.getUserParams {
 				userManager.EXPECT().
-					User(params.screenName).
+					User(matchContext(), params.screenName).
 					Return(params.result, params.err)
 			}
 			for _, params := range tc.mockParams.insertUserParams {
 				userManager.EXPECT().
-					InsertUser(params.user).
+					InsertUser(matchContext(), params.user).
 					Return(params.err)
 			}
 			cookieBaker := newMockCookieBaker(t)
@@ -1115,7 +1115,7 @@ func TestAuthService_FLAPLoginResponse(t *testing.T) {
 				cookieBaker: cookieBaker,
 				userManager: userManager,
 			}
-			outputSNAC, err := svc.FLAPLogin(tc.inputSNAC, tc.newUserFn)
+			outputSNAC, err := svc.FLAPLogin(context.Background(), tc.inputSNAC, tc.newUserFn)
 			assert.ErrorIs(t, err, tc.wantErr)
 			assert.Equal(t, tc.expectOutput, outputSNAC)
 		})
@@ -1274,7 +1274,7 @@ func TestAuthService_BUCPChallengeRequest(t *testing.T) {
 			userManager := newMockUserManager(t)
 			for _, params := range tc.mockParams.userManagerParams.getUserParams {
 				userManager.EXPECT().
-					User(params.screenName).
+					User(matchContext(), params.screenName).
 					Return(params.result, params.err)
 			}
 			svc := AuthService{
@@ -1284,7 +1284,7 @@ func TestAuthService_BUCPChallengeRequest(t *testing.T) {
 			fnNewUUID := func() uuid.UUID {
 				return sessUUID
 			}
-			outputSNAC, err := svc.BUCPChallenge(tc.inputSNAC, fnNewUUID)
+			outputSNAC, err := svc.BUCPChallenge(context.Background(), tc.inputSNAC, fnNewUUID)
 			assert.ErrorIs(t, err, tc.wantErr)
 			assert.Equal(t, tc.expectOutput, outputSNAC)
 		})
@@ -1382,7 +1382,7 @@ func TestAuthService_RegisterBOSSession(t *testing.T) {
 					},
 				},
 				accountManagerParams: accountManagerParams{
-					accountManagerConfirmStatusByNameParams: accountManagerConfirmStatusByNameParams{
+					accountManagerConfirmStatusParams: accountManagerConfirmStatusParams{
 						{
 							screenName:    screenName.IdentScreenName(),
 							confirmStatus: true,
@@ -1426,7 +1426,7 @@ func TestAuthService_RegisterBOSSession(t *testing.T) {
 					},
 				},
 				accountManagerParams: accountManagerParams{
-					accountManagerConfirmStatusByNameParams: accountManagerConfirmStatusByNameParams{
+					accountManagerConfirmStatusParams: accountManagerConfirmStatusParams{
 						{
 							screenName:    uin.IdentScreenName(),
 							confirmStatus: true,
@@ -1459,13 +1459,13 @@ func TestAuthService_RegisterBOSSession(t *testing.T) {
 			userManager := newMockUserManager(t)
 			for _, params := range tc.mockParams.userManagerParams.getUserParams {
 				userManager.EXPECT().
-					User(params.screenName).
+					User(matchContext(), params.screenName).
 					Return(params.result, nil)
 			}
 			accountManager := newMockAccountManager(t)
-			for _, params := range tc.mockParams.accountManagerConfirmStatusByNameParams {
+			for _, params := range tc.mockParams.accountManagerConfirmStatusParams {
 				accountManager.EXPECT().
-					ConfirmStatusByName(params.screenName).
+					ConfirmStatus(matchContext(), params.screenName).
 					Return(params.confirmStatus, nil)
 			}
 
@@ -1504,12 +1504,12 @@ func TestAuthService_RetrieveBOSSession_HappyPath(t *testing.T) {
 
 	userManager := newMockUserManager(t)
 	userManager.EXPECT().
-		User(sess.IdentScreenName()).
+		User(matchContext(), sess.IdentScreenName()).
 		Return(&state.User{IdentScreenName: sess.IdentScreenName()}, nil)
 
 	svc := NewAuthService(config.Config{}, nil, nil, userManager, cookieBaker, nil, nil, sessionRetriever)
 
-	have, err := svc.RetrieveBOSSession(authCookie)
+	have, err := svc.RetrieveBOSSession(context.Background(), authCookie)
 	assert.NoError(t, err)
 	assert.Equal(t, sess, have)
 }
@@ -1537,12 +1537,12 @@ func TestAuthService_RetrieveBOSSession_SessionNotFound(t *testing.T) {
 
 	userManager := newMockUserManager(t)
 	userManager.EXPECT().
-		User(sess.IdentScreenName()).
+		User(matchContext(), sess.IdentScreenName()).
 		Return(&state.User{IdentScreenName: sess.IdentScreenName()}, nil)
 
 	svc := NewAuthService(config.Config{}, nil, nil, userManager, cookieBaker, nil, nil, sessionRetriever)
 
-	have, err := svc.RetrieveBOSSession(authCookie)
+	have, err := svc.RetrieveBOSSession(context.Background(), authCookie)
 	assert.NoError(t, err)
 	assert.Nil(t, have)
 }
@@ -1625,7 +1625,7 @@ func TestAuthService_SignoutChat(t *testing.T) {
 			chatMessageRelayer := newMockChatMessageRelayer(t)
 			for _, params := range tt.mockParams.chatRelayToAllExceptParams {
 				chatMessageRelayer.EXPECT().
-					RelayToAllExcept(nil, tt.userSession.ChatRoomCookie(), params.screenName, params.message)
+					RelayToAllExcept(matchContext(), tt.userSession.ChatRoomCookie(), params.screenName, params.message)
 			}
 			sessionManager := newMockChatSessionRegistry(t)
 			for _, params := range tt.mockParams.removeSessionParams {
@@ -1634,7 +1634,7 @@ func TestAuthService_SignoutChat(t *testing.T) {
 			}
 
 			svc := NewAuthService(config.Config{}, nil, sessionManager, nil, nil, chatMessageRelayer, nil, nil)
-			svc.SignoutChat(nil, tt.userSession)
+			svc.SignoutChat(context.Background(), tt.userSession)
 		})
 	}
 }
@@ -1680,7 +1680,7 @@ func TestAuthService_Signout(t *testing.T) {
 			}
 			svc := NewAuthService(config.Config{}, sessionManager, nil, nil, nil, nil, nil, nil)
 
-			svc.Signout(nil, tt.userSession)
+			svc.Signout(context.Background(), tt.userSession)
 		})
 	}
 }

+ 7 - 7
foodgroup/bart.go

@@ -20,20 +20,20 @@ var blankGIF = []byte{
 
 func NewBARTService(
 	logger *slog.Logger,
-	bartManager BARTManager,
+	buddyIconManager BuddyIconManager,
 	messageRelayer MessageRelayer,
-	buddyListRetriever BuddyListRetriever,
+	relationshipFetcher RelationshipFetcher,
 	sessionRetriever SessionRetriever,
 ) BARTService {
 	return BARTService{
-		bartManager:            bartManager,
-		buddyUpdateBroadcaster: newBuddyNotifier(buddyListRetriever, messageRelayer, sessionRetriever),
+		buddyIconManager:       buddyIconManager,
+		buddyUpdateBroadcaster: newBuddyNotifier(buddyIconManager, relationshipFetcher, messageRelayer, sessionRetriever),
 		logger:                 logger,
 	}
 }
 
 type BARTService struct {
-	bartManager            BARTManager
+	buddyIconManager       BuddyIconManager
 	buddyUpdateBroadcaster buddyBroadcaster
 	logger                 *slog.Logger
 }
@@ -45,7 +45,7 @@ func (s BARTService) UpsertItem(ctx context.Context, sess *state.Session, inFram
 	}
 	hash := h.Sum(nil)
 
-	if err := s.bartManager.BARTUpsert(hash, inBody.Data); err != nil {
+	if err := s.buddyIconManager.SetBuddyIcon(ctx, hash, inBody.Data); err != nil {
 		return wire.SNACMessage{}, err
 	}
 
@@ -83,7 +83,7 @@ func (s BARTService) RetrieveItem(ctx context.Context, sess *state.Session, inFr
 		icon = blankGIF
 	} else {
 		var err error
-		if icon, err = s.bartManager.BARTRetrieve(inBody.Hash); err != nil {
+		if icon, err = s.buddyIconManager.BuddyIcon(ctx, inBody.Hash); err != nil {
 			return wire.SNACMessage{}, err
 		}
 	}

+ 17 - 16
foodgroup/bart_test.go

@@ -1,6 +1,7 @@
 package foodgroup
 
 import (
+	"context"
 	"log/slog"
 	"testing"
 
@@ -38,8 +39,8 @@ func TestBARTService_UpsertItem(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				bartManagerParams: bartManagerParams{
-					bartManagerUpsertParams: bartManagerUpsertParams{
+				buddyIconManagerParams: buddyIconManagerParams{
+					buddyIconManagerUpsertParams: buddyIconManagerUpsertParams{
 						{
 							itemHash: []byte{0x4e, 0xd9, 0xc1, 0x96, 0x45, 0xdb, 0x5a, 0xec, 0xdb, 0xf5, 0xc7, 0xa2, 0x4e, 0x8e, 0xa0, 0xed},
 							payload:  []byte{'i', 't', 'e', 'm', 'd', 'a', 't', 'a'},
@@ -76,10 +77,10 @@ func TestBARTService_UpsertItem(t *testing.T) {
 
 	for _, tc := range cases {
 		t.Run(tc.name, func(t *testing.T) {
-			bartManager := newMockBARTManager(t)
-			for _, params := range tc.mockParams.bartManagerUpsertParams {
-				bartManager.EXPECT().
-					BARTUpsert(params.itemHash, params.payload).
+			buddyIconManager := newMockBuddyIconManager(t)
+			for _, params := range tc.mockParams.buddyIconManagerUpsertParams {
+				buddyIconManager.EXPECT().
+					SetBuddyIcon(matchContext(), params.itemHash, params.payload).
 					Return(nil)
 			}
 			buddyUpdateBroadcaster := newMockbuddyBroadcaster(t)
@@ -88,10 +89,10 @@ func TestBARTService_UpsertItem(t *testing.T) {
 					BroadcastBuddyArrived(mock.Anything, matchSession(params.screenName)).
 					Return(params.err)
 			}
-			svc := NewBARTService(slog.Default(), bartManager, nil, nil, nil)
+			svc := NewBARTService(slog.Default(), buddyIconManager, nil, nil, nil)
 			svc.buddyUpdateBroadcaster = buddyUpdateBroadcaster
 
-			output, err := svc.UpsertItem(nil, tc.userSession, tc.inputSNAC.Frame,
+			output, err := svc.UpsertItem(context.Background(), tc.userSession, tc.inputSNAC.Frame,
 				tc.inputSNAC.Body.(wire.SNAC_0x10_0x02_BARTUploadQuery))
 
 			assert.NoError(t, err)
@@ -136,8 +137,8 @@ func TestBARTService_RetrieveItem(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				bartManagerParams: bartManagerParams{
-					bartManagerRetrieveParams: bartManagerRetrieveParams{
+				buddyIconManagerParams: buddyIconManagerParams{
+					buddyIconManagerRetrieveParams: buddyIconManagerRetrieveParams{
 						{
 							itemHash: []byte{0x4e, 0xd9, 0xc1, 0x96, 0x45, 0xdb, 0x5a, 0xec, 0xdb, 0xf5, 0xc7, 0xa2, 0x4e, 0x8e, 0xa0, 0xed},
 							result:   []byte{'i', 't', 'e', 'm', 'd', 'a', 't', 'a'},
@@ -206,16 +207,16 @@ func TestBARTService_RetrieveItem(t *testing.T) {
 
 	for _, tc := range cases {
 		t.Run(tc.name, func(t *testing.T) {
-			bartManager := newMockBARTManager(t)
-			for _, params := range tc.mockParams.bartManagerParams.bartManagerRetrieveParams {
-				bartManager.EXPECT().
-					BARTRetrieve(params.itemHash).
+			buddyIconManager := newMockBuddyIconManager(t)
+			for _, params := range tc.mockParams.buddyIconManagerParams.buddyIconManagerRetrieveParams {
+				buddyIconManager.EXPECT().
+					BuddyIcon(matchContext(), params.itemHash).
 					Return(params.result, nil)
 			}
 
-			svc := NewBARTService(slog.Default(), bartManager, nil, nil, nil)
+			svc := NewBARTService(slog.Default(), buddyIconManager, nil, nil, nil)
 
-			output, err := svc.RetrieveItem(nil, tc.userSession, tc.inputSNAC.Frame,
+			output, err := svc.RetrieveItem(context.Background(), tc.userSession, tc.inputSNAC.Frame,
 				tc.inputSNAC.Body.(wire.SNAC_0x10_0x04_BARTDownloadQuery))
 
 			assert.ErrorIs(t, err, tc.expectErr)

+ 28 - 28
foodgroup/buddy.go

@@ -11,20 +11,21 @@ import (
 // NewBuddyService creates a new instance of BuddyService.
 func NewBuddyService(
 	messageRelayer MessageRelayer,
-	localBuddyListManager LocalBuddyListManager,
-	buddyListRetriever BuddyListRetriever,
+	clientSideBuddyListManager ClientSideBuddyListManager,
+	relationshipFetcher RelationshipFetcher,
 	sessionRetriever SessionRetriever,
+	buddyIconManager BuddyIconManager,
 ) *BuddyService {
 	return &BuddyService{
-		buddyBroadcaster:      newBuddyNotifier(buddyListRetriever, messageRelayer, sessionRetriever),
-		localBuddyListManager: localBuddyListManager,
+		buddyBroadcaster:           newBuddyNotifier(buddyIconManager, relationshipFetcher, messageRelayer, sessionRetriever),
+		clientSideBuddyListManager: clientSideBuddyListManager,
 	}
 }
 
 // BuddyService provides functionality for the Buddy food group.
 type BuddyService struct {
-	localBuddyListManager LocalBuddyListManager
-	buddyBroadcaster      buddyBroadcaster
+	clientSideBuddyListManager ClientSideBuddyListManager
+	buddyBroadcaster           buddyBroadcaster
 }
 
 // RightsQuery returns buddy list service parameters.
@@ -57,7 +58,7 @@ func (s BuddyService) AddBuddies(
 
 	for _, entry := range inBody.Buddies {
 		sn := state.NewIdentScreenName(entry.ScreenName)
-		if err := s.localBuddyListManager.AddBuddy(sess.IdentScreenName(), sn); err != nil {
+		if err := s.clientSideBuddyListManager.AddBuddy(ctx, sess.IdentScreenName(), sn); err != nil {
 			return err
 		}
 	}
@@ -80,17 +81,13 @@ func (s BuddyService) AddBuddies(
 }
 
 // DelBuddies deletes buddies from my client-side buddy list.
-func (s BuddyService) DelBuddies(
-	ctx context.Context,
-	sess *state.Session,
-	inBody wire.SNAC_0x03_0x05_BuddyDelBuddies,
-) error {
+func (s BuddyService) DelBuddies(ctx context.Context, sess *state.Session, inBody wire.SNAC_0x03_0x05_BuddyDelBuddies) error {
 
 	var toNotify []state.IdentScreenName
 
 	for _, entry := range inBody.Buddies {
 		sn := state.NewIdentScreenName(entry.ScreenName)
-		if err := s.localBuddyListManager.RemoveBuddy(sess.IdentScreenName(), sn); err != nil {
+		if err := s.clientSideBuddyListManager.RemoveBuddy(ctx, sess.IdentScreenName(), sn); err != nil {
 			return err
 		}
 		toNotify = append(toNotify, sn)
@@ -108,23 +105,26 @@ func (s BuddyService) BroadcastBuddyDeparted(ctx context.Context, sess *state.Se
 }
 
 func newBuddyNotifier(
-	buddyListRetriever BuddyListRetriever,
+	buddyIconManager BuddyIconManager,
+	relationshipFetcher RelationshipFetcher,
 	messageRelayer MessageRelayer,
 	sessionRetriever SessionRetriever,
 ) buddyNotifier {
 	return buddyNotifier{
-		buddyListRetriever: buddyListRetriever,
-		messageRelayer:     messageRelayer,
-		sessionRetriever:   sessionRetriever,
+		buddyIconManager:    buddyIconManager,
+		relationshipFetcher: relationshipFetcher,
+		messageRelayer:      messageRelayer,
+		sessionRetriever:    sessionRetriever,
 	}
 }
 
 // buddyNotifier centralizes logic for sending buddy arrival and departure
 // notifications.
 type buddyNotifier struct {
-	buddyListRetriever BuddyListRetriever
-	messageRelayer     MessageRelayer
-	sessionRetriever   SessionRetriever
+	buddyIconManager    BuddyIconManager
+	relationshipFetcher RelationshipFetcher
+	messageRelayer      MessageRelayer
+	sessionRetriever    SessionRetriever
 }
 
 // BroadcastBuddyArrived sends the latest user info to the user's adjacent users.
@@ -132,7 +132,7 @@ type buddyNotifier struct {
 // only used to indicate the user coming online. It can also notify changes to
 // buddy icons, warning levels, invisibility status, etc.
 func (s buddyNotifier) BroadcastBuddyArrived(ctx context.Context, sess *state.Session) error {
-	users, err := s.buddyListRetriever.AllRelationships(sess.IdentScreenName(), nil)
+	users, err := s.relationshipFetcher.AllRelationships(ctx, sess.IdentScreenName(), nil)
 	if err != nil {
 		return err
 	}
@@ -146,7 +146,7 @@ func (s buddyNotifier) BroadcastBuddyArrived(ctx context.Context, sess *state.Se
 	}
 
 	userInfo := sess.TLVUserInfo()
-	if err := s.setBuddyIcon(sess.IdentScreenName(), &userInfo); err != nil {
+	if err := s.setBuddyIcon(ctx, sess.IdentScreenName(), &userInfo); err != nil {
 		return fmt.Errorf("failed to set buddy icon for %s: %w", sess.IdentScreenName().String(), err)
 	}
 
@@ -165,7 +165,7 @@ func (s buddyNotifier) BroadcastBuddyArrived(ctx context.Context, sess *state.Se
 }
 
 func (s buddyNotifier) BroadcastBuddyDeparted(ctx context.Context, sess *state.Session) error {
-	users, err := s.buddyListRetriever.AllRelationships(sess.IdentScreenName(), nil)
+	users, err := s.relationshipFetcher.AllRelationships(ctx, sess.IdentScreenName(), nil)
 	if err != nil {
 		return err
 	}
@@ -227,7 +227,7 @@ func (s buddyNotifier) BroadcastVisibility(
 	doSendDepartures bool,
 ) error {
 
-	relationships, err := s.buddyListRetriever.AllRelationships(you.IdentScreenName(), filter)
+	relationships, err := s.relationshipFetcher.AllRelationships(ctx, you.IdentScreenName(), filter)
 	if err != nil {
 		return fmt.Errorf("retrieving relationships: %w", err)
 	}
@@ -249,7 +249,7 @@ func (s buddyNotifier) BroadcastVisibility(
 			if relationship.IsOnTheirList {
 				if !buddyIconSet {
 					// lazy load your buddy icon
-					if err := s.setBuddyIcon(you.IdentScreenName(), &yourTLVInfo); err != nil {
+					if err := s.setBuddyIcon(ctx, you.IdentScreenName(), &yourTLVInfo); err != nil {
 						return fmt.Errorf("failed to set buddy icon for %s: %w", you.IdentScreenName().String(), err)
 					}
 					buddyIconSet = true
@@ -259,7 +259,7 @@ func (s buddyNotifier) BroadcastVisibility(
 			}
 			if relationship.IsOnYourList {
 				theirInfo := theirSess.TLVUserInfo()
-				if err := s.setBuddyIcon(theirSess.IdentScreenName(), &theirInfo); err != nil {
+				if err := s.setBuddyIcon(ctx, theirSess.IdentScreenName(), &theirInfo); err != nil {
 					return fmt.Errorf("failed to set buddy icon for %s: %w", you.IdentScreenName().String(), err)
 				}
 				// tell you they're online
@@ -281,8 +281,8 @@ func (s buddyNotifier) BroadcastVisibility(
 }
 
 // setBuddyIcon adds buddy icon metadata to TLV user info
-func (s buddyNotifier) setBuddyIcon(you state.IdentScreenName, myInfo *wire.TLVUserInfo) error {
-	icon, err := s.buddyListRetriever.BuddyIconRefByName(you)
+func (s buddyNotifier) setBuddyIcon(ctx context.Context, you state.IdentScreenName, myInfo *wire.TLVUserInfo) error {
+	icon, err := s.buddyIconManager.BuddyIconMetadata(ctx, you)
 	if err != nil {
 		return fmt.Errorf("retrieve buddy icon ref: %v", err)
 	}

+ 120 - 107
foodgroup/buddy_test.go

@@ -1,6 +1,7 @@
 package foodgroup
 
 import (
+	"context"
 	"testing"
 
 	"github.com/stretchr/testify/mock"
@@ -12,7 +13,7 @@ import (
 )
 
 func TestBuddyService_RightsQuery(t *testing.T) {
-	svc := NewBuddyService(nil, nil, nil, nil)
+	svc := NewBuddyService(nil, nil, nil, nil, nil)
 
 	want := wire.SNACMessage{
 		Frame: wire.SNACFrame{
@@ -66,7 +67,7 @@ func TestBuddyService_AddBuddies(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					addBuddyParams: addBuddyParams{
 						{
 							me:   state.NewIdentScreenName("user_screen_name"),
@@ -107,7 +108,7 @@ func TestBuddyService_AddBuddies(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					addBuddyParams: addBuddyParams{
 						{
 							me:   state.NewIdentScreenName("user_screen_name"),
@@ -124,10 +125,10 @@ func TestBuddyService_AddBuddies(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			localBuddyListManager := newMockLocalBuddyListManager(t)
+			clientSideBuddyListManager := newMockClientSideBuddyListManager(t)
 			for _, params := range tt.mockParams.addBuddyParams {
-				localBuddyListManager.EXPECT().
-					AddBuddy(params.me, params.them).
+				clientSideBuddyListManager.EXPECT().
+					AddBuddy(matchContext(), params.me, params.them).
 					Return(params.err)
 			}
 			mockBuddyBroadcaster := newMockbuddyBroadcaster(t)
@@ -138,11 +139,11 @@ func TestBuddyService_AddBuddies(t *testing.T) {
 			}
 
 			svc := BuddyService{
-				localBuddyListManager: localBuddyListManager,
-				buddyBroadcaster:      mockBuddyBroadcaster,
+				clientSideBuddyListManager: clientSideBuddyListManager,
+				buddyBroadcaster:           mockBuddyBroadcaster,
 			}
 
-			haveErr := svc.AddBuddies(nil, tt.sess, tt.bodyIn)
+			haveErr := svc.AddBuddies(context.Background(), tt.sess, tt.bodyIn)
 			assert.ErrorIs(t, tt.wantErr, haveErr)
 		})
 	}
@@ -189,7 +190,7 @@ func TestBuddyService_DelBuddies(t *testing.T) {
 						},
 					},
 				},
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					deleteBuddyParams: deleteBuddyParams{
 						{
 							me:   state.NewIdentScreenName("user_screen_name"),
@@ -212,19 +213,19 @@ func TestBuddyService_DelBuddies(t *testing.T) {
 					BroadcastVisibility(mock.Anything, matchSession(params.from), params.filter, true).
 					Return(params.err)
 			}
-			localBuddyListManager := newMockLocalBuddyListManager(t)
+			clientSideBuddyListManager := newMockClientSideBuddyListManager(t)
 			for _, params := range tt.mockParams.deleteBuddyParams {
-				localBuddyListManager.EXPECT().
-					RemoveBuddy(params.me, params.them).
+				clientSideBuddyListManager.EXPECT().
+					RemoveBuddy(matchContext(), params.me, params.them).
 					Return(params.err)
 			}
 
 			svc := BuddyService{
-				buddyBroadcaster:      mockBuddyBroadcaster,
-				localBuddyListManager: localBuddyListManager,
+				buddyBroadcaster:           mockBuddyBroadcaster,
+				clientSideBuddyListManager: clientSideBuddyListManager,
 			}
 
-			assert.ErrorIs(t, tt.wantErr, svc.DelBuddies(nil, tt.sess, tt.bodyIn))
+			assert.ErrorIs(t, tt.wantErr, svc.DelBuddies(context.Background(), tt.sess, tt.bodyIn))
 		})
 	}
 }
@@ -243,7 +244,21 @@ func TestBuddyNotifier_BroadcastBuddyArrived(t *testing.T) {
 			name:        "happy path",
 			userSession: newTestSession("me"),
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				buddyIconManagerParams: buddyIconManagerParams{
+					buddyIconMetadataParams: buddyIconMetadataParams{
+						{
+							screenName: state.NewIdentScreenName("me"),
+							result: &wire.BARTID{
+								Type: wire.BARTTypesBuddyIcon,
+								BARTInfo: wire.BARTInfo{
+									Flags: wire.BARTFlagsKnown,
+									Hash:  []byte{'m', 'y', 'i', 'c', 'o', 'n'},
+								},
+							},
+						},
+					},
+				},
+				relationshipFetcherParams: relationshipFetcherParams{
 					allRelationshipsParams: allRelationshipsParams{
 						{
 							screenName: state.NewIdentScreenName("me"),
@@ -287,18 +302,6 @@ func TestBuddyNotifier_BroadcastBuddyArrived(t *testing.T) {
 							},
 						},
 					},
-					buddyIconRefByNameParams: buddyIconRefByNameParams{
-						{
-							screenName: state.NewIdentScreenName("me"),
-							result: &wire.BARTID{
-								Type: wire.BARTTypesBuddyIcon,
-								BARTInfo: wire.BARTInfo{
-									Flags: wire.BARTFlagsKnown,
-									Hash:  []byte{'m', 'y', 'i', 'c', 'o', 'n'},
-								},
-							},
-						},
-					},
 				},
 				messageRelayerParams: messageRelayerParams{
 					relayToScreenNamesParams: relayToScreenNamesParams{
@@ -326,30 +329,31 @@ func TestBuddyNotifier_BroadcastBuddyArrived(t *testing.T) {
 
 	for _, tc := range cases {
 		t.Run(tc.name, func(t *testing.T) {
-			buddyListRetriever := newMockBuddyListRetriever(t)
+			relationshipFetcher := newMockRelationshipFetcher(t)
 			for _, params := range tc.mockParams.allRelationshipsParams {
-				buddyListRetriever.EXPECT().
-					AllRelationships(params.screenName, params.filter).
+				relationshipFetcher.EXPECT().
+					AllRelationships(matchContext(), params.screenName, params.filter).
 					Return(params.result, params.err)
 			}
-			for _, params := range tc.mockParams.buddyIconRefByNameParams {
-				buddyListRetriever.EXPECT().
-					BuddyIconRefByName(params.screenName).
+			buddyIconManager := newMockBuddyIconManager(t)
+			for _, params := range tc.mockParams.buddyIconMetadataParams {
+				buddyIconManager.EXPECT().
+					BuddyIconMetadata(matchContext(), params.screenName).
 					Return(params.result, params.err)
 			}
-
 			messageRelayer := newMockMessageRelayer(t)
 			for _, params := range tc.mockParams.relayToScreenNamesParams {
 				messageRelayer.EXPECT().
-					RelayToScreenNames(mock.Anything, params.screenNames, params.message)
+					RelayToScreenNames(matchContext(), params.screenNames, params.message)
 			}
 
 			svc := buddyNotifier{
-				buddyListRetriever: buddyListRetriever,
-				messageRelayer:     messageRelayer,
+				buddyIconManager:    buddyIconManager,
+				relationshipFetcher: relationshipFetcher,
+				messageRelayer:      messageRelayer,
 			}
 
-			err := svc.BroadcastBuddyArrived(nil, tc.userSession)
+			err := svc.BroadcastBuddyArrived(context.Background(), tc.userSession)
 			assert.NoError(t, err)
 		})
 	}
@@ -369,7 +373,7 @@ func TestBuddyService_BroadcastDeparture(t *testing.T) {
 			name:        "happy path",
 			userSession: newTestSession("me"),
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					allRelationshipsParams: allRelationshipsParams{
 						{
 							screenName: state.NewIdentScreenName("me"),
@@ -448,15 +452,16 @@ func TestBuddyService_BroadcastDeparture(t *testing.T) {
 
 	for _, tc := range cases {
 		t.Run(tc.name, func(t *testing.T) {
-			buddyListRetriever := newMockBuddyListRetriever(t)
+			relationshipFetcher := newMockRelationshipFetcher(t)
 			for _, params := range tc.mockParams.allRelationshipsParams {
-				buddyListRetriever.EXPECT().
-					AllRelationships(params.screenName, params.filter).
+				relationshipFetcher.EXPECT().
+					AllRelationships(matchContext(), params.screenName, params.filter).
 					Return(params.result, params.err)
 			}
-			for _, params := range tc.mockParams.buddyIconRefByNameParams {
-				buddyListRetriever.EXPECT().
-					BuddyIconRefByName(params.screenName).
+			buddyIconManager := newMockBuddyIconManager(t)
+			for _, params := range tc.mockParams.buddyIconMetadataParams {
+				buddyIconManager.EXPECT().
+					BuddyIconMetadata(matchContext(), params.screenName).
 					Return(params.result, params.err)
 			}
 
@@ -467,11 +472,11 @@ func TestBuddyService_BroadcastDeparture(t *testing.T) {
 			}
 
 			svc := buddyNotifier{
-				buddyListRetriever: buddyListRetriever,
-				messageRelayer:     messageRelayer,
+				relationshipFetcher: relationshipFetcher,
+				messageRelayer:      messageRelayer,
 			}
 
-			err := svc.BroadcastBuddyDeparted(nil, tc.userSession)
+			err := svc.BroadcastBuddyDeparted(context.Background(), tc.userSession)
 			assert.NoError(t, err)
 		})
 	}
@@ -495,7 +500,23 @@ func Test_buddyNotifier_BroadcastVisibility(t *testing.T) {
 			name:        "happy path",
 			userSession: newTestSession("me"),
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				buddyIconManagerParams: buddyIconManagerParams{
+					buddyIconMetadataParams: buddyIconMetadataParams{
+						{
+							screenName: state.NewIdentScreenName("me"),
+							result:     nil,
+						},
+						{
+							screenName: state.NewIdentScreenName("friend3-visible-on-your-list"),
+							result:     nil,
+						},
+						{
+							screenName: state.NewIdentScreenName("friend4-visible-on-both-lists"),
+							result:     nil,
+						},
+					},
+				},
+				relationshipFetcherParams: relationshipFetcherParams{
 					allRelationshipsParams: allRelationshipsParams{
 						{
 							screenName: state.NewIdentScreenName("me"),
@@ -560,20 +581,6 @@ func Test_buddyNotifier_BroadcastVisibility(t *testing.T) {
 							},
 						},
 					},
-					buddyIconRefByNameParams: buddyIconRefByNameParams{
-						{
-							screenName: state.NewIdentScreenName("me"),
-							result:     nil,
-						},
-						{
-							screenName: state.NewIdentScreenName("friend3-visible-on-your-list"),
-							result:     nil,
-						},
-						{
-							screenName: state.NewIdentScreenName("friend4-visible-on-both-lists"),
-							result:     nil,
-						},
-					},
 				},
 				messageRelayerParams: messageRelayerParams{
 					relayToScreenNameParams: relayToScreenNameParams{
@@ -650,7 +657,23 @@ func Test_buddyNotifier_BroadcastVisibility(t *testing.T) {
 			name:        "don't send departure notifications",
 			userSession: newTestSession("me"),
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				buddyIconManagerParams: buddyIconManagerParams{
+					buddyIconMetadataParams: buddyIconMetadataParams{
+						{
+							screenName: state.NewIdentScreenName("me"),
+							result:     nil,
+						},
+						{
+							screenName: state.NewIdentScreenName("friend3-visible-on-your-list"),
+							result:     nil,
+						},
+						{
+							screenName: state.NewIdentScreenName("friend4-visible-on-both-lists"),
+							result:     nil,
+						},
+					},
+				},
+				relationshipFetcherParams: relationshipFetcherParams{
 					allRelationshipsParams: allRelationshipsParams{
 						{
 							screenName: state.NewIdentScreenName("me"),
@@ -687,20 +710,6 @@ func Test_buddyNotifier_BroadcastVisibility(t *testing.T) {
 							},
 						},
 					},
-					buddyIconRefByNameParams: buddyIconRefByNameParams{
-						{
-							screenName: state.NewIdentScreenName("me"),
-							result:     nil,
-						},
-						{
-							screenName: state.NewIdentScreenName("friend3-visible-on-your-list"),
-							result:     nil,
-						},
-						{
-							screenName: state.NewIdentScreenName("friend4-visible-on-both-lists"),
-							result:     nil,
-						},
-					},
 				},
 				messageRelayerParams: messageRelayerParams{
 					relayToScreenNameParams: relayToScreenNameParams{
@@ -749,23 +758,8 @@ func Test_buddyNotifier_BroadcastVisibility(t *testing.T) {
 			name:        "users have buddy icons",
 			userSession: newTestSession("me"),
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
-					allRelationshipsParams: allRelationshipsParams{
-						{
-							screenName: state.NewIdentScreenName("me"),
-							filter:     nil,
-							result: []state.Relationship{
-								{
-									User:          state.NewIdentScreenName("friend-visible-on-both-lists"),
-									BlocksYou:     false,
-									YouBlock:      false,
-									IsOnYourList:  true,
-									IsOnTheirList: true,
-								},
-							},
-						},
-					},
-					buddyIconRefByNameParams: buddyIconRefByNameParams{
+				buddyIconManagerParams: buddyIconManagerParams{
+					buddyIconMetadataParams: buddyIconMetadataParams{
 						{
 							screenName: state.NewIdentScreenName("me"),
 							result: &wire.BARTID{
@@ -788,6 +782,23 @@ func Test_buddyNotifier_BroadcastVisibility(t *testing.T) {
 						},
 					},
 				},
+				relationshipFetcherParams: relationshipFetcherParams{
+					allRelationshipsParams: allRelationshipsParams{
+						{
+							screenName: state.NewIdentScreenName("me"),
+							filter:     nil,
+							result: []state.Relationship{
+								{
+									User:          state.NewIdentScreenName("friend-visible-on-both-lists"),
+									BlocksYou:     false,
+									YouBlock:      false,
+									IsOnYourList:  true,
+									IsOnTheirList: true,
+								},
+							},
+						},
+					},
+				},
 				messageRelayerParams: messageRelayerParams{
 					relayToScreenNameParams: relayToScreenNameParams{
 						{
@@ -833,15 +844,16 @@ func Test_buddyNotifier_BroadcastVisibility(t *testing.T) {
 
 	for _, tc := range cases {
 		t.Run(tc.name, func(t *testing.T) {
-			buddyListRetriever := newMockBuddyListRetriever(t)
+			relationshipFetcher := newMockRelationshipFetcher(t)
 			for _, params := range tc.mockParams.allRelationshipsParams {
-				buddyListRetriever.EXPECT().
-					AllRelationships(params.screenName, params.filter).
+				relationshipFetcher.EXPECT().
+					AllRelationships(matchContext(), params.screenName, params.filter).
 					Return(params.result, params.err)
 			}
-			for _, params := range tc.mockParams.buddyIconRefByNameParams {
-				buddyListRetriever.EXPECT().
-					BuddyIconRefByName(params.screenName).
+			buddyIconManager := newMockBuddyIconManager(t)
+			for _, params := range tc.mockParams.buddyIconMetadataParams {
+				buddyIconManager.EXPECT().
+					BuddyIconMetadata(matchContext(), params.screenName).
 					Return(params.result, params.err)
 			}
 			messageRelayer := newMockMessageRelayer(t)
@@ -857,12 +869,13 @@ func Test_buddyNotifier_BroadcastVisibility(t *testing.T) {
 			}
 
 			svc := buddyNotifier{
-				buddyListRetriever: buddyListRetriever,
-				messageRelayer:     messageRelayer,
-				sessionRetriever:   sessionRetriever,
+				buddyIconManager:    buddyIconManager,
+				relationshipFetcher: relationshipFetcher,
+				messageRelayer:      messageRelayer,
+				sessionRetriever:    sessionRetriever,
 			}
 
-			err := svc.BroadcastVisibility(nil, tc.userSession, tc.filter, tc.doSendDepartures)
+			err := svc.BroadcastVisibility(context.Background(), tc.userSession, tc.filter, tc.doSendDepartures)
 			assert.NoError(t, err)
 		})
 	}

+ 5 - 5
foodgroup/chat_nav.go

@@ -76,7 +76,7 @@ func (s ChatNavService) RequestChatRights(_ context.Context, inFrame wire.SNACFr
 // CreateRoom creates and returns a chat room or returns an existing chat
 // room. It returns SNAC wire.ChatNavNavInfo, which contains metadata for the
 // chat room.
-func (s ChatNavService) CreateRoom(_ context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (wire.SNACMessage, error) {
+func (s ChatNavService) CreateRoom(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate) (wire.SNACMessage, error) {
 	if err := validateExchange(inBody.Exchange); err != nil {
 		s.logger.Debug("error validating exchange: " + err.Error())
 		return sendChatNavErrorSNAC(inFrame, wire.ErrorCodeNotSupportedByHost)
@@ -91,7 +91,7 @@ func (s ChatNavService) CreateRoom(_ context.Context, sess *state.Session, inFra
 	}
 
 	// todo call ChatRoomByName and CreateChatRoom in a txn
-	room, err := s.chatRoomManager.ChatRoomByName(inBody.Exchange, name)
+	room, err := s.chatRoomManager.ChatRoomByName(ctx, inBody.Exchange, name)
 
 	switch {
 	case errors.Is(err, state.ErrChatRoomNotFound):
@@ -102,7 +102,7 @@ func (s ChatNavService) CreateRoom(_ context.Context, sess *state.Session, inFra
 
 		room = state.NewChatRoom(name, sess.IdentScreenName(), inBody.Exchange)
 
-		if err := s.chatRoomManager.CreateChatRoom(&room); err != nil {
+		if err := s.chatRoomManager.CreateChatRoom(ctx, &room); err != nil {
 			return wire.SNACMessage{}, fmt.Errorf("%w: %w", errChatNavRoomCreateFailed, err)
 		}
 		break
@@ -135,13 +135,13 @@ func (s ChatNavService) CreateRoom(_ context.Context, sess *state.Session, inFra
 
 // RequestRoomInfo returns wire.ChatNavNavInfo, which contains metadata for
 // the chat room specified in the inFrame.hmacCookie.
-func (s ChatNavService) RequestRoomInfo(_ context.Context, inFrame wire.SNACFrame, inBody wire.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (wire.SNACMessage, error) {
+func (s ChatNavService) RequestRoomInfo(ctx context.Context, inFrame wire.SNACFrame, inBody wire.SNAC_0x0D_0x04_ChatNavRequestRoomInfo) (wire.SNACMessage, error) {
 	if err := validateExchange(inBody.Exchange); err != nil {
 		s.logger.Debug("error validating exchange: " + err.Error())
 		return sendChatNavErrorSNAC(inFrame, wire.ErrorCodeNotSupportedByHost)
 	}
 
-	room, err := s.chatRoomManager.ChatRoomByCookie(inBody.Cookie)
+	room, err := s.chatRoomManager.ChatRoomByCookie(ctx, inBody.Cookie)
 	if err != nil {
 		return wire.SNACMessage{}, fmt.Errorf("%w: %w", state.ErrChatRoomNotFound, err)
 	}

+ 5 - 5
foodgroup/chat_nav_test.go

@@ -389,12 +389,12 @@ func TestChatNavService_CreateRoom(t *testing.T) {
 			chatRoomRegistry := newMockChatRoomRegistry(t)
 			for _, params := range tt.mockParams.chatRoomByNameParams {
 				chatRoomRegistry.EXPECT().
-					ChatRoomByName(params.exchange, params.name).
+					ChatRoomByName(matchContext(), params.exchange, params.name).
 					Return(params.room, params.err)
 			}
 			for _, params := range tt.mockParams.createChatRoomParams {
 				chatRoomRegistry.EXPECT().
-					CreateChatRoom(params.room).
+					CreateChatRoom(matchContext(), params.room).
 					Return(params.err)
 			}
 
@@ -581,12 +581,12 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) {
 			chatRoomRegistry := newMockChatRoomRegistry(t)
 			for _, params := range tt.mockParams.chatRoomByCookieParams {
 				chatRoomRegistry.EXPECT().
-					ChatRoomByCookie(params.cookie).
+					ChatRoomByCookie(matchContext(), params.cookie).
 					Return(params.room, params.err)
 			}
 
 			svc := NewChatNavService(slog.Default(), chatRoomRegistry)
-			got, err := svc.RequestRoomInfo(nil, tt.inputSNAC.Frame,
+			got, err := svc.RequestRoomInfo(context.Background(), tt.inputSNAC.Frame,
 				tt.inputSNAC.Body.(wire.SNAC_0x0D_0x04_ChatNavRequestRoomInfo))
 			assert.ErrorIs(t, err, tt.wantErr)
 			if tt.wantErr != nil {
@@ -600,7 +600,7 @@ func TestChatNavService_RequestRoomInfo(t *testing.T) {
 func TestChatNavService_RequestChatRights(t *testing.T) {
 	svc := NewChatNavService(nil, nil)
 
-	have := svc.RequestChatRights(nil, wire.SNACFrame{RequestID: 1234})
+	have := svc.RequestChatRights(context.Background(), wire.SNACFrame{RequestID: 1234})
 
 	want := wire.SNACMessage{
 		Frame: wire.SNACFrame{

+ 15 - 15
foodgroup/feedbag.go

@@ -17,13 +17,13 @@ func NewFeedbagService(
 	logger *slog.Logger,
 	messageRelayer MessageRelayer,
 	feedbagManager FeedbagManager,
-	bartManager BARTManager,
-	buddyListRetriever BuddyListRetriever,
+	buddyIconManager BuddyIconManager,
+	relationshipFetcher RelationshipFetcher,
 	sessionRetriever SessionRetriever,
 ) FeedbagService {
 	return FeedbagService{
-		bartManager:      bartManager,
-		buddyBroadcaster: newBuddyNotifier(buddyListRetriever, messageRelayer, sessionRetriever),
+		buddyIconManager: buddyIconManager,
+		buddyBroadcaster: newBuddyNotifier(buddyIconManager, relationshipFetcher, messageRelayer, sessionRetriever),
 		feedbagManager:   feedbagManager,
 		logger:           logger,
 		messageRelayer:   messageRelayer,
@@ -33,7 +33,7 @@ func NewFeedbagService(
 // FeedbagService provides functionality for the Feedbag food group, which
 // handles buddy list management.
 type FeedbagService struct {
-	bartManager      BARTManager
+	buddyIconManager BuddyIconManager
 	buddyBroadcaster buddyBroadcaster
 	feedbagManager   FeedbagManager
 	logger           *slog.Logger
@@ -91,8 +91,8 @@ func (s FeedbagService) RightsQuery(_ context.Context, inFrame wire.SNACFrame) w
 
 // Query fetches the user's feedbag (aka buddy list). It returns
 // wire.FeedbagReply, which contains feedbag entries.
-func (s FeedbagService) Query(_ context.Context, sess *state.Session, inFrame wire.SNACFrame) (wire.SNACMessage, error) {
-	fb, err := s.feedbagManager.Feedbag(sess.IdentScreenName())
+func (s FeedbagService) Query(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame) (wire.SNACMessage, error) {
+	fb, err := s.feedbagManager.Feedbag(ctx, sess.IdentScreenName())
 	if err != nil {
 		return wire.SNACMessage{}, err
 	}
@@ -100,7 +100,7 @@ func (s FeedbagService) Query(_ context.Context, sess *state.Session, inFrame wi
 	lm := time.UnixMilli(0)
 
 	if len(fb) > 0 {
-		lm, err = s.feedbagManager.FeedbagLastModified(sess.IdentScreenName())
+		lm, err = s.feedbagManager.FeedbagLastModified(ctx, sess.IdentScreenName())
 		if err != nil {
 			return wire.SNACMessage{}, err
 		}
@@ -124,8 +124,8 @@ func (s FeedbagService) Query(_ context.Context, sess *state.Session, inFrame wi
 // wire.FeedbagReplyNotModified if the feedbag was last modified before
 // inBody.LastUpdate, else return wire.FeedbagReply, which contains feedbag
 // entries.
-func (s FeedbagService) QueryIfModified(_ context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x13_0x05_FeedbagQueryIfModified) (wire.SNACMessage, error) {
-	fb, err := s.feedbagManager.Feedbag(sess.IdentScreenName())
+func (s FeedbagService) QueryIfModified(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x13_0x05_FeedbagQueryIfModified) (wire.SNACMessage, error) {
+	fb, err := s.feedbagManager.Feedbag(ctx, sess.IdentScreenName())
 	if err != nil {
 		return wire.SNACMessage{}, err
 	}
@@ -133,7 +133,7 @@ func (s FeedbagService) QueryIfModified(_ context.Context, sess *state.Session,
 	lm := time.UnixMilli(0)
 
 	if len(fb) > 0 {
-		lm, err = s.feedbagManager.FeedbagLastModified(sess.IdentScreenName())
+		lm, err = s.feedbagManager.FeedbagLastModified(ctx, sess.IdentScreenName())
 		if err != nil {
 			return wire.SNACMessage{}, err
 		}
@@ -192,7 +192,7 @@ func (s FeedbagService) UpsertItem(ctx context.Context, sess *state.Session, inF
 		}
 	}
 
-	if err := s.feedbagManager.FeedbagUpsert(sess.IdentScreenName(), items); err != nil {
+	if err := s.feedbagManager.FeedbagUpsert(ctx, sess.IdentScreenName(), items); err != nil {
 		return wire.SNACMessage{}, err
 	}
 
@@ -259,7 +259,7 @@ func (s FeedbagService) broadcastIconUpdate(ctx context.Context, sess *state.Ses
 			Hash:  btlv.Hash,
 		},
 	}
-	if b, err := s.bartManager.BARTRetrieve(btlv.Hash); err != nil {
+	if b, err := s.buddyIconManager.BuddyIcon(ctx, btlv.Hash); err != nil {
 		return err
 	} else if len(b) == 0 {
 		// icon doesn't exist, tell the client to upload buddy icon
@@ -293,7 +293,7 @@ func (s FeedbagService) broadcastIconUpdate(ctx context.Context, sess *state.Ses
 // Sends buddy arrival notifications to each unblocked buddy if current user is
 // visible. It returns wire.FeedbagStatus, which contains update confirmation.
 func (s FeedbagService) DeleteItem(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x13_0x0A_FeedbagDeleteItem) (wire.SNACMessage, error) {
-	if err := s.feedbagManager.FeedbagDelete(sess.IdentScreenName(), inBody.Items); err != nil {
+	if err := s.feedbagManager.FeedbagDelete(ctx, sess.IdentScreenName(), inBody.Items); err != nil {
 		return wire.SNACMessage{}, err
 	}
 
@@ -334,7 +334,7 @@ func (s FeedbagService) StartCluster(context.Context, wire.SNACFrame, wire.SNAC_
 // by AIM clients that use the feedbag food group for buddy list management (as
 // opposed to client-side management).
 func (s FeedbagService) Use(ctx context.Context, sess *state.Session) error {
-	if err := s.feedbagManager.UseFeedbag(sess.IdentScreenName()); err != nil {
+	if err := s.feedbagManager.UseFeedbag(ctx, sess.IdentScreenName()); err != nil {
 		return fmt.Errorf("could not use feedbag: %w", err)
 	}
 	return nil

+ 25 - 24
foodgroup/feedbag_test.go

@@ -1,6 +1,7 @@
 package foodgroup
 
 import (
+	"context"
 	"log/slog"
 	"testing"
 	"time"
@@ -114,19 +115,19 @@ func TestFeedbagService_Query(t *testing.T) {
 			feedbagManager := newMockFeedbagManager(t)
 			for _, params := range tc.mockParams.feedbagParams {
 				feedbagManager.EXPECT().
-					Feedbag(params.screenName).
+					Feedbag(matchContext(), params.screenName).
 					Return(params.results, nil)
 			}
 			for _, params := range tc.mockParams.feedbagLastModifiedParams {
 				feedbagManager.EXPECT().
-					FeedbagLastModified(params.screenName).
+					FeedbagLastModified(matchContext(), params.screenName).
 					Return(params.result, nil)
 			}
 
 			svc := FeedbagService{
 				feedbagManager: feedbagManager,
 			}
-			outputSNAC, err := svc.Query(nil, tc.userSession, tc.inputSNAC.Frame)
+			outputSNAC, err := svc.Query(context.Background(), tc.userSession, tc.inputSNAC.Frame)
 			assert.NoError(t, err)
 			assert.Equal(t, tc.expectOutput, outputSNAC)
 		})
@@ -289,12 +290,12 @@ func TestFeedbagService_QueryIfModified(t *testing.T) {
 			feedbagManager := newMockFeedbagManager(t)
 			for _, params := range tc.mockParams.feedbagParams {
 				feedbagManager.EXPECT().
-					Feedbag(params.screenName).
+					Feedbag(matchContext(), params.screenName).
 					Return(params.results, nil)
 			}
 			for _, params := range tc.mockParams.feedbagLastModifiedParams {
 				feedbagManager.EXPECT().
-					FeedbagLastModified(params.screenName).
+					FeedbagLastModified(matchContext(), params.screenName).
 					Return(params.result, nil)
 			}
 			//
@@ -303,7 +304,7 @@ func TestFeedbagService_QueryIfModified(t *testing.T) {
 			svc := FeedbagService{
 				feedbagManager: feedbagManager,
 			}
-			outputSNAC, err := svc.QueryIfModified(nil, tc.userSession, tc.inputSNAC.Frame,
+			outputSNAC, err := svc.QueryIfModified(context.Background(), tc.userSession, tc.inputSNAC.Frame,
 				tc.inputSNAC.Body.(wire.SNAC_0x13_0x05_FeedbagQueryIfModified))
 			assert.NoError(t, err)
 			//
@@ -317,7 +318,7 @@ func TestFeedbagService_QueryIfModified(t *testing.T) {
 func TestFeedbagService_RightsQuery(t *testing.T) {
 	svc := NewFeedbagService(nil, nil, nil, nil, nil, nil)
 
-	outputSNAC := svc.RightsQuery(nil, wire.SNACFrame{RequestID: 1234})
+	outputSNAC := svc.RightsQuery(context.Background(), wire.SNACFrame{RequestID: 1234})
 	expectSNAC := wire.SNACMessage{
 		Frame: wire.SNACFrame{
 			FoodGroup: wire.Feedbag,
@@ -663,8 +664,8 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				bartManagerParams: bartManagerParams{
-					bartManagerRetrieveParams: bartManagerRetrieveParams{
+				buddyIconManagerParams: buddyIconManagerParams{
+					buddyIconManagerRetrieveParams: buddyIconManagerRetrieveParams{
 						{
 							itemHash: []byte{'t', 'h', 'e', 'h', 'a', 's', 'h'},
 							result:   []byte{}, // icon doesn't exist
@@ -747,8 +748,8 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				bartManagerParams: bartManagerParams{
-					bartManagerRetrieveParams: bartManagerRetrieveParams{
+				buddyIconManagerParams: buddyIconManagerParams{
+					buddyIconManagerRetrieveParams: buddyIconManagerRetrieveParams{
 						{
 							itemHash: []byte{'t', 'h', 'e', 'h', 'a', 's', 'h'},
 							result:   []byte{'i', 'c', 'o', 'n', 'd', 'a', 't', 'a'},
@@ -885,7 +886,7 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 			feedbagManager := newMockFeedbagManager(t)
 			for _, params := range tc.mockParams.feedbagManagerParams.feedbagUpsertParams {
 				feedbagManager.EXPECT().
-					FeedbagUpsert(params.screenName, params.items).
+					FeedbagUpsert(matchContext(), params.screenName, params.items).
 					Return(nil)
 			}
 			messageRelayer := newMockMessageRelayer(t)
@@ -893,10 +894,10 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 				messageRelayer.EXPECT().
 					RelayToScreenName(mock.Anything, params.screenName, params.message)
 			}
-			bartManager := newMockBARTManager(t)
-			for _, params := range tc.mockParams.bartManagerParams.bartManagerRetrieveParams {
-				bartManager.EXPECT().
-					BARTRetrieve(params.itemHash).
+			buddyIconManager := newMockBuddyIconManager(t)
+			for _, params := range tc.mockParams.buddyIconManagerParams.buddyIconManagerRetrieveParams {
+				buddyIconManager.EXPECT().
+					BuddyIcon(matchContext(), params.itemHash).
 					Return(params.result, nil)
 			}
 			buddyUpdateBroadcaster := newMockbuddyBroadcaster(t)
@@ -910,9 +911,9 @@ func TestFeedbagService_UpsertItem(t *testing.T) {
 					BroadcastVisibility(mock.Anything, matchSession(params.from), params.filter, true).
 					Return(params.err)
 			}
-			svc := NewFeedbagService(slog.Default(), messageRelayer, feedbagManager, bartManager, nil, nil)
+			svc := NewFeedbagService(slog.Default(), messageRelayer, feedbagManager, buddyIconManager, nil, nil)
 			svc.buddyBroadcaster = buddyUpdateBroadcaster
-			output, err := svc.UpsertItem(nil, tc.userSession, tc.inputSNAC.Frame,
+			output, err := svc.UpsertItem(context.Background(), tc.userSession, tc.inputSNAC.Frame,
 				tc.inputSNAC.Body.(wire.SNAC_0x13_0x08_FeedbagInsertItem).Items)
 			assert.NoError(t, err)
 			assert.Equal(t, output, tc.expectOutput)
@@ -1010,7 +1011,7 @@ func TestFeedbagService_DeleteItem(t *testing.T) {
 			feedbagManager := newMockFeedbagManager(t)
 			for _, params := range tc.mockParams.feedbagManagerParams.feedbagDeleteParams {
 				feedbagManager.EXPECT().
-					FeedbagDelete(params.screenName, params.items).
+					FeedbagDelete(matchContext(), params.screenName, params.items).
 					Return(nil)
 			}
 			buddyUpdateBroadcast := newMockbuddyBroadcaster(t)
@@ -1025,7 +1026,7 @@ func TestFeedbagService_DeleteItem(t *testing.T) {
 				feedbagManager:   feedbagManager,
 				messageRelayer:   nil,
 			}
-			output, err := svc.DeleteItem(nil, tc.userSession, tc.inputSNAC.Frame,
+			output, err := svc.DeleteItem(context.Background(), tc.userSession, tc.inputSNAC.Frame,
 				tc.inputSNAC.Body.(wire.SNAC_0x13_0x0A_FeedbagDeleteItem))
 			assert.NoError(t, err)
 			assert.Equal(t, output, tc.expectOutput)
@@ -1071,13 +1072,13 @@ func TestFeedbagService_Use(t *testing.T) {
 			feedbagManager := newMockFeedbagManager(t)
 			for _, params := range tt.mockParams.buddiesParams {
 				feedbagManager.EXPECT().
-					UseFeedbag(params.screenName).
+					UseFeedbag(matchContext(), params.screenName).
 					Return(nil)
 			}
 
 			svc := NewFeedbagService(slog.Default(), nil, feedbagManager, nil, nil, nil)
 
-			haveErr := svc.Use(nil, tt.sess)
+			haveErr := svc.Use(context.Background(), tt.sess)
 			assert.ErrorIs(t, tt.wantErr, haveErr)
 		})
 	}
@@ -1170,11 +1171,11 @@ func TestFeedbagService_RespondAuthorizeToHost(t *testing.T) {
 			messageRelayer := newMockMessageRelayer(t)
 			for _, params := range tt.mockParams.relayToScreenNameParams {
 				messageRelayer.EXPECT().
-					RelayToScreenName(nil, params.screenName, params.message)
+					RelayToScreenName(matchContext(), params.screenName, params.message)
 			}
 
 			svc := NewFeedbagService(slog.Default(), messageRelayer, nil, nil, nil, nil)
-			haveErr := svc.RespondAuthorizeToHost(nil, tt.sess, wire.SNACFrame{}, tt.bodyIn)
+			haveErr := svc.RespondAuthorizeToHost(context.Background(), tt.sess, wire.SNACFrame{}, tt.bodyIn)
 			assert.ErrorIs(t, tt.wantErr, haveErr)
 		})
 	}

+ 59 - 50
foodgroup/test_helpers.go → foodgroup/helpers_test.go

@@ -1,6 +1,7 @@
 package foodgroup
 
 import (
+	"context"
 	"net/mail"
 	"net/netip"
 	"time"
@@ -15,16 +16,16 @@ import (
 // in one place for a table test
 type mockParams struct {
 	accountManagerParams
-	bartManagerParams
+	buddyIconManagerParams
 	buddyBroadcasterParams
-	buddyListRetrieverParams
+	relationshipFetcherParams
 	chatMessageRelayerParams
 	chatRoomRegistryParams
 	cookieBakerParams
 	feedbagManagerParams
 	icqUserFinderParams
 	icqUserUpdaterParams
-	localBuddyListManagerParams
+	clientSideBuddyListManagerParams
 	messageRelayerParams
 	offlineMessageManagerParams
 	profileManagerParams
@@ -33,16 +34,15 @@ type mockParams struct {
 	userManagerParams
 }
 
-// buddyListRetrieverParams is a helper struct that contains mock parameters
-// for BuddyListRetriever methods
-type buddyListRetrieverParams struct {
+// relationshipFetcherParams is a helper struct that contains mock parameters
+// for RelationshipFetcher methods
+type relationshipFetcherParams struct {
 	allRelationshipsParams
-	buddyIconRefByNameParams
 	relationshipParams
 }
 
 // allRelationshipsParams is the list of parameters passed at the mock
-// BuddyListRetriever.AllRelationships call site
+// RelationshipFetcher.AllRelationships call site
 type allRelationshipsParams []struct {
 	screenName state.IdentScreenName
 	filter     []state.IdentScreenName
@@ -50,16 +50,8 @@ type allRelationshipsParams []struct {
 	err        error
 }
 
-// buddyIconRefByNameParams is the list of parameters passed at the mock
-// BuddyListRetriever.BuddyIconRefByName call site
-type buddyIconRefByNameParams []struct {
-	screenName state.IdentScreenName
-	result     *wire.BARTID
-	err        error
-}
-
 // relationshipParams is the list of parameters passed at the mock
-// BuddyListRetriever.Relationship call site
+// RelationshipFetcher.Relationship call site
 type relationshipParams []struct {
 	me     state.IdentScreenName
 	them   state.IdentScreenName
@@ -222,27 +214,36 @@ type setMoreInfoParams []struct {
 	err  error
 }
 
-// bartManagerParams is a helper struct that contains mock parameters for
-// BARTManager methods
-type bartManagerParams struct {
-	bartManagerRetrieveParams
-	bartManagerUpsertParams
+// buddyIconManagerParams is a helper struct that contains mock parameters for
+// BuddyIconManager methods
+type buddyIconManagerParams struct {
+	buddyIconManagerRetrieveParams
+	buddyIconManagerUpsertParams
+	buddyIconMetadataParams
 }
 
-// bartManagerRetrieveParams is the list of parameters passed at the mock
-// BARTManager.BARTRetrieve call site
-type bartManagerRetrieveParams []struct {
+// buddyIconManagerRetrieveParams is the list of parameters passed at the mock
+// BuddyIconManager.BuddyIcon call site
+type buddyIconManagerRetrieveParams []struct {
 	itemHash []byte
 	result   []byte
 }
 
-// bartManagerUpsertParams is the list of parameters passed at the mock
-// BARTManager.BARTUpsert call site
-type bartManagerUpsertParams []struct {
+// buddyIconManagerUpsertParams is the list of parameters passed at the mock
+// BuddyIconManager.SetBuddyIcon call site
+type buddyIconManagerUpsertParams []struct {
 	itemHash []byte
 	payload  []byte
 }
 
+// buddyIconMetadataParams is the list of parameters passed at the mock
+// BuddyIconManager.BuddyIconMetadata call site
+type buddyIconMetadataParams []struct {
+	screenName state.IdentScreenName
+	result     *wire.BARTID
+	err        error
+}
+
 // userManagerParams is a helper struct that contains mock parameters for
 // UserManager methods
 type userManagerParams struct {
@@ -471,9 +472,9 @@ type chatRelayToScreenNameParams []struct {
 	err        error
 }
 
-// localBuddyListManagerParams is a helper struct that contains mock
-// parameters for LocalBuddyListManager methods
-type localBuddyListManagerParams struct {
+// clientSideBuddyListManagerParams is a helper struct that contains mock
+// parameters for ClientSideBuddyListManager methods
+type clientSideBuddyListManagerParams struct {
 	addBuddyParams
 	deleteBuddyParams
 	denyBuddyParams
@@ -484,7 +485,7 @@ type localBuddyListManagerParams struct {
 }
 
 // legacyBuddiesParams is the list of parameters passed at the mock
-// LocalBuddyListManager.AddBuddy call site
+// ClientSideBuddyListManager.AddBuddy call site
 type addBuddyParams []struct {
 	me   state.IdentScreenName
 	them state.IdentScreenName
@@ -492,7 +493,7 @@ type addBuddyParams []struct {
 }
 
 // legacyBuddiesParams is the list of parameters passed at the mock
-// LocalBuddyListManager.RemoveBuddy call site
+// ClientSideBuddyListManager.RemoveBuddy call site
 type deleteBuddyParams []struct {
 	me   state.IdentScreenName
 	them state.IdentScreenName
@@ -500,7 +501,7 @@ type deleteBuddyParams []struct {
 }
 
 // deleteUserParams is the list of parameters passed at the mock
-// LocalBuddyListManager.RemoveBuddy call site
+// ClientSideBuddyListManager.RemoveBuddy call site
 type denyBuddyParams []struct {
 	me   state.IdentScreenName
 	them state.IdentScreenName
@@ -508,7 +509,7 @@ type denyBuddyParams []struct {
 }
 
 // permitBuddyParams is the list of parameters passed at the mock
-// LocalBuddyListManager.PermitBuddy call site
+// ClientSideBuddyListManager.PermitBuddy call site
 type permitBuddyParams []struct {
 	me   state.IdentScreenName
 	them state.IdentScreenName
@@ -516,7 +517,7 @@ type permitBuddyParams []struct {
 }
 
 // removeDenyBuddyParams is the list of parameters passed at the mock
-// LocalBuddyListManager.RemoveDenyBuddy call site
+// ClientSideBuddyListManager.RemoveDenyBuddy call site
 type removeDenyBuddyParams []struct {
 	me   state.IdentScreenName
 	them state.IdentScreenName
@@ -524,7 +525,7 @@ type removeDenyBuddyParams []struct {
 }
 
 // removePermitBuddyParams is the list of parameters passed at the mock
-// LocalBuddyListManager.RemovePermitBuddy call site
+// ClientSideBuddyListManager.RemovePermitBuddy call site
 type removePermitBuddyParams []struct {
 	me   state.IdentScreenName
 	them state.IdentScreenName
@@ -532,7 +533,7 @@ type removePermitBuddyParams []struct {
 }
 
 // setPDModeParams is the list of parameters passed at the mock
-// LocalBuddyListManager.SetPDMode call site
+// ClientSideBuddyListManager.SetPDMode call site
 type setPDModeParams []struct {
 	userScreenName state.IdentScreenName
 	pdMode         wire.FeedbagPDMode
@@ -567,11 +568,11 @@ type cookieIssueParams []struct {
 type accountManagerParams struct {
 	accountManagerUpdateDisplayScreenNameParams
 	accountManagerUpdateEmailAddressParams
-	accountManagerEmailAddressByNameParams
+	accountManagerEmailAddressParams
 	accountManagerUpdateRegStatusParams
-	accountManagerRegStatusByNameParams
+	accountManagerRegStatusParams
 	accountManagerUpdateConfirmStatusParams
-	accountManagerConfirmStatusByNameParams
+	accountManagerConfirmStatusParams
 	accountManagerUserParams
 	accountManagerSetUserPasswordParams
 }
@@ -591,9 +592,9 @@ type accountManagerUpdateEmailAddressParams []struct {
 	err          error
 }
 
-// accountManagerEmailAddressByNameParams is the list of parameters passed at the mock
-// accountManager.EmailAddressByName call site
-type accountManagerEmailAddressByNameParams []struct {
+// accountManagerEmailAddressParams is the list of parameters passed at the mock
+// accountManager.EmailAddress call site
+type accountManagerEmailAddressParams []struct {
 	screenName   state.IdentScreenName
 	emailAddress *mail.Address
 	err          error
@@ -607,9 +608,9 @@ type accountManagerUpdateRegStatusParams []struct {
 	err        error
 }
 
-// accountManagerRegStatusByNameParams is the list of parameters passed at the mock
-// accountManager.RegStatusByName call site
-type accountManagerRegStatusByNameParams []struct {
+// accountManagerRegStatusParams is the list of parameters passed at the mock
+// accountManager.RegStatus call site
+type accountManagerRegStatusParams []struct {
 	screenName state.IdentScreenName
 	regStatus  uint16
 	err        error
@@ -623,9 +624,9 @@ type accountManagerUpdateConfirmStatusParams []struct {
 	err           error
 }
 
-// accountManagerConfirmStatusByNameParams is the list of parameters passed at the mock
-// accountManager.ConfirmStatusByName call site
-type accountManagerConfirmStatusByNameParams []struct {
+// accountManagerConfirmStatusParams is the list of parameters passed at the mock
+// accountManager.ConfirmStatus call site
+type accountManagerConfirmStatusParams []struct {
 	screenName    state.IdentScreenName
 	confirmStatus bool
 	err           error
@@ -799,3 +800,11 @@ func matchSession(mustMatch state.IdentScreenName) interface{} {
 		return mustMatch == s.IdentScreenName()
 	})
 }
+
+// matchContext matches any instance of Context interface.
+func matchContext() interface{} {
+	return mock.MatchedBy(func(ctx any) bool {
+		_, ok := ctx.(context.Context)
+		return ok
+	})
+}

+ 9 - 8
foodgroup/icbm.go

@@ -17,14 +17,15 @@ const (
 
 // NewICBMService returns a new instance of ICBMService.
 func NewICBMService(
+	buddyIconManager BuddyIconManager,
 	messageRelayer MessageRelayer,
 	offlineMessageSaver OfflineMessageManager,
-	buddyListRetriever BuddyListRetriever,
+	relationshipFetcher RelationshipFetcher,
 	sessionRetriever SessionRetriever,
 ) *ICBMService {
 	return &ICBMService{
-		buddyListRetriever:  buddyListRetriever,
-		buddyBroadcaster:    newBuddyNotifier(buddyListRetriever, messageRelayer, sessionRetriever),
+		relationshipFetcher: relationshipFetcher,
+		buddyBroadcaster:    newBuddyNotifier(buddyIconManager, relationshipFetcher, messageRelayer, sessionRetriever),
 		messageRelayer:      messageRelayer,
 		offlineMessageSaver: offlineMessageSaver,
 		timeNow:             time.Now,
@@ -36,7 +37,7 @@ func NewICBMService(
 // responsible for sending and receiving instant messages and associated
 // functionality such as warning, typing events, etc.
 type ICBMService struct {
-	buddyListRetriever  BuddyListRetriever
+	relationshipFetcher RelationshipFetcher
 	buddyBroadcaster    buddyBroadcaster
 	messageRelayer      MessageRelayer
 	offlineMessageSaver OfflineMessageManager
@@ -83,7 +84,7 @@ func newICBMErr(requestID uint32, errCode uint16) *wire.SNACMessage {
 func (s ICBMService) ChannelMsgToHost(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x04_0x06_ICBMChannelMsgToHost) (*wire.SNACMessage, error) {
 	recip := state.NewIdentScreenName(inBody.ScreenName)
 
-	rel, err := s.buddyListRetriever.Relationship(sess.IdentScreenName(), recip)
+	rel, err := s.relationshipFetcher.Relationship(ctx, sess.IdentScreenName(), recip)
 	if err != nil {
 		return nil, err
 	}
@@ -105,7 +106,7 @@ func (s ICBMService) ChannelMsgToHost(ctx context.Context, sess *state.Session,
 				Sender:    sess.IdentScreenName(),
 				Sent:      s.timeNow().UTC(),
 			}
-			if err := s.offlineMessageSaver.SaveMessage(offlineMsg); err != nil {
+			if err := s.offlineMessageSaver.SaveMessage(ctx, offlineMsg); err != nil {
 				return nil, fmt.Errorf("save ICBM offline message failed: %w", err)
 			}
 		}
@@ -208,7 +209,7 @@ func addExternalIP(sess *state.Session, tlv wire.TLV) (wire.TLV, error) {
 // ClientEvent relays SNAC wire.ICBMClientEvent typing events from the
 // sender to the recipient.
 func (s ICBMService) ClientEvent(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x04_0x14_ICBMClientEvent) error {
-	blocked, err := s.buddyListRetriever.Relationship(sess.IdentScreenName(), state.NewIdentScreenName(inBody.ScreenName))
+	blocked, err := s.relationshipFetcher.Relationship(ctx, sess.IdentScreenName(), state.NewIdentScreenName(inBody.ScreenName))
 
 	switch {
 	case err != nil:
@@ -276,7 +277,7 @@ func (s ICBMService) EvilRequest(ctx context.Context, sess *state.Session, inFra
 		}, nil
 	}
 
-	blocked, err := s.buddyListRetriever.Relationship(sess.IdentScreenName(), identScreenName)
+	blocked, err := s.relationshipFetcher.Relationship(ctx, sess.IdentScreenName(), identScreenName)
 	if err != nil {
 		return wire.SNACMessage{}, err
 	}

+ 43 - 42
foodgroup/icbm_test.go

@@ -1,6 +1,7 @@
 package foodgroup
 
 import (
+	"context"
 	"net"
 	"net/netip"
 	"testing"
@@ -34,7 +35,7 @@ func TestICBMService_ChannelMsgToHost(t *testing.T) {
 			name:          "transmit message from sender to recipient, ack message back to sender",
 			senderSession: newTestSession("sender-screen-name", sessOptWarning(10)),
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("sender-screen-name"),
@@ -125,7 +126,7 @@ func TestICBMService_ChannelMsgToHost(t *testing.T) {
 			name:          "transmit message from sender to recipient, don't ack message back to sender",
 			senderSession: newTestSession("sender-screen-name", sessOptWarning(10)),
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("sender-screen-name"),
@@ -202,7 +203,7 @@ func TestICBMService_ChannelMsgToHost(t *testing.T) {
 			name:          "don't transmit message from sender to recipient because sender has blocked recipient",
 			senderSession: newTestSession("sender-screen-name", sessOptWarning(10)),
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("sender-screen-name"),
@@ -256,7 +257,7 @@ func TestICBMService_ChannelMsgToHost(t *testing.T) {
 			name:          "don't transmit message from sender to recipient because recipient has blocked sender",
 			senderSession: newTestSession("sender-screen-name", sessOptWarning(10)),
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("sender-screen-name"),
@@ -310,7 +311,7 @@ func TestICBMService_ChannelMsgToHost(t *testing.T) {
 			name:          "don't transmit message from sender to recipient because recipient doesn't exist",
 			senderSession: newTestSession("sender-screen-name", sessOptWarning(10)),
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("sender-screen-name"),
@@ -397,7 +398,7 @@ func TestICBMService_ChannelMsgToHost(t *testing.T) {
 				return time.Date(2020, time.August, 1, 0, 0, 0, 0, time.UTC)
 			},
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("11111111"),
@@ -451,7 +452,7 @@ func TestICBMService_ChannelMsgToHost(t *testing.T) {
 			senderSession: newTestSession("sender-screen-name", sessOptWarning(10),
 				sessRemoteAddr(netip.AddrPortFrom(netip.MustParseAddr("129.168.0.1"), 0))),
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("sender-screen-name"),
@@ -538,7 +539,7 @@ func TestICBMService_ChannelMsgToHost(t *testing.T) {
 			senderSession: newTestSession("sender-screen-name", sessOptWarning(10),
 				sessRemoteAddr(netip.AddrPortFrom(netip.MustParseAddr("129.168.0.1"), 0))),
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("sender-screen-name"),
@@ -611,7 +612,7 @@ func TestICBMService_ChannelMsgToHost(t *testing.T) {
 			name:          "send rendezvous request for file transfer without IP in session, expect no IP TLV override",
 			senderSession: newTestSession("sender-screen-name", sessOptWarning(10)),
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("sender-screen-name"),
@@ -696,10 +697,10 @@ func TestICBMService_ChannelMsgToHost(t *testing.T) {
 
 	for _, tc := range cases {
 		t.Run(tc.name, func(t *testing.T) {
-			buddyListRetriever := newMockBuddyListRetriever(t)
-			for _, item := range tc.mockParams.buddyListRetrieverParams.relationshipParams {
-				buddyListRetriever.EXPECT().
-					Relationship(item.me, item.them).
+			relationshipFetcher := newMockRelationshipFetcher(t)
+			for _, item := range tc.mockParams.relationshipFetcherParams.relationshipParams {
+				relationshipFetcher.EXPECT().
+					Relationship(matchContext(), item.me, item.them).
 					Return(item.result, item.err)
 			}
 			sessionRetriever := newMockSessionRetriever(t)
@@ -716,19 +717,19 @@ func TestICBMService_ChannelMsgToHost(t *testing.T) {
 			offlineMessageManager := newMockOfflineMessageManager(t)
 			for _, params := range tc.mockParams.saveMessageParams {
 				offlineMessageManager.EXPECT().
-					SaveMessage(params.offlineMessageIn).
+					SaveMessage(matchContext(), params.offlineMessageIn).
 					Return(params.err)
 			}
 
 			svc := ICBMService{
-				buddyListRetriever:  buddyListRetriever,
+				relationshipFetcher: relationshipFetcher,
 				messageRelayer:      messageRelayer,
 				offlineMessageSaver: offlineMessageManager,
 				sessionRetriever:    sessionRetriever,
 				timeNow:             tc.timeNow,
 			}
 
-			outputSNAC, err := svc.ChannelMsgToHost(nil, tc.senderSession, tc.inputSNAC.Frame,
+			outputSNAC, err := svc.ChannelMsgToHost(context.Background(), tc.senderSession, tc.inputSNAC.Frame,
 				tc.inputSNAC.Body.(wire.SNAC_0x04_0x06_ICBMChannelMsgToHost))
 			assert.NoError(t, err)
 			assert.Equal(t, tc.expectOutput, outputSNAC)
@@ -752,7 +753,7 @@ func TestICBMService_ClientEvent(t *testing.T) {
 			name:             "transmit message from sender to recipient",
 			senderScreenName: "sender-screen-name",
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("sender-screen-name"),
@@ -804,7 +805,7 @@ func TestICBMService_ClientEvent(t *testing.T) {
 			name:             "don't transmit message from sender to recipient because sender has blocked recipient",
 			senderScreenName: "sender-screen-name",
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("sender-screen-name"),
@@ -836,24 +837,24 @@ func TestICBMService_ClientEvent(t *testing.T) {
 
 	for _, tc := range cases {
 		t.Run(tc.name, func(t *testing.T) {
-			buddyListRetriever := newMockBuddyListRetriever(t)
-			for _, item := range tc.mockParams.buddyListRetrieverParams.relationshipParams {
-				buddyListRetriever.EXPECT().
-					Relationship(item.me, item.them).
+			relationshipFetcher := newMockRelationshipFetcher(t)
+			for _, item := range tc.mockParams.relationshipFetcherParams.relationshipParams {
+				relationshipFetcher.EXPECT().
+					Relationship(matchContext(), item.me, item.them).
 					Return(item.result, item.err)
 			}
 			messageRelayer := newMockMessageRelayer(t)
 			for _, item := range tc.mockParams.relayToScreenNameParams {
 				messageRelayer.EXPECT().
-					RelayToScreenName(mock.Anything, item.screenName, item.message)
+					RelayToScreenName(matchContext(), item.screenName, item.message)
 			}
 
 			senderSession := newTestSession(tc.senderScreenName)
 			svc := ICBMService{
-				buddyListRetriever: buddyListRetriever,
-				messageRelayer:     messageRelayer,
+				relationshipFetcher: relationshipFetcher,
+				messageRelayer:      messageRelayer,
 			}
-			assert.NoError(t, svc.ClientEvent(nil, senderSession, tc.inputSNAC.Frame,
+			assert.NoError(t, svc.ClientEvent(context.Background(), senderSession, tc.inputSNAC.Frame,
 				tc.inputSNAC.Body.(wire.SNAC_0x04_0x14_ICBMClientEvent)))
 		})
 	}
@@ -904,7 +905,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 						},
 					},
 				},
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("sender-screen-name"),
@@ -976,7 +977,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 						},
 					},
 				},
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("sender-screen-name"),
@@ -1048,7 +1049,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("sender-screen-name"),
@@ -1088,7 +1089,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("sender-screen-name"),
@@ -1132,7 +1133,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 			name:          "don't transmit non-anonymous warning from sender to recipient because recipient is offline",
 			senderSession: newTestSession("sender-screen-name"),
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("sender-screen-name"),
@@ -1180,7 +1181,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 			name:          "don't transmit anonymous warning from sender to recipient because recipient is offline",
 			senderSession: newTestSession("sender-screen-name"),
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("sender-screen-name"),
@@ -1234,10 +1235,10 @@ func TestICBMService_EvilRequest(t *testing.T) {
 					BroadcastBuddyArrived(mock.Anything, matchSession(item.screenName)).
 					Return(item.err)
 			}
-			buddyListRetriever := newMockBuddyListRetriever(t)
-			for _, item := range tc.mockParams.buddyListRetrieverParams.relationshipParams {
-				buddyListRetriever.EXPECT().
-					Relationship(item.me, item.them).
+			relationshipFetcher := newMockRelationshipFetcher(t)
+			for _, item := range tc.mockParams.relationshipFetcherParams.relationshipParams {
+				relationshipFetcher.EXPECT().
+					Relationship(matchContext(), item.me, item.them).
 					Return(item.result, item.err)
 			}
 			sessionRetriever := newMockSessionRetriever(t)
@@ -1254,19 +1255,19 @@ func TestICBMService_EvilRequest(t *testing.T) {
 			offlineMessageManager := newMockOfflineMessageManager(t)
 			for _, params := range tc.mockParams.saveMessageParams {
 				offlineMessageManager.EXPECT().
-					SaveMessage(params.offlineMessageIn).
+					SaveMessage(matchContext(), params.offlineMessageIn).
 					Return(params.err)
 			}
 
 			svc := ICBMService{
 				buddyBroadcaster:    mockBuddyBroadcaster,
-				buddyListRetriever:  buddyListRetriever,
+				relationshipFetcher: relationshipFetcher,
 				messageRelayer:      messageRelayer,
 				offlineMessageSaver: offlineMessageManager,
 				sessionRetriever:    sessionRetriever,
 			}
 
-			outputSNAC, err := svc.EvilRequest(nil, tc.senderSession, tc.inputSNAC.Frame,
+			outputSNAC, err := svc.EvilRequest(context.Background(), tc.senderSession, tc.inputSNAC.Frame,
 				tc.inputSNAC.Body.(wire.SNAC_0x04_0x08_ICBMEvilRequest))
 			assert.NoError(t, err)
 			assert.Equal(t, tc.expectOutput, outputSNAC)
@@ -1275,7 +1276,7 @@ func TestICBMService_EvilRequest(t *testing.T) {
 }
 
 func TestICBMService_ParameterQuery(t *testing.T) {
-	svc := NewICBMService(nil, nil, nil, nil)
+	svc := NewICBMService(nil, nil, nil, nil, nil)
 
 	have := svc.ParameterQuery(nil, wire.SNACFrame{RequestID: 1234})
 	want := wire.SNACMessage{
@@ -1327,8 +1328,8 @@ func TestICBMService_ClientErr(t *testing.T) {
 	messageRelayer.EXPECT().
 		RelayToScreenName(mock.Anything, state.NewIdentScreenName("recipientScreenName"), expect)
 
-	svc := NewICBMService(messageRelayer, nil, nil, nil)
+	svc := NewICBMService(nil, messageRelayer, nil, nil, nil)
 
-	err := svc.ClientErr(nil, sess, wire.SNACFrame{RequestID: 1234}, inBody)
+	err := svc.ClientErr(context.Background(), sess, wire.SNACFrame{RequestID: 1234}, inBody)
 	assert.NoError(t, err)
 }

+ 18 - 18
foodgroup/icq.go

@@ -48,7 +48,7 @@ type ICQService struct {
 }
 
 func (s ICQService) DeleteMsgReq(ctx context.Context, sess *state.Session, seq uint16) error {
-	if err := s.offlineMessageManager.DeleteMessages(sess.IdentScreenName()); err != nil {
+	if err := s.offlineMessageManager.DeleteMessages(ctx, sess.IdentScreenName()); err != nil {
 		return fmt.Errorf("deleting messages: %w", err)
 	}
 	return nil
@@ -65,7 +65,7 @@ func (s ICQService) FindByICQName(ctx context.Context, sess *state.Session, req
 		ReqSubType: wire.ICQDBQueryMetaReplyLastUserFound,
 	}
 
-	res, err := s.userFinder.FindByICQName(req.FirstName, req.LastName, req.NickName)
+	res, err := s.userFinder.FindByICQName(ctx, req.FirstName, req.LastName, req.NickName)
 
 	if err != nil {
 		s.logger.Error("FindByICQName failed", "err", err.Error())
@@ -110,7 +110,7 @@ func (s ICQService) FindByICQEmail(ctx context.Context, sess *state.Session, req
 	}
 	resp.LastResult()
 
-	res, err := s.userFinder.FindByICQEmail(req.Email)
+	res, err := s.userFinder.FindByICQEmail(ctx, req.Email)
 
 	switch {
 	case errors.Is(err, state.ErrNoUser):
@@ -150,7 +150,7 @@ func (s ICQService) FindByEmail3(ctx context.Context, sess *state.Session, req w
 	}
 	resp.LastResult()
 
-	res, err := s.userFinder.FindByICQEmail(email.Email)
+	res, err := s.userFinder.FindByICQEmail(ctx, email.Email)
 
 	switch {
 	case errors.Is(err, state.ErrNoUser):
@@ -180,7 +180,7 @@ func (s ICQService) FindByICQInterests(ctx context.Context, sess *state.Session,
 	}
 
 	interests := strings.Split(req.InterestsKeyword, ",")
-	res, err := s.userFinder.FindByICQInterests(req.InterestsCode, interests)
+	res, err := s.userFinder.FindByICQInterests(ctx, req.InterestsCode, interests)
 
 	if err != nil {
 		s.logger.Error("FindByICQInterests failed", "err", err.Error())
@@ -217,7 +217,7 @@ func (s ICQService) FindByWhitePages2(ctx context.Context, sess *state.Session,
 
 	users, err := func() ([]state.User, error) {
 		if keyword, hasKeyword := req.ICQString(wire.ICQTLVTagsWhitepagesSearchKeywords); hasKeyword {
-			res, err := s.userFinder.FindByICQKeyword(keyword)
+			res, err := s.userFinder.FindByICQKeyword(ctx, keyword)
 			if err != nil {
 				return nil, fmt.Errorf("FindByICQKeyword failed: %w", err)
 			}
@@ -229,7 +229,7 @@ func (s ICQService) FindByWhitePages2(ctx context.Context, sess *state.Session,
 		bLast, hastLast := req.ICQString(wire.ICQTLVTagsLastName)
 
 		if hasNick || hasFirst || hastLast {
-			res, err := s.userFinder.FindByICQName(bFirst, bLast, bNick)
+			res, err := s.userFinder.FindByICQName(ctx, bFirst, bLast, bNick)
 			if err != nil {
 				return nil, fmt.Errorf("FindByICQName failed: %w", err)
 			}
@@ -293,7 +293,7 @@ func (s ICQService) FindByUIN(ctx context.Context, sess *state.Session, req wire
 	}
 	resp.LastResult()
 
-	res, err := s.userFinder.FindByUIN(req.UIN)
+	res, err := s.userFinder.FindByUIN(ctx, req.UIN)
 
 	switch {
 	case errors.Is(err, state.ErrNoUser):
@@ -328,7 +328,7 @@ func (s ICQService) FindByUIN2(ctx context.Context, sess *state.Session, req wir
 	}
 	resp.LastResult()
 
-	res, err := s.userFinder.FindByUIN(UIN)
+	res, err := s.userFinder.FindByUIN(ctx, UIN)
 
 	switch {
 	case errors.Is(err, state.ErrNoUser):
@@ -348,7 +348,7 @@ func (s ICQService) FindByUIN2(ctx context.Context, sess *state.Session, req wir
 
 func (s ICQService) FullUserInfo(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x051F_DBQueryMetaReqSearchByUIN, seq uint16) error {
 
-	user, err := s.userFinder.FindByUIN(req.UIN)
+	user, err := s.userFinder.FindByUIN(ctx, req.UIN)
 	if err != nil {
 		return err
 	}
@@ -388,7 +388,7 @@ func (s ICQService) FullUserInfo(ctx context.Context, sess *state.Session, req w
 }
 
 func (s ICQService) OfflineMsgReq(ctx context.Context, sess *state.Session, seq uint16) error {
-	messages, err := s.offlineMessageManager.RetrieveMessages(sess.IdentScreenName())
+	messages, err := s.offlineMessageManager.RetrieveMessages(ctx, sess.IdentScreenName())
 	if err != nil {
 		return fmt.Errorf("retrieving messages: %w", err)
 	}
@@ -479,7 +479,7 @@ func (s ICQService) SetAffiliations(ctx context.Context, sess *state.Session, re
 		CurrentKeyword3: req.Affiliations[2].Keyword,
 	}
 
-	if err := s.userUpdater.SetAffiliations(sess.IdentScreenName(), u); err != nil {
+	if err := s.userUpdater.SetAffiliations(ctx, sess.IdentScreenName(), u); err != nil {
 		return err
 	}
 
@@ -504,7 +504,7 @@ func (s ICQService) SetBasicInfo(ctx context.Context, sess *state.Session, req w
 		ZIPCode:      req.ZIP,
 	}
 
-	if err := s.userUpdater.SetBasicInfo(sess.IdentScreenName(), u); err != nil {
+	if err := s.userUpdater.SetBasicInfo(ctx, sess.IdentScreenName(), u); err != nil {
 		return err
 	}
 
@@ -533,7 +533,7 @@ func (s ICQService) SetInterests(ctx context.Context, sess *state.Session, req w
 		Keyword4: req.Interests[3].Keyword,
 	}
 
-	if err := s.userUpdater.SetInterests(sess.IdentScreenName(), u); err != nil {
+	if err := s.userUpdater.SetInterests(ctx, sess.IdentScreenName(), u); err != nil {
 		return err
 	}
 
@@ -552,7 +552,7 @@ func (s ICQService) SetMoreInfo(ctx context.Context, sess *state.Session, req wi
 		Lang3:        req.Lang3,
 	}
 
-	if err := s.userUpdater.SetMoreInfo(sess.IdentScreenName(), u); err != nil {
+	if err := s.userUpdater.SetMoreInfo(ctx, sess.IdentScreenName(), u); err != nil {
 		return err
 	}
 
@@ -569,7 +569,7 @@ func (s ICQService) SetUserNotes(ctx context.Context, sess *state.Session, req w
 		Notes: req.Notes,
 	}
 
-	if err := s.userUpdater.SetUserNotes(sess.IdentScreenName(), u); err != nil {
+	if err := s.userUpdater.SetUserNotes(ctx, sess.IdentScreenName(), u); err != nil {
 		return err
 	}
 
@@ -592,7 +592,7 @@ func (s ICQService) SetWorkInfo(ctx context.Context, sess *state.Session, req wi
 		ZIPCode:        req.ZIP,
 	}
 
-	if err := s.userUpdater.SetWorkInfo(sess.IdentScreenName(), icqWorkInfo); err != nil {
+	if err := s.userUpdater.SetWorkInfo(ctx, sess.IdentScreenName(), icqWorkInfo); err != nil {
 		return err
 	}
 
@@ -600,7 +600,7 @@ func (s ICQService) SetWorkInfo(ctx context.Context, sess *state.Session, req wi
 }
 
 func (s ICQService) ShortUserInfo(ctx context.Context, sess *state.Session, req wire.ICQ_0x07D0_0x04BA_DBQueryMetaReqShortInfo, seq uint16) error {
-	user, err := s.userFinder.FindByUIN(req.UIN)
+	user, err := s.userFinder.FindByUIN(ctx, req.UIN)
 	if err != nil {
 		return err
 	}

+ 39 - 38
foodgroup/icq_test.go

@@ -2,6 +2,7 @@ package foodgroup
 
 import (
 	"bytes"
+	"context"
 	"log/slog"
 	"testing"
 	"time"
@@ -41,12 +42,12 @@ func TestICQService_DeleteMsgReq(t *testing.T) {
 			offlineMessageManager := newMockOfflineMessageManager(t)
 			for _, params := range tt.mockParams.deleteMessagesParams {
 				offlineMessageManager.EXPECT().
-					DeleteMessages(params.recipIn).
+					DeleteMessages(matchContext(), params.recipIn).
 					Return(params.err)
 			}
 
 			s := NewICQService(nil, nil, nil, slog.Default(), nil, offlineMessageManager)
-			err := s.DeleteMsgReq(nil, tt.sess, tt.seq)
+			err := s.DeleteMsgReq(context.Background(), tt.sess, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -225,7 +226,7 @@ func TestICQService_FindByICQName(t *testing.T) {
 			userFinder := newMockICQUserFinder(t)
 			for _, params := range tt.mockParams.findByDetailsParams {
 				userFinder.EXPECT().
-					FindByICQName(params.firstName, params.lastName, params.nickName).
+					FindByICQName(matchContext(), params.firstName, params.lastName, params.nickName).
 					Return(params.result, params.err)
 			}
 
@@ -247,7 +248,7 @@ func TestICQService_FindByICQName(t *testing.T) {
 				timeNow:          tt.timeNow,
 				userFinder:       userFinder,
 			}
-			err := s.FindByICQName(nil, tt.sess, tt.req, tt.seq)
+			err := s.FindByICQName(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -361,7 +362,7 @@ func TestICQService_FindByICQEmail(t *testing.T) {
 			userFinder := newMockICQUserFinder(t)
 			for _, params := range tt.mockParams.findByEmailParams {
 				userFinder.EXPECT().
-					FindByICQEmail(params.email).
+					FindByICQEmail(matchContext(), params.email).
 					Return(params.result, params.err)
 			}
 
@@ -383,7 +384,7 @@ func TestICQService_FindByICQEmail(t *testing.T) {
 				timeNow:          tt.timeNow,
 				userFinder:       userFinder,
 			}
-			err := s.FindByICQEmail(nil, tt.sess, tt.req, tt.seq)
+			err := s.FindByICQEmail(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -503,7 +504,7 @@ func TestICQService_FindByEmail3(t *testing.T) {
 			userFinder := newMockICQUserFinder(t)
 			for _, params := range tt.mockParams.findByEmailParams {
 				userFinder.EXPECT().
-					FindByICQEmail(params.email).
+					FindByICQEmail(matchContext(), params.email).
 					Return(params.result, params.err)
 			}
 
@@ -525,7 +526,7 @@ func TestICQService_FindByEmail3(t *testing.T) {
 				timeNow:          tt.timeNow,
 				userFinder:       userFinder,
 			}
-			err := s.FindByEmail3(nil, tt.sess, tt.req, tt.seq)
+			err := s.FindByEmail3(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -639,7 +640,7 @@ func TestICQService_FindByUIN(t *testing.T) {
 			userFinder := newMockICQUserFinder(t)
 			for _, params := range tt.mockParams.findByUINParams {
 				userFinder.EXPECT().
-					FindByUIN(params.UIN).
+					FindByUIN(matchContext(), params.UIN).
 					Return(params.result, params.err)
 			}
 
@@ -661,7 +662,7 @@ func TestICQService_FindByUIN(t *testing.T) {
 				timeNow:          tt.timeNow,
 				userFinder:       userFinder,
 			}
-			err := s.FindByUIN(nil, tt.sess, tt.req, tt.seq)
+			err := s.FindByUIN(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -779,7 +780,7 @@ func TestICQService_FindByUIN2(t *testing.T) {
 			userFinder := newMockICQUserFinder(t)
 			for _, params := range tt.mockParams.findByUINParams {
 				userFinder.EXPECT().
-					FindByUIN(params.UIN).
+					FindByUIN(matchContext(), params.UIN).
 					Return(params.result, params.err)
 			}
 
@@ -801,7 +802,7 @@ func TestICQService_FindByUIN2(t *testing.T) {
 				timeNow:          tt.timeNow,
 				userFinder:       userFinder,
 			}
-			err := s.FindByUIN2(nil, tt.sess, tt.req, tt.seq)
+			err := s.FindByUIN2(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -978,7 +979,7 @@ func TestICQService_FindByWhitePages(t *testing.T) {
 			userFinder := newMockICQUserFinder(t)
 			for _, params := range tt.mockParams.findByInterestsParams {
 				userFinder.EXPECT().
-					FindByICQInterests(params.code, params.keywords).
+					FindByICQInterests(matchContext(), params.code, params.keywords).
 					Return(params.result, params.err)
 			}
 
@@ -1000,7 +1001,7 @@ func TestICQService_FindByWhitePages(t *testing.T) {
 				timeNow:          tt.timeNow,
 				userFinder:       userFinder,
 			}
-			err := s.FindByICQInterests(nil, tt.sess, tt.req, tt.seq)
+			err := s.FindByICQInterests(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -1297,12 +1298,12 @@ func TestICQService_FindByWhitePages2(t *testing.T) {
 			userFinder := newMockICQUserFinder(t)
 			for _, params := range tt.mockParams.findByKeywordParams {
 				userFinder.EXPECT().
-					FindByICQKeyword(params.keyword).
+					FindByICQKeyword(matchContext(), params.keyword).
 					Return(params.result, params.err)
 			}
 			for _, params := range tt.mockParams.findByDetailsParams {
 				userFinder.EXPECT().
-					FindByICQName(params.firstName, params.lastName, params.nickName).
+					FindByICQName(matchContext(), params.firstName, params.lastName, params.nickName).
 					Return(params.result, params.err)
 			}
 
@@ -1324,7 +1325,7 @@ func TestICQService_FindByWhitePages2(t *testing.T) {
 				timeNow:          tt.timeNow,
 				userFinder:       userFinder,
 			}
-			err := s.FindByWhitePages2(nil, tt.sess, tt.req, tt.seq)
+			err := s.FindByWhitePages2(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -1766,7 +1767,7 @@ func TestICQService_FullUserInfo(t *testing.T) {
 			userFinder := newMockICQUserFinder(t)
 			for _, params := range tt.mockParams.findByUINParams {
 				userFinder.EXPECT().
-					FindByUIN(params.UIN).
+					FindByUIN(matchContext(), params.UIN).
 					Return(params.result, params.err)
 			}
 
@@ -1780,7 +1781,7 @@ func TestICQService_FullUserInfo(t *testing.T) {
 				timeNow:        tt.timeNow,
 				userFinder:     userFinder,
 			}
-			err := s.FullUserInfo(nil, tt.sess, tt.req, tt.seq)
+			err := s.FullUserInfo(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -1949,7 +1950,7 @@ func TestICQService_OfflineMsgReq(t *testing.T) {
 			offlineMessageManager := newMockOfflineMessageManager(t)
 			for _, params := range tt.mockParams.retrieveMessagesParams {
 				offlineMessageManager.EXPECT().
-					RetrieveMessages(params.recipIn).
+					RetrieveMessages(matchContext(), params.recipIn).
 					Return(params.messagesOut, params.err)
 			}
 			messageRelayer := newMockMessageRelayer(t)
@@ -1958,7 +1959,7 @@ func TestICQService_OfflineMsgReq(t *testing.T) {
 			}
 
 			s := NewICQService(messageRelayer, nil, nil, slog.Default(), nil, offlineMessageManager)
-			err := s.OfflineMsgReq(nil, tt.sess, tt.seq)
+			err := s.OfflineMsgReq(context.Background(), tt.sess, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -2099,7 +2100,7 @@ func TestICQService_SetAffiliations(t *testing.T) {
 			userUpdater := newMockICQUserUpdater(t)
 			for _, params := range tt.mockParams.setAffiliationsParams {
 				userUpdater.EXPECT().
-					SetAffiliations(params.name, params.data).
+					SetAffiliations(matchContext(), params.name, params.data).
 					Return(params.err)
 			}
 
@@ -2112,7 +2113,7 @@ func TestICQService_SetAffiliations(t *testing.T) {
 				userUpdater:    userUpdater,
 				messageRelayer: messageRelayer,
 			}
-			err := s.SetAffiliations(nil, tt.sess, tt.req, tt.seq)
+			err := s.SetAffiliations(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.ErrorIs(t, err, tt.wantErr)
 		})
 	}
@@ -2187,7 +2188,7 @@ func TestICQService_SetEmails(t *testing.T) {
 				logger:         slog.Default(),
 				messageRelayer: messageRelayer,
 			}
-			err := s.SetEmails(nil, tt.sess, tt.req, tt.seq)
+			err := s.SetEmails(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -2284,7 +2285,7 @@ func TestICQService_SetBasicInfo(t *testing.T) {
 			userUpdater := newMockICQUserUpdater(t)
 			for _, params := range tt.mockParams.setBasicInfoParams {
 				userUpdater.EXPECT().
-					SetBasicInfo(params.name, params.data).
+					SetBasicInfo(matchContext(), params.name, params.data).
 					Return(params.err)
 			}
 
@@ -2297,7 +2298,7 @@ func TestICQService_SetBasicInfo(t *testing.T) {
 				userUpdater:    userUpdater,
 				messageRelayer: messageRelayer,
 			}
-			err := s.SetBasicInfo(nil, tt.sess, tt.req, tt.seq)
+			err := s.SetBasicInfo(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -2416,7 +2417,7 @@ func TestICQService_SetInterests(t *testing.T) {
 			userUpdater := newMockICQUserUpdater(t)
 			for _, params := range tt.mockParams.setInterestsParams {
 				userUpdater.EXPECT().
-					SetInterests(params.name, params.data).
+					SetInterests(matchContext(), params.name, params.data).
 					Return(params.err)
 			}
 
@@ -2429,7 +2430,7 @@ func TestICQService_SetInterests(t *testing.T) {
 				userUpdater:    userUpdater,
 				messageRelayer: messageRelayer,
 			}
-			err := s.SetInterests(nil, tt.sess, tt.req, tt.seq)
+			err := s.SetInterests(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.ErrorIs(t, err, tt.wantErr)
 		})
 	}
@@ -2515,7 +2516,7 @@ func TestICQService_SetMoreInfo(t *testing.T) {
 			userUpdater := newMockICQUserUpdater(t)
 			for _, params := range tt.mockParams.setMoreInfoParams {
 				userUpdater.EXPECT().
-					SetMoreInfo(params.name, params.data).
+					SetMoreInfo(matchContext(), params.name, params.data).
 					Return(params.err)
 			}
 
@@ -2528,7 +2529,7 @@ func TestICQService_SetMoreInfo(t *testing.T) {
 				userUpdater:    userUpdater,
 				messageRelayer: messageRelayer,
 			}
-			err := s.SetMoreInfo(nil, tt.sess, tt.req, tt.seq)
+			err := s.SetMoreInfo(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -2593,7 +2594,7 @@ func TestICQService_SetPermissions(t *testing.T) {
 				logger:         slog.Default(),
 				messageRelayer: messageRelayer,
 			}
-			err := s.SetPermissions(nil, tt.sess, tt.req, tt.seq)
+			err := s.SetPermissions(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -2664,7 +2665,7 @@ func TestICQService_SetUserNotes(t *testing.T) {
 			userUpdater := newMockICQUserUpdater(t)
 			for _, params := range tt.mockParams.setUserNotesParams {
 				userUpdater.EXPECT().
-					SetUserNotes(params.name, params.data).
+					SetUserNotes(matchContext(), params.name, params.data).
 					Return(params.err)
 			}
 
@@ -2677,7 +2678,7 @@ func TestICQService_SetUserNotes(t *testing.T) {
 				userUpdater:    userUpdater,
 				messageRelayer: messageRelayer,
 			}
-			err := s.SetUserNotes(nil, tt.sess, tt.req, tt.seq)
+			err := s.SetUserNotes(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -2770,7 +2771,7 @@ func TestICQService_SetWorkInfo(t *testing.T) {
 			userUpdater := newMockICQUserUpdater(t)
 			for _, params := range tt.mockParams.setWorkInfoParams {
 				userUpdater.EXPECT().
-					SetWorkInfo(params.name, params.data).
+					SetWorkInfo(matchContext(), params.name, params.data).
 					Return(params.err)
 			}
 
@@ -2783,7 +2784,7 @@ func TestICQService_SetWorkInfo(t *testing.T) {
 				userUpdater:    userUpdater,
 				messageRelayer: messageRelayer,
 			}
-			err := s.SetWorkInfo(nil, tt.sess, tt.req, tt.seq)
+			err := s.SetWorkInfo(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -2884,7 +2885,7 @@ func TestICQService_ShortUserInfo(t *testing.T) {
 			userFinder := newMockICQUserFinder(t)
 			for _, params := range tt.mockParams.findByUINParams {
 				userFinder.EXPECT().
-					FindByUIN(params.UIN).
+					FindByUIN(matchContext(), params.UIN).
 					Return(params.result, params.err)
 			}
 
@@ -2898,7 +2899,7 @@ func TestICQService_ShortUserInfo(t *testing.T) {
 				timeNow:        tt.timeNow,
 				userFinder:     userFinder,
 			}
-			err := s.ShortUserInfo(nil, tt.sess, tt.req, tt.seq)
+			err := s.ShortUserInfo(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.NoError(t, err)
 		})
 	}
@@ -2968,7 +2969,7 @@ func TestICQService_XMLReqData(t *testing.T) {
 				messageRelayer: messageRelayer,
 				timeNow:        tt.timeNow,
 			}
-			err := s.XMLReqData(nil, tt.sess, tt.req, tt.seq)
+			err := s.XMLReqData(context.Background(), tt.sess, tt.req, tt.seq)
 			assert.NoError(t, err)
 		})
 	}

+ 17 - 16
foodgroup/locate.go

@@ -22,16 +22,17 @@ var omitCaps = map[[16]byte]bool{
 
 // NewLocateService creates a new instance of LocateService.
 func NewLocateService(
+	buddyIconManager BuddyIconManager,
 	messageRelayer MessageRelayer,
 	profileManager ProfileManager,
-	buddyListRetriever BuddyListRetriever,
+	relationshipFetcher RelationshipFetcher,
 	sessionRetriever SessionRetriever,
 ) LocateService {
 	return LocateService{
-		buddyBroadcaster:   newBuddyNotifier(buddyListRetriever, messageRelayer, sessionRetriever),
-		buddyListRetriever: buddyListRetriever,
-		profileManager:     profileManager,
-		sessionRetriever:   sessionRetriever,
+		buddyBroadcaster:    newBuddyNotifier(buddyIconManager, relationshipFetcher, messageRelayer, sessionRetriever),
+		relationshipFetcher: relationshipFetcher,
+		profileManager:      profileManager,
+		sessionRetriever:    sessionRetriever,
 	}
 }
 
@@ -39,10 +40,10 @@ func NewLocateService(
 // responsible for user profiles, user info lookups, directory information, and
 // keyword lookups.
 type LocateService struct {
-	buddyBroadcaster   buddyBroadcaster
-	buddyListRetriever BuddyListRetriever
-	profileManager     ProfileManager
-	sessionRetriever   SessionRetriever
+	buddyBroadcaster    buddyBroadcaster
+	relationshipFetcher RelationshipFetcher
+	profileManager      ProfileManager
+	sessionRetriever    SessionRetriever
 }
 
 // RightsQuery returns SNAC wire.LocateRightsReply, which contains Locate food
@@ -74,7 +75,7 @@ func (s LocateService) RightsQuery(_ context.Context, inFrame wire.SNACFrame) wi
 func (s LocateService) SetInfo(ctx context.Context, sess *state.Session, inBody wire.SNAC_0x02_0x04_LocateSetInfo) error {
 	// update profile
 	if profile, hasProfile := inBody.String(wire.LocateTLVTagsInfoSigData); hasProfile {
-		if err := s.profileManager.SetProfile(sess.IdentScreenName(), profile); err != nil {
+		if err := s.profileManager.SetProfile(ctx, sess.IdentScreenName(), profile); err != nil {
 			return err
 		}
 	}
@@ -130,10 +131,10 @@ func newLocateErr(requestID uint32, errCode uint16) wire.SNACMessage {
 // UserInfoQuery fetches display information about an arbitrary user (not the
 // current user). It returns wire.LocateUserInfoReply, which contains the
 // profile, if requested, and/or the away message, if requested.
-func (s LocateService) UserInfoQuery(_ context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x02_0x05_LocateUserInfoQuery) (wire.SNACMessage, error) {
+func (s LocateService) UserInfoQuery(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x02_0x05_LocateUserInfoQuery) (wire.SNACMessage, error) {
 	identScreenName := state.NewIdentScreenName(inBody.ScreenName)
 
-	rel, err := s.buddyListRetriever.Relationship(sess.IdentScreenName(), identScreenName)
+	rel, err := s.relationshipFetcher.Relationship(ctx, sess.IdentScreenName(), identScreenName)
 	if err != nil {
 		return wire.SNACMessage{}, err
 	}
@@ -151,7 +152,7 @@ func (s LocateService) UserInfoQuery(_ context.Context, sess *state.Session, inF
 	var list wire.TLVList
 
 	if inBody.RequestProfile() {
-		profile, err := s.profileManager.Profile(identScreenName)
+		profile, err := s.profileManager.Profile(ctx, identScreenName)
 		if err != nil {
 			return wire.SNACMessage{}, err
 		}
@@ -188,7 +189,7 @@ func (s LocateService) UserInfoQuery(_ context.Context, sess *state.Session, inF
 func (s LocateService) SetDirInfo(ctx context.Context, sess *state.Session, inFrame wire.SNACFrame, inBody wire.SNAC_0x02_0x09_LocateSetDirInfo) (wire.SNACMessage, error) {
 	info := newAIMNameAndAddrFromTLVList(inBody.TLVList)
 
-	if err := s.profileManager.SetDirectoryInfo(sess.IdentScreenName(), info); err != nil {
+	if err := s.profileManager.SetDirectoryInfo(ctx, sess.IdentScreenName(), info); err != nil {
 		return wire.SNACMessage{}, err
 	}
 
@@ -222,7 +223,7 @@ func (s LocateService) SetKeywordInfo(ctx context.Context, sess *state.Session,
 		}
 	}
 
-	if err := s.profileManager.SetKeywords(sess.IdentScreenName(), keywords); err != nil {
+	if err := s.profileManager.SetKeywords(ctx, sess.IdentScreenName(), keywords); err != nil {
 		return wire.SNACMessage{}, fmt.Errorf("SetKeywords: %w", err)
 	}
 
@@ -247,7 +248,7 @@ func (s LocateService) DirInfo(ctx context.Context, inFrame wire.SNACFrame, body
 		},
 	}
 
-	user, err := s.profileManager.User(state.NewIdentScreenName(body.ScreenName))
+	user, err := s.profileManager.User(ctx, state.NewIdentScreenName(body.ScreenName))
 	if err != nil {
 		return wire.SNACMessage{}, fmt.Errorf("User: %w", err)
 	}

+ 30 - 30
foodgroup/locate_test.go

@@ -28,7 +28,7 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 		{
 			name: "request user info, expect user info response",
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("user_screen_name"),
@@ -82,7 +82,7 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 		{
 			name: "request user info + profile, expect user info response + profile",
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("user_screen_name"),
@@ -150,7 +150,7 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 		{
 			name: "request user info + profile, expect user info response + profile",
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("user_screen_name"),
@@ -218,7 +218,7 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 		{
 			name: "request user info + away message, expect user info response + away message",
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("user_screen_name"),
@@ -278,7 +278,7 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 		{
 			name: "request user info of user who blocked requester, expect not logged in error",
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("user_screen_name"),
@@ -317,7 +317,7 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 		{
 			name: "request user info of user who does not exist, expect not logged in error",
 			mockParams: mockParams{
-				buddyListRetrieverParams: buddyListRetrieverParams{
+				relationshipFetcherParams: relationshipFetcherParams{
 					relationshipParams: relationshipParams{
 						{
 							me:   state.NewIdentScreenName("user_screen_name"),
@@ -365,10 +365,10 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 
 	for _, tc := range cases {
 		t.Run(tc.name, func(t *testing.T) {
-			buddyListRetriever := newMockBuddyListRetriever(t)
-			for _, params := range tc.mockParams.buddyListRetrieverParams.relationshipParams {
-				buddyListRetriever.EXPECT().
-					Relationship(params.me, params.them).
+			relationshipFetcher := newMockRelationshipFetcher(t)
+			for _, params := range tc.mockParams.relationshipFetcherParams.relationshipParams {
+				relationshipFetcher.EXPECT().
+					Relationship(matchContext(), params.me, params.them).
 					Return(params.result, params.err)
 			}
 			sessionRetriever := newMockSessionRetriever(t)
@@ -380,13 +380,13 @@ func TestLocateService_UserInfoQuery(t *testing.T) {
 			profileManager := newMockProfileManager(t)
 			for _, val := range tc.mockParams.retrieveProfileParams {
 				profileManager.EXPECT().
-					Profile(val.screenName).
+					Profile(matchContext(), val.screenName).
 					Return(val.result, val.err)
 			}
 			svc := LocateService{
-				buddyListRetriever: buddyListRetriever,
-				sessionRetriever:   sessionRetriever,
-				profileManager:     profileManager,
+				relationshipFetcher: relationshipFetcher,
+				sessionRetriever:    sessionRetriever,
+				profileManager:      profileManager,
 			}
 			outputSNAC, err := svc.UserInfoQuery(context.Background(), tc.userSession, tc.inputSNAC.Frame,
 				tc.inputSNAC.Body.(wire.SNAC_0x02_0x05_LocateUserInfoQuery))
@@ -561,11 +561,11 @@ func TestLocateService_SetKeywordInfo(t *testing.T) {
 			profileManager := newMockProfileManager(t)
 			for _, params := range tt.mockParams.setKeywordsParams {
 				profileManager.EXPECT().
-					SetKeywords(params.screenName, params.keywords).
+					SetKeywords(matchContext(), params.screenName, params.keywords).
 					Return(params.err)
 			}
-			svc := NewLocateService(nil, profileManager, nil, nil)
-			outputSNAC, err := svc.SetKeywordInfo(nil, tt.userSession, tt.inputSNAC.Frame, tt.inputSNAC.Body.(wire.SNAC_0x02_0x0F_LocateSetKeywordInfo))
+			svc := NewLocateService(nil, nil, profileManager, nil, nil)
+			outputSNAC, err := svc.SetKeywordInfo(context.Background(), tt.userSession, tt.inputSNAC.Frame, tt.inputSNAC.Body.(wire.SNAC_0x02_0x0F_LocateSetKeywordInfo))
 			assert.NoError(t, err)
 			assert.Equal(t, tt.expectOutput, outputSNAC)
 		})
@@ -650,11 +650,11 @@ func TestLocateService_SetDirInfo(t *testing.T) {
 			profileManager := newMockProfileManager(t)
 			for _, params := range tt.mockParams.setDirectoryInfoParams {
 				profileManager.EXPECT().
-					SetDirectoryInfo(params.screenName, params.info).
+					SetDirectoryInfo(matchContext(), params.screenName, params.info).
 					Return(nil)
 			}
-			svc := NewLocateService(nil, profileManager, nil, nil)
-			outputSNAC, err := svc.SetDirInfo(nil, tt.userSession, tt.inputSNAC.Frame, tt.inputSNAC.Body.(wire.SNAC_0x02_0x09_LocateSetDirInfo))
+			svc := NewLocateService(nil, nil, profileManager, nil, nil)
+			outputSNAC, err := svc.SetDirInfo(context.Background(), tt.userSession, tt.inputSNAC.Frame, tt.inputSNAC.Body.(wire.SNAC_0x02_0x09_LocateSetDirInfo))
 			assert.NoError(t, err)
 			assert.Equal(t, tt.expectOutput, outputSNAC)
 		})
@@ -737,7 +737,7 @@ func TestLocateService_SetInfo(t *testing.T) {
 			profileManager := newMockProfileManager(t)
 			for _, params := range tt.mockParams.setProfileParams {
 				profileManager.EXPECT().
-					SetProfile(params.screenName, params.body).
+					SetProfile(matchContext(), params.screenName, params.body).
 					Return(nil)
 			}
 			buddyUpdateBroadcaster := newMockbuddyBroadcaster(t)
@@ -746,15 +746,15 @@ func TestLocateService_SetInfo(t *testing.T) {
 					BroadcastBuddyArrived(mock.Anything, matchSession(params.screenName)).
 					Return(params.err)
 			}
-			svc := NewLocateService(nil, profileManager, nil, nil)
+			svc := NewLocateService(nil, nil, profileManager, nil, nil)
 			svc.buddyBroadcaster = buddyUpdateBroadcaster
-			assert.Equal(t, tt.wantErr, svc.SetInfo(nil, tt.userSession, tt.inBody))
+			assert.Equal(t, tt.wantErr, svc.SetInfo(context.Background(), tt.userSession, tt.inBody))
 		})
 	}
 }
 
 func TestLocateService_SetInfo_SetCaps(t *testing.T) {
-	svc := NewLocateService(nil, nil, nil, nil)
+	svc := NewLocateService(nil, nil, nil, nil, nil)
 
 	sess := newTestSession("screen-name")
 	inBody := wire.SNAC_0x02_0x04_LocateSetInfo{
@@ -775,7 +775,7 @@ func TestLocateService_SetInfo_SetCaps(t *testing.T) {
 			},
 		},
 	}
-	assert.NoError(t, svc.SetInfo(nil, sess, inBody))
+	assert.NoError(t, svc.SetInfo(context.Background(), sess, inBody))
 
 	expect := [][16]byte{
 		// 748F2420-6287-11D1-8222-444553540000 (chat)
@@ -787,9 +787,9 @@ func TestLocateService_SetInfo_SetCaps(t *testing.T) {
 }
 
 func TestLocateService_RightsQuery(t *testing.T) {
-	svc := NewLocateService(nil, nil, nil, nil)
+	svc := NewLocateService(nil, nil, nil, nil, nil)
 
-	outputSNAC := svc.RightsQuery(nil, wire.SNACFrame{RequestID: 1234})
+	outputSNAC := svc.RightsQuery(context.Background(), wire.SNACFrame{RequestID: 1234})
 	expectSNAC := wire.SNACMessage{
 		Frame: wire.SNACFrame{
 			FoodGroup: wire.Locate,
@@ -928,11 +928,11 @@ func TestLocateService_DirInfo(t *testing.T) {
 			profileManager := newMockProfileManager(t)
 			for _, params := range tt.mockParams.profileManagerParams.getUserParams {
 				profileManager.EXPECT().
-					User(params.screenName).
+					User(matchContext(), params.screenName).
 					Return(params.result, params.err)
 			}
-			svc := NewLocateService(nil, profileManager, nil, nil)
-			outputSNAC, err := svc.DirInfo(nil, tt.inputSNAC.Frame, tt.inputSNAC.Body.(wire.SNAC_0x02_0x0B_LocateGetDirInfo))
+			svc := NewLocateService(nil, nil, profileManager, nil, nil)
+			outputSNAC, err := svc.DirInfo(context.Background(), tt.inputSNAC.Frame, tt.inputSNAC.Body.(wire.SNAC_0x02_0x0B_LocateGetDirInfo))
 			assert.NoError(t, err)
 			assert.Equal(t, tt.expectOutput, outputSNAC)
 		})

+ 136 - 125
foodgroup/mock_account_manager_test.go

@@ -3,10 +3,12 @@
 package foodgroup
 
 import (
+	context "context"
 	mail "net/mail"
 
-	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
+
+	state "github.com/mk6i/retro-aim-server/state"
 )
 
 // mockAccountManager is an autogenerated mock type for the AccountManager type
@@ -22,27 +24,27 @@ func (_m *mockAccountManager) EXPECT() *mockAccountManager_Expecter {
 	return &mockAccountManager_Expecter{mock: &_m.Mock}
 }
 
-// ConfirmStatusByName provides a mock function with given fields: screenName
-func (_m *mockAccountManager) ConfirmStatusByName(screenName state.IdentScreenName) (bool, error) {
-	ret := _m.Called(screenName)
+// ConfirmStatus provides a mock function with given fields: ctx, screenName
+func (_m *mockAccountManager) ConfirmStatus(ctx context.Context, screenName state.IdentScreenName) (bool, error) {
+	ret := _m.Called(ctx, screenName)
 
 	if len(ret) == 0 {
-		panic("no return value specified for ConfirmStatusByName")
+		panic("no return value specified for ConfirmStatus")
 	}
 
 	var r0 bool
 	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (bool, error)); ok {
-		return rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) (bool, error)); ok {
+		return rf(ctx, screenName)
 	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) bool); ok {
-		r0 = rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) bool); ok {
+		r0 = rf(ctx, screenName)
 	} else {
 		r0 = ret.Get(0).(bool)
 	}
 
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -50,57 +52,58 @@ func (_m *mockAccountManager) ConfirmStatusByName(screenName state.IdentScreenNa
 	return r0, r1
 }
 
-// mockAccountManager_ConfirmStatusByName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConfirmStatusByName'
-type mockAccountManager_ConfirmStatusByName_Call struct {
+// mockAccountManager_ConfirmStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConfirmStatus'
+type mockAccountManager_ConfirmStatus_Call struct {
 	*mock.Call
 }
 
-// ConfirmStatusByName is a helper method to define mock.On call
+// ConfirmStatus is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockAccountManager_Expecter) ConfirmStatusByName(screenName interface{}) *mockAccountManager_ConfirmStatusByName_Call {
-	return &mockAccountManager_ConfirmStatusByName_Call{Call: _e.mock.On("ConfirmStatusByName", screenName)}
+func (_e *mockAccountManager_Expecter) ConfirmStatus(ctx interface{}, screenName interface{}) *mockAccountManager_ConfirmStatus_Call {
+	return &mockAccountManager_ConfirmStatus_Call{Call: _e.mock.On("ConfirmStatus", ctx, screenName)}
 }
 
-func (_c *mockAccountManager_ConfirmStatusByName_Call) Run(run func(screenName state.IdentScreenName)) *mockAccountManager_ConfirmStatusByName_Call {
+func (_c *mockAccountManager_ConfirmStatus_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockAccountManager_ConfirmStatus_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
 
-func (_c *mockAccountManager_ConfirmStatusByName_Call) Return(_a0 bool, _a1 error) *mockAccountManager_ConfirmStatusByName_Call {
+func (_c *mockAccountManager_ConfirmStatus_Call) Return(_a0 bool, _a1 error) *mockAccountManager_ConfirmStatus_Call {
 	_c.Call.Return(_a0, _a1)
 	return _c
 }
 
-func (_c *mockAccountManager_ConfirmStatusByName_Call) RunAndReturn(run func(state.IdentScreenName) (bool, error)) *mockAccountManager_ConfirmStatusByName_Call {
+func (_c *mockAccountManager_ConfirmStatus_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) (bool, error)) *mockAccountManager_ConfirmStatus_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// EmailAddressByName provides a mock function with given fields: screenName
-func (_m *mockAccountManager) EmailAddressByName(screenName state.IdentScreenName) (*mail.Address, error) {
-	ret := _m.Called(screenName)
+// EmailAddress provides a mock function with given fields: ctx, screenName
+func (_m *mockAccountManager) EmailAddress(ctx context.Context, screenName state.IdentScreenName) (*mail.Address, error) {
+	ret := _m.Called(ctx, screenName)
 
 	if len(ret) == 0 {
-		panic("no return value specified for EmailAddressByName")
+		panic("no return value specified for EmailAddress")
 	}
 
 	var r0 *mail.Address
 	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (*mail.Address, error)); ok {
-		return rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) (*mail.Address, error)); ok {
+		return rf(ctx, screenName)
 	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) *mail.Address); ok {
-		r0 = rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) *mail.Address); ok {
+		r0 = rf(ctx, screenName)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*mail.Address)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -108,55 +111,56 @@ func (_m *mockAccountManager) EmailAddressByName(screenName state.IdentScreenNam
 	return r0, r1
 }
 
-// mockAccountManager_EmailAddressByName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EmailAddressByName'
-type mockAccountManager_EmailAddressByName_Call struct {
+// mockAccountManager_EmailAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EmailAddress'
+type mockAccountManager_EmailAddress_Call struct {
 	*mock.Call
 }
 
-// EmailAddressByName is a helper method to define mock.On call
+// EmailAddress is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockAccountManager_Expecter) EmailAddressByName(screenName interface{}) *mockAccountManager_EmailAddressByName_Call {
-	return &mockAccountManager_EmailAddressByName_Call{Call: _e.mock.On("EmailAddressByName", screenName)}
+func (_e *mockAccountManager_Expecter) EmailAddress(ctx interface{}, screenName interface{}) *mockAccountManager_EmailAddress_Call {
+	return &mockAccountManager_EmailAddress_Call{Call: _e.mock.On("EmailAddress", ctx, screenName)}
 }
 
-func (_c *mockAccountManager_EmailAddressByName_Call) Run(run func(screenName state.IdentScreenName)) *mockAccountManager_EmailAddressByName_Call {
+func (_c *mockAccountManager_EmailAddress_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockAccountManager_EmailAddress_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
 
-func (_c *mockAccountManager_EmailAddressByName_Call) Return(_a0 *mail.Address, _a1 error) *mockAccountManager_EmailAddressByName_Call {
+func (_c *mockAccountManager_EmailAddress_Call) Return(_a0 *mail.Address, _a1 error) *mockAccountManager_EmailAddress_Call {
 	_c.Call.Return(_a0, _a1)
 	return _c
 }
 
-func (_c *mockAccountManager_EmailAddressByName_Call) RunAndReturn(run func(state.IdentScreenName) (*mail.Address, error)) *mockAccountManager_EmailAddressByName_Call {
+func (_c *mockAccountManager_EmailAddress_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) (*mail.Address, error)) *mockAccountManager_EmailAddress_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// RegStatusByName provides a mock function with given fields: screenName
-func (_m *mockAccountManager) RegStatusByName(screenName state.IdentScreenName) (uint16, error) {
-	ret := _m.Called(screenName)
+// RegStatus provides a mock function with given fields: ctx, screenName
+func (_m *mockAccountManager) RegStatus(ctx context.Context, screenName state.IdentScreenName) (uint16, error) {
+	ret := _m.Called(ctx, screenName)
 
 	if len(ret) == 0 {
-		panic("no return value specified for RegStatusByName")
+		panic("no return value specified for RegStatus")
 	}
 
 	var r0 uint16
 	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (uint16, error)); ok {
-		return rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) (uint16, error)); ok {
+		return rf(ctx, screenName)
 	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) uint16); ok {
-		r0 = rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) uint16); ok {
+		r0 = rf(ctx, screenName)
 	} else {
 		r0 = ret.Get(0).(uint16)
 	}
 
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -164,45 +168,46 @@ func (_m *mockAccountManager) RegStatusByName(screenName state.IdentScreenName)
 	return r0, r1
 }
 
-// mockAccountManager_RegStatusByName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RegStatusByName'
-type mockAccountManager_RegStatusByName_Call struct {
+// mockAccountManager_RegStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RegStatus'
+type mockAccountManager_RegStatus_Call struct {
 	*mock.Call
 }
 
-// RegStatusByName is a helper method to define mock.On call
+// RegStatus is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockAccountManager_Expecter) RegStatusByName(screenName interface{}) *mockAccountManager_RegStatusByName_Call {
-	return &mockAccountManager_RegStatusByName_Call{Call: _e.mock.On("RegStatusByName", screenName)}
+func (_e *mockAccountManager_Expecter) RegStatus(ctx interface{}, screenName interface{}) *mockAccountManager_RegStatus_Call {
+	return &mockAccountManager_RegStatus_Call{Call: _e.mock.On("RegStatus", ctx, screenName)}
 }
 
-func (_c *mockAccountManager_RegStatusByName_Call) Run(run func(screenName state.IdentScreenName)) *mockAccountManager_RegStatusByName_Call {
+func (_c *mockAccountManager_RegStatus_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockAccountManager_RegStatus_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
 
-func (_c *mockAccountManager_RegStatusByName_Call) Return(_a0 uint16, _a1 error) *mockAccountManager_RegStatusByName_Call {
+func (_c *mockAccountManager_RegStatus_Call) Return(_a0 uint16, _a1 error) *mockAccountManager_RegStatus_Call {
 	_c.Call.Return(_a0, _a1)
 	return _c
 }
 
-func (_c *mockAccountManager_RegStatusByName_Call) RunAndReturn(run func(state.IdentScreenName) (uint16, error)) *mockAccountManager_RegStatusByName_Call {
+func (_c *mockAccountManager_RegStatus_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) (uint16, error)) *mockAccountManager_RegStatus_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// SetUserPassword provides a mock function with given fields: screenName, newPassword
-func (_m *mockAccountManager) SetUserPassword(screenName state.IdentScreenName, newPassword string) error {
-	ret := _m.Called(screenName, newPassword)
+// SetUserPassword provides a mock function with given fields: ctx, screenName, newPassword
+func (_m *mockAccountManager) SetUserPassword(ctx context.Context, screenName state.IdentScreenName, newPassword string) error {
+	ret := _m.Called(ctx, screenName, newPassword)
 
 	if len(ret) == 0 {
 		panic("no return value specified for SetUserPassword")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, string) error); ok {
-		r0 = rf(screenName, newPassword)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, string) error); ok {
+		r0 = rf(ctx, screenName, newPassword)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -216,15 +221,16 @@ type mockAccountManager_SetUserPassword_Call struct {
 }
 
 // SetUserPassword is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
 //   - newPassword string
-func (_e *mockAccountManager_Expecter) SetUserPassword(screenName interface{}, newPassword interface{}) *mockAccountManager_SetUserPassword_Call {
-	return &mockAccountManager_SetUserPassword_Call{Call: _e.mock.On("SetUserPassword", screenName, newPassword)}
+func (_e *mockAccountManager_Expecter) SetUserPassword(ctx interface{}, screenName interface{}, newPassword interface{}) *mockAccountManager_SetUserPassword_Call {
+	return &mockAccountManager_SetUserPassword_Call{Call: _e.mock.On("SetUserPassword", ctx, screenName, newPassword)}
 }
 
-func (_c *mockAccountManager_SetUserPassword_Call) Run(run func(screenName state.IdentScreenName, newPassword string)) *mockAccountManager_SetUserPassword_Call {
+func (_c *mockAccountManager_SetUserPassword_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName, newPassword string)) *mockAccountManager_SetUserPassword_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(string))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(string))
 	})
 	return _c
 }
@@ -234,22 +240,22 @@ func (_c *mockAccountManager_SetUserPassword_Call) Return(_a0 error) *mockAccoun
 	return _c
 }
 
-func (_c *mockAccountManager_SetUserPassword_Call) RunAndReturn(run func(state.IdentScreenName, string) error) *mockAccountManager_SetUserPassword_Call {
+func (_c *mockAccountManager_SetUserPassword_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, string) error) *mockAccountManager_SetUserPassword_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// UpdateConfirmStatus provides a mock function with given fields: confirmStatus, screenName
-func (_m *mockAccountManager) UpdateConfirmStatus(confirmStatus bool, screenName state.IdentScreenName) error {
-	ret := _m.Called(confirmStatus, screenName)
+// UpdateConfirmStatus provides a mock function with given fields: ctx, screenName, confirmStatus
+func (_m *mockAccountManager) UpdateConfirmStatus(ctx context.Context, screenName state.IdentScreenName, confirmStatus bool) error {
+	ret := _m.Called(ctx, screenName, confirmStatus)
 
 	if len(ret) == 0 {
 		panic("no return value specified for UpdateConfirmStatus")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(bool, state.IdentScreenName) error); ok {
-		r0 = rf(confirmStatus, screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, bool) error); ok {
+		r0 = rf(ctx, screenName, confirmStatus)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -263,15 +269,16 @@ type mockAccountManager_UpdateConfirmStatus_Call struct {
 }
 
 // UpdateConfirmStatus is a helper method to define mock.On call
-//   - confirmStatus bool
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockAccountManager_Expecter) UpdateConfirmStatus(confirmStatus interface{}, screenName interface{}) *mockAccountManager_UpdateConfirmStatus_Call {
-	return &mockAccountManager_UpdateConfirmStatus_Call{Call: _e.mock.On("UpdateConfirmStatus", confirmStatus, screenName)}
+//   - confirmStatus bool
+func (_e *mockAccountManager_Expecter) UpdateConfirmStatus(ctx interface{}, screenName interface{}, confirmStatus interface{}) *mockAccountManager_UpdateConfirmStatus_Call {
+	return &mockAccountManager_UpdateConfirmStatus_Call{Call: _e.mock.On("UpdateConfirmStatus", ctx, screenName, confirmStatus)}
 }
 
-func (_c *mockAccountManager_UpdateConfirmStatus_Call) Run(run func(confirmStatus bool, screenName state.IdentScreenName)) *mockAccountManager_UpdateConfirmStatus_Call {
+func (_c *mockAccountManager_UpdateConfirmStatus_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName, confirmStatus bool)) *mockAccountManager_UpdateConfirmStatus_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(bool), args[1].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(bool))
 	})
 	return _c
 }
@@ -281,22 +288,22 @@ func (_c *mockAccountManager_UpdateConfirmStatus_Call) Return(_a0 error) *mockAc
 	return _c
 }
 
-func (_c *mockAccountManager_UpdateConfirmStatus_Call) RunAndReturn(run func(bool, state.IdentScreenName) error) *mockAccountManager_UpdateConfirmStatus_Call {
+func (_c *mockAccountManager_UpdateConfirmStatus_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, bool) error) *mockAccountManager_UpdateConfirmStatus_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// UpdateDisplayScreenName provides a mock function with given fields: displayScreenName
-func (_m *mockAccountManager) UpdateDisplayScreenName(displayScreenName state.DisplayScreenName) error {
-	ret := _m.Called(displayScreenName)
+// UpdateDisplayScreenName provides a mock function with given fields: ctx, displayScreenName
+func (_m *mockAccountManager) UpdateDisplayScreenName(ctx context.Context, displayScreenName state.DisplayScreenName) error {
+	ret := _m.Called(ctx, displayScreenName)
 
 	if len(ret) == 0 {
 		panic("no return value specified for UpdateDisplayScreenName")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.DisplayScreenName) error); ok {
-		r0 = rf(displayScreenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.DisplayScreenName) error); ok {
+		r0 = rf(ctx, displayScreenName)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -310,14 +317,15 @@ type mockAccountManager_UpdateDisplayScreenName_Call struct {
 }
 
 // UpdateDisplayScreenName is a helper method to define mock.On call
+//   - ctx context.Context
 //   - displayScreenName state.DisplayScreenName
-func (_e *mockAccountManager_Expecter) UpdateDisplayScreenName(displayScreenName interface{}) *mockAccountManager_UpdateDisplayScreenName_Call {
-	return &mockAccountManager_UpdateDisplayScreenName_Call{Call: _e.mock.On("UpdateDisplayScreenName", displayScreenName)}
+func (_e *mockAccountManager_Expecter) UpdateDisplayScreenName(ctx interface{}, displayScreenName interface{}) *mockAccountManager_UpdateDisplayScreenName_Call {
+	return &mockAccountManager_UpdateDisplayScreenName_Call{Call: _e.mock.On("UpdateDisplayScreenName", ctx, displayScreenName)}
 }
 
-func (_c *mockAccountManager_UpdateDisplayScreenName_Call) Run(run func(displayScreenName state.DisplayScreenName)) *mockAccountManager_UpdateDisplayScreenName_Call {
+func (_c *mockAccountManager_UpdateDisplayScreenName_Call) Run(run func(ctx context.Context, displayScreenName state.DisplayScreenName)) *mockAccountManager_UpdateDisplayScreenName_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.DisplayScreenName))
+		run(args[0].(context.Context), args[1].(state.DisplayScreenName))
 	})
 	return _c
 }
@@ -327,22 +335,22 @@ func (_c *mockAccountManager_UpdateDisplayScreenName_Call) Return(_a0 error) *mo
 	return _c
 }
 
-func (_c *mockAccountManager_UpdateDisplayScreenName_Call) RunAndReturn(run func(state.DisplayScreenName) error) *mockAccountManager_UpdateDisplayScreenName_Call {
+func (_c *mockAccountManager_UpdateDisplayScreenName_Call) RunAndReturn(run func(context.Context, state.DisplayScreenName) error) *mockAccountManager_UpdateDisplayScreenName_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// UpdateEmailAddress provides a mock function with given fields: emailAddress, screenName
-func (_m *mockAccountManager) UpdateEmailAddress(emailAddress *mail.Address, screenName state.IdentScreenName) error {
-	ret := _m.Called(emailAddress, screenName)
+// UpdateEmailAddress provides a mock function with given fields: ctx, screenName, emailAddress
+func (_m *mockAccountManager) UpdateEmailAddress(ctx context.Context, screenName state.IdentScreenName, emailAddress *mail.Address) error {
+	ret := _m.Called(ctx, screenName, emailAddress)
 
 	if len(ret) == 0 {
 		panic("no return value specified for UpdateEmailAddress")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(*mail.Address, state.IdentScreenName) error); ok {
-		r0 = rf(emailAddress, screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, *mail.Address) error); ok {
+		r0 = rf(ctx, screenName, emailAddress)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -356,15 +364,16 @@ type mockAccountManager_UpdateEmailAddress_Call struct {
 }
 
 // UpdateEmailAddress is a helper method to define mock.On call
-//   - emailAddress *mail.Address
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockAccountManager_Expecter) UpdateEmailAddress(emailAddress interface{}, screenName interface{}) *mockAccountManager_UpdateEmailAddress_Call {
-	return &mockAccountManager_UpdateEmailAddress_Call{Call: _e.mock.On("UpdateEmailAddress", emailAddress, screenName)}
+//   - emailAddress *mail.Address
+func (_e *mockAccountManager_Expecter) UpdateEmailAddress(ctx interface{}, screenName interface{}, emailAddress interface{}) *mockAccountManager_UpdateEmailAddress_Call {
+	return &mockAccountManager_UpdateEmailAddress_Call{Call: _e.mock.On("UpdateEmailAddress", ctx, screenName, emailAddress)}
 }
 
-func (_c *mockAccountManager_UpdateEmailAddress_Call) Run(run func(emailAddress *mail.Address, screenName state.IdentScreenName)) *mockAccountManager_UpdateEmailAddress_Call {
+func (_c *mockAccountManager_UpdateEmailAddress_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName, emailAddress *mail.Address)) *mockAccountManager_UpdateEmailAddress_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(*mail.Address), args[1].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(*mail.Address))
 	})
 	return _c
 }
@@ -374,22 +383,22 @@ func (_c *mockAccountManager_UpdateEmailAddress_Call) Return(_a0 error) *mockAcc
 	return _c
 }
 
-func (_c *mockAccountManager_UpdateEmailAddress_Call) RunAndReturn(run func(*mail.Address, state.IdentScreenName) error) *mockAccountManager_UpdateEmailAddress_Call {
+func (_c *mockAccountManager_UpdateEmailAddress_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, *mail.Address) error) *mockAccountManager_UpdateEmailAddress_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// UpdateRegStatus provides a mock function with given fields: regStatus, screenName
-func (_m *mockAccountManager) UpdateRegStatus(regStatus uint16, screenName state.IdentScreenName) error {
-	ret := _m.Called(regStatus, screenName)
+// UpdateRegStatus provides a mock function with given fields: ctx, screenName, regStatus
+func (_m *mockAccountManager) UpdateRegStatus(ctx context.Context, screenName state.IdentScreenName, regStatus uint16) error {
+	ret := _m.Called(ctx, screenName, regStatus)
 
 	if len(ret) == 0 {
 		panic("no return value specified for UpdateRegStatus")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(uint16, state.IdentScreenName) error); ok {
-		r0 = rf(regStatus, screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, uint16) error); ok {
+		r0 = rf(ctx, screenName, regStatus)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -403,15 +412,16 @@ type mockAccountManager_UpdateRegStatus_Call struct {
 }
 
 // UpdateRegStatus is a helper method to define mock.On call
-//   - regStatus uint16
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockAccountManager_Expecter) UpdateRegStatus(regStatus interface{}, screenName interface{}) *mockAccountManager_UpdateRegStatus_Call {
-	return &mockAccountManager_UpdateRegStatus_Call{Call: _e.mock.On("UpdateRegStatus", regStatus, screenName)}
+//   - regStatus uint16
+func (_e *mockAccountManager_Expecter) UpdateRegStatus(ctx interface{}, screenName interface{}, regStatus interface{}) *mockAccountManager_UpdateRegStatus_Call {
+	return &mockAccountManager_UpdateRegStatus_Call{Call: _e.mock.On("UpdateRegStatus", ctx, screenName, regStatus)}
 }
 
-func (_c *mockAccountManager_UpdateRegStatus_Call) Run(run func(regStatus uint16, screenName state.IdentScreenName)) *mockAccountManager_UpdateRegStatus_Call {
+func (_c *mockAccountManager_UpdateRegStatus_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName, regStatus uint16)) *mockAccountManager_UpdateRegStatus_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(uint16), args[1].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(uint16))
 	})
 	return _c
 }
@@ -421,14 +431,14 @@ func (_c *mockAccountManager_UpdateRegStatus_Call) Return(_a0 error) *mockAccoun
 	return _c
 }
 
-func (_c *mockAccountManager_UpdateRegStatus_Call) RunAndReturn(run func(uint16, state.IdentScreenName) error) *mockAccountManager_UpdateRegStatus_Call {
+func (_c *mockAccountManager_UpdateRegStatus_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, uint16) error) *mockAccountManager_UpdateRegStatus_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// User provides a mock function with given fields: screenName
-func (_m *mockAccountManager) User(screenName state.IdentScreenName) (*state.User, error) {
-	ret := _m.Called(screenName)
+// User provides a mock function with given fields: ctx, screenName
+func (_m *mockAccountManager) User(ctx context.Context, screenName state.IdentScreenName) (*state.User, error) {
+	ret := _m.Called(ctx, screenName)
 
 	if len(ret) == 0 {
 		panic("no return value specified for User")
@@ -436,19 +446,19 @@ func (_m *mockAccountManager) User(screenName state.IdentScreenName) (*state.Use
 
 	var r0 *state.User
 	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (*state.User, error)); ok {
-		return rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) (*state.User, error)); ok {
+		return rf(ctx, screenName)
 	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) *state.User); ok {
-		r0 = rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) *state.User); ok {
+		r0 = rf(ctx, screenName)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*state.User)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -462,14 +472,15 @@ type mockAccountManager_User_Call struct {
 }
 
 // User is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockAccountManager_Expecter) User(screenName interface{}) *mockAccountManager_User_Call {
-	return &mockAccountManager_User_Call{Call: _e.mock.On("User", screenName)}
+func (_e *mockAccountManager_Expecter) User(ctx interface{}, screenName interface{}) *mockAccountManager_User_Call {
+	return &mockAccountManager_User_Call{Call: _e.mock.On("User", ctx, screenName)}
 }
 
-func (_c *mockAccountManager_User_Call) Run(run func(screenName state.IdentScreenName)) *mockAccountManager_User_Call {
+func (_c *mockAccountManager_User_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockAccountManager_User_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
@@ -479,7 +490,7 @@ func (_c *mockAccountManager_User_Call) Return(_a0 *state.User, _a1 error) *mock
 	return _c
 }
 
-func (_c *mockAccountManager_User_Call) RunAndReturn(run func(state.IdentScreenName) (*state.User, error)) *mockAccountManager_User_Call {
+func (_c *mockAccountManager_User_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) (*state.User, error)) *mockAccountManager_User_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 0 - 137
foodgroup/mock_bart_manager_test.go

@@ -1,137 +0,0 @@
-// Code generated by mockery v2.52.1. DO NOT EDIT.
-
-package foodgroup
-
-import mock "github.com/stretchr/testify/mock"
-
-// mockBARTManager is an autogenerated mock type for the BARTManager type
-type mockBARTManager struct {
-	mock.Mock
-}
-
-type mockBARTManager_Expecter struct {
-	mock *mock.Mock
-}
-
-func (_m *mockBARTManager) EXPECT() *mockBARTManager_Expecter {
-	return &mockBARTManager_Expecter{mock: &_m.Mock}
-}
-
-// BARTRetrieve provides a mock function with given fields: itemHash
-func (_m *mockBARTManager) BARTRetrieve(itemHash []byte) ([]byte, error) {
-	ret := _m.Called(itemHash)
-
-	if len(ret) == 0 {
-		panic("no return value specified for BARTRetrieve")
-	}
-
-	var r0 []byte
-	var r1 error
-	if rf, ok := ret.Get(0).(func([]byte) ([]byte, error)); ok {
-		return rf(itemHash)
-	}
-	if rf, ok := ret.Get(0).(func([]byte) []byte); ok {
-		r0 = rf(itemHash)
-	} else {
-		if ret.Get(0) != nil {
-			r0 = ret.Get(0).([]byte)
-		}
-	}
-
-	if rf, ok := ret.Get(1).(func([]byte) error); ok {
-		r1 = rf(itemHash)
-	} else {
-		r1 = ret.Error(1)
-	}
-
-	return r0, r1
-}
-
-// mockBARTManager_BARTRetrieve_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BARTRetrieve'
-type mockBARTManager_BARTRetrieve_Call struct {
-	*mock.Call
-}
-
-// BARTRetrieve is a helper method to define mock.On call
-//   - itemHash []byte
-func (_e *mockBARTManager_Expecter) BARTRetrieve(itemHash interface{}) *mockBARTManager_BARTRetrieve_Call {
-	return &mockBARTManager_BARTRetrieve_Call{Call: _e.mock.On("BARTRetrieve", itemHash)}
-}
-
-func (_c *mockBARTManager_BARTRetrieve_Call) Run(run func(itemHash []byte)) *mockBARTManager_BARTRetrieve_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].([]byte))
-	})
-	return _c
-}
-
-func (_c *mockBARTManager_BARTRetrieve_Call) Return(_a0 []byte, _a1 error) *mockBARTManager_BARTRetrieve_Call {
-	_c.Call.Return(_a0, _a1)
-	return _c
-}
-
-func (_c *mockBARTManager_BARTRetrieve_Call) RunAndReturn(run func([]byte) ([]byte, error)) *mockBARTManager_BARTRetrieve_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// BARTUpsert provides a mock function with given fields: itemHash, payload
-func (_m *mockBARTManager) BARTUpsert(itemHash []byte, payload []byte) error {
-	ret := _m.Called(itemHash, payload)
-
-	if len(ret) == 0 {
-		panic("no return value specified for BARTUpsert")
-	}
-
-	var r0 error
-	if rf, ok := ret.Get(0).(func([]byte, []byte) error); ok {
-		r0 = rf(itemHash, payload)
-	} else {
-		r0 = ret.Error(0)
-	}
-
-	return r0
-}
-
-// mockBARTManager_BARTUpsert_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BARTUpsert'
-type mockBARTManager_BARTUpsert_Call struct {
-	*mock.Call
-}
-
-// BARTUpsert is a helper method to define mock.On call
-//   - itemHash []byte
-//   - payload []byte
-func (_e *mockBARTManager_Expecter) BARTUpsert(itemHash interface{}, payload interface{}) *mockBARTManager_BARTUpsert_Call {
-	return &mockBARTManager_BARTUpsert_Call{Call: _e.mock.On("BARTUpsert", itemHash, payload)}
-}
-
-func (_c *mockBARTManager_BARTUpsert_Call) Run(run func(itemHash []byte, payload []byte)) *mockBARTManager_BARTUpsert_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].([]byte), args[1].([]byte))
-	})
-	return _c
-}
-
-func (_c *mockBARTManager_BARTUpsert_Call) Return(_a0 error) *mockBARTManager_BARTUpsert_Call {
-	_c.Call.Return(_a0)
-	return _c
-}
-
-func (_c *mockBARTManager_BARTUpsert_Call) RunAndReturn(run func([]byte, []byte) error) *mockBARTManager_BARTUpsert_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// newMockBARTManager creates a new instance of mockBARTManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func newMockBARTManager(t interface {
-	mock.TestingT
-	Cleanup(func())
-}) *mockBARTManager {
-	mock := &mockBARTManager{}
-	mock.Mock.Test(t)
-
-	t.Cleanup(func() { mock.AssertExpectations(t) })
-
-	return mock
-}

+ 205 - 0
foodgroup/mock_buddy_icon_manager_test.go

@@ -0,0 +1,205 @@
+// Code generated by mockery v2.52.1. DO NOT EDIT.
+
+package foodgroup
+
+import (
+	context "context"
+
+	state "github.com/mk6i/retro-aim-server/state"
+	mock "github.com/stretchr/testify/mock"
+
+	wire "github.com/mk6i/retro-aim-server/wire"
+)
+
+// mockBuddyIconManager is an autogenerated mock type for the BuddyIconManager type
+type mockBuddyIconManager struct {
+	mock.Mock
+}
+
+type mockBuddyIconManager_Expecter struct {
+	mock *mock.Mock
+}
+
+func (_m *mockBuddyIconManager) EXPECT() *mockBuddyIconManager_Expecter {
+	return &mockBuddyIconManager_Expecter{mock: &_m.Mock}
+}
+
+// BuddyIcon provides a mock function with given fields: ctx, md5
+func (_m *mockBuddyIconManager) BuddyIcon(ctx context.Context, md5 []byte) ([]byte, error) {
+	ret := _m.Called(ctx, md5)
+
+	if len(ret) == 0 {
+		panic("no return value specified for BuddyIcon")
+	}
+
+	var r0 []byte
+	var r1 error
+	if rf, ok := ret.Get(0).(func(context.Context, []byte) ([]byte, error)); ok {
+		return rf(ctx, md5)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, []byte) []byte); ok {
+		r0 = rf(ctx, md5)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).([]byte)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func(context.Context, []byte) error); ok {
+		r1 = rf(ctx, md5)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// mockBuddyIconManager_BuddyIcon_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BuddyIcon'
+type mockBuddyIconManager_BuddyIcon_Call struct {
+	*mock.Call
+}
+
+// BuddyIcon is a helper method to define mock.On call
+//   - ctx context.Context
+//   - md5 []byte
+func (_e *mockBuddyIconManager_Expecter) BuddyIcon(ctx interface{}, md5 interface{}) *mockBuddyIconManager_BuddyIcon_Call {
+	return &mockBuddyIconManager_BuddyIcon_Call{Call: _e.mock.On("BuddyIcon", ctx, md5)}
+}
+
+func (_c *mockBuddyIconManager_BuddyIcon_Call) Run(run func(ctx context.Context, md5 []byte)) *mockBuddyIconManager_BuddyIcon_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].([]byte))
+	})
+	return _c
+}
+
+func (_c *mockBuddyIconManager_BuddyIcon_Call) Return(_a0 []byte, _a1 error) *mockBuddyIconManager_BuddyIcon_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *mockBuddyIconManager_BuddyIcon_Call) RunAndReturn(run func(context.Context, []byte) ([]byte, error)) *mockBuddyIconManager_BuddyIcon_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// BuddyIconMetadata provides a mock function with given fields: ctx, screenName
+func (_m *mockBuddyIconManager) BuddyIconMetadata(ctx context.Context, screenName state.IdentScreenName) (*wire.BARTID, error) {
+	ret := _m.Called(ctx, screenName)
+
+	if len(ret) == 0 {
+		panic("no return value specified for BuddyIconMetadata")
+	}
+
+	var r0 *wire.BARTID
+	var r1 error
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) (*wire.BARTID, error)); ok {
+		return rf(ctx, screenName)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) *wire.BARTID); ok {
+		r0 = rf(ctx, screenName)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(*wire.BARTID)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// mockBuddyIconManager_BuddyIconMetadata_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BuddyIconMetadata'
+type mockBuddyIconManager_BuddyIconMetadata_Call struct {
+	*mock.Call
+}
+
+// BuddyIconMetadata is a helper method to define mock.On call
+//   - ctx context.Context
+//   - screenName state.IdentScreenName
+func (_e *mockBuddyIconManager_Expecter) BuddyIconMetadata(ctx interface{}, screenName interface{}) *mockBuddyIconManager_BuddyIconMetadata_Call {
+	return &mockBuddyIconManager_BuddyIconMetadata_Call{Call: _e.mock.On("BuddyIconMetadata", ctx, screenName)}
+}
+
+func (_c *mockBuddyIconManager_BuddyIconMetadata_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockBuddyIconManager_BuddyIconMetadata_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
+	})
+	return _c
+}
+
+func (_c *mockBuddyIconManager_BuddyIconMetadata_Call) Return(_a0 *wire.BARTID, _a1 error) *mockBuddyIconManager_BuddyIconMetadata_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *mockBuddyIconManager_BuddyIconMetadata_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) (*wire.BARTID, error)) *mockBuddyIconManager_BuddyIconMetadata_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// SetBuddyIcon provides a mock function with given fields: ctx, md5, image
+func (_m *mockBuddyIconManager) SetBuddyIcon(ctx context.Context, md5 []byte, image []byte) error {
+	ret := _m.Called(ctx, md5, image)
+
+	if len(ret) == 0 {
+		panic("no return value specified for SetBuddyIcon")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context, []byte, []byte) error); ok {
+		r0 = rf(ctx, md5, image)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// mockBuddyIconManager_SetBuddyIcon_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetBuddyIcon'
+type mockBuddyIconManager_SetBuddyIcon_Call struct {
+	*mock.Call
+}
+
+// SetBuddyIcon is a helper method to define mock.On call
+//   - ctx context.Context
+//   - md5 []byte
+//   - image []byte
+func (_e *mockBuddyIconManager_Expecter) SetBuddyIcon(ctx interface{}, md5 interface{}, image interface{}) *mockBuddyIconManager_SetBuddyIcon_Call {
+	return &mockBuddyIconManager_SetBuddyIcon_Call{Call: _e.mock.On("SetBuddyIcon", ctx, md5, image)}
+}
+
+func (_c *mockBuddyIconManager_SetBuddyIcon_Call) Run(run func(ctx context.Context, md5 []byte, image []byte)) *mockBuddyIconManager_SetBuddyIcon_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].([]byte), args[2].([]byte))
+	})
+	return _c
+}
+
+func (_c *mockBuddyIconManager_SetBuddyIcon_Call) Return(_a0 error) *mockBuddyIconManager_SetBuddyIcon_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *mockBuddyIconManager_SetBuddyIcon_Call) RunAndReturn(run func(context.Context, []byte, []byte) error) *mockBuddyIconManager_SetBuddyIcon_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// newMockBuddyIconManager creates a new instance of mockBuddyIconManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func newMockBuddyIconManager(t interface {
+	mock.TestingT
+	Cleanup(func())
+}) *mockBuddyIconManager {
+	mock := &mockBuddyIconManager{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}

+ 0 - 211
foodgroup/mock_buddy_list_retriever_test.go

@@ -1,211 +0,0 @@
-// Code generated by mockery v2.52.1. DO NOT EDIT.
-
-package foodgroup
-
-import (
-	state "github.com/mk6i/retro-aim-server/state"
-	mock "github.com/stretchr/testify/mock"
-
-	wire "github.com/mk6i/retro-aim-server/wire"
-)
-
-// mockBuddyListRetriever is an autogenerated mock type for the BuddyListRetriever type
-type mockBuddyListRetriever struct {
-	mock.Mock
-}
-
-type mockBuddyListRetriever_Expecter struct {
-	mock *mock.Mock
-}
-
-func (_m *mockBuddyListRetriever) EXPECT() *mockBuddyListRetriever_Expecter {
-	return &mockBuddyListRetriever_Expecter{mock: &_m.Mock}
-}
-
-// AllRelationships provides a mock function with given fields: screenName, filter
-func (_m *mockBuddyListRetriever) AllRelationships(screenName state.IdentScreenName, filter []state.IdentScreenName) ([]state.Relationship, error) {
-	ret := _m.Called(screenName, filter)
-
-	if len(ret) == 0 {
-		panic("no return value specified for AllRelationships")
-	}
-
-	var r0 []state.Relationship
-	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, []state.IdentScreenName) ([]state.Relationship, error)); ok {
-		return rf(screenName, filter)
-	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, []state.IdentScreenName) []state.Relationship); ok {
-		r0 = rf(screenName, filter)
-	} else {
-		if ret.Get(0) != nil {
-			r0 = ret.Get(0).([]state.Relationship)
-		}
-	}
-
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName, []state.IdentScreenName) error); ok {
-		r1 = rf(screenName, filter)
-	} else {
-		r1 = ret.Error(1)
-	}
-
-	return r0, r1
-}
-
-// mockBuddyListRetriever_AllRelationships_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AllRelationships'
-type mockBuddyListRetriever_AllRelationships_Call struct {
-	*mock.Call
-}
-
-// AllRelationships is a helper method to define mock.On call
-//   - screenName state.IdentScreenName
-//   - filter []state.IdentScreenName
-func (_e *mockBuddyListRetriever_Expecter) AllRelationships(screenName interface{}, filter interface{}) *mockBuddyListRetriever_AllRelationships_Call {
-	return &mockBuddyListRetriever_AllRelationships_Call{Call: _e.mock.On("AllRelationships", screenName, filter)}
-}
-
-func (_c *mockBuddyListRetriever_AllRelationships_Call) Run(run func(screenName state.IdentScreenName, filter []state.IdentScreenName)) *mockBuddyListRetriever_AllRelationships_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].([]state.IdentScreenName))
-	})
-	return _c
-}
-
-func (_c *mockBuddyListRetriever_AllRelationships_Call) Return(_a0 []state.Relationship, _a1 error) *mockBuddyListRetriever_AllRelationships_Call {
-	_c.Call.Return(_a0, _a1)
-	return _c
-}
-
-func (_c *mockBuddyListRetriever_AllRelationships_Call) RunAndReturn(run func(state.IdentScreenName, []state.IdentScreenName) ([]state.Relationship, error)) *mockBuddyListRetriever_AllRelationships_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// BuddyIconRefByName provides a mock function with given fields: screenName
-func (_m *mockBuddyListRetriever) BuddyIconRefByName(screenName state.IdentScreenName) (*wire.BARTID, error) {
-	ret := _m.Called(screenName)
-
-	if len(ret) == 0 {
-		panic("no return value specified for BuddyIconRefByName")
-	}
-
-	var r0 *wire.BARTID
-	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (*wire.BARTID, error)); ok {
-		return rf(screenName)
-	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) *wire.BARTID); ok {
-		r0 = rf(screenName)
-	} else {
-		if ret.Get(0) != nil {
-			r0 = ret.Get(0).(*wire.BARTID)
-		}
-	}
-
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
-	} else {
-		r1 = ret.Error(1)
-	}
-
-	return r0, r1
-}
-
-// mockBuddyListRetriever_BuddyIconRefByName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BuddyIconRefByName'
-type mockBuddyListRetriever_BuddyIconRefByName_Call struct {
-	*mock.Call
-}
-
-// BuddyIconRefByName is a helper method to define mock.On call
-//   - screenName state.IdentScreenName
-func (_e *mockBuddyListRetriever_Expecter) BuddyIconRefByName(screenName interface{}) *mockBuddyListRetriever_BuddyIconRefByName_Call {
-	return &mockBuddyListRetriever_BuddyIconRefByName_Call{Call: _e.mock.On("BuddyIconRefByName", screenName)}
-}
-
-func (_c *mockBuddyListRetriever_BuddyIconRefByName_Call) Run(run func(screenName state.IdentScreenName)) *mockBuddyListRetriever_BuddyIconRefByName_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
-	})
-	return _c
-}
-
-func (_c *mockBuddyListRetriever_BuddyIconRefByName_Call) Return(_a0 *wire.BARTID, _a1 error) *mockBuddyListRetriever_BuddyIconRefByName_Call {
-	_c.Call.Return(_a0, _a1)
-	return _c
-}
-
-func (_c *mockBuddyListRetriever_BuddyIconRefByName_Call) RunAndReturn(run func(state.IdentScreenName) (*wire.BARTID, error)) *mockBuddyListRetriever_BuddyIconRefByName_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// Relationship provides a mock function with given fields: me, them
-func (_m *mockBuddyListRetriever) Relationship(me state.IdentScreenName, them state.IdentScreenName) (state.Relationship, error) {
-	ret := _m.Called(me, them)
-
-	if len(ret) == 0 {
-		panic("no return value specified for Relationship")
-	}
-
-	var r0 state.Relationship
-	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.IdentScreenName) (state.Relationship, error)); ok {
-		return rf(me, them)
-	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.IdentScreenName) state.Relationship); ok {
-		r0 = rf(me, them)
-	} else {
-		r0 = ret.Get(0).(state.Relationship)
-	}
-
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName, state.IdentScreenName) error); ok {
-		r1 = rf(me, them)
-	} else {
-		r1 = ret.Error(1)
-	}
-
-	return r0, r1
-}
-
-// mockBuddyListRetriever_Relationship_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Relationship'
-type mockBuddyListRetriever_Relationship_Call struct {
-	*mock.Call
-}
-
-// Relationship is a helper method to define mock.On call
-//   - me state.IdentScreenName
-//   - them state.IdentScreenName
-func (_e *mockBuddyListRetriever_Expecter) Relationship(me interface{}, them interface{}) *mockBuddyListRetriever_Relationship_Call {
-	return &mockBuddyListRetriever_Relationship_Call{Call: _e.mock.On("Relationship", me, them)}
-}
-
-func (_c *mockBuddyListRetriever_Relationship_Call) Run(run func(me state.IdentScreenName, them state.IdentScreenName)) *mockBuddyListRetriever_Relationship_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(state.IdentScreenName))
-	})
-	return _c
-}
-
-func (_c *mockBuddyListRetriever_Relationship_Call) Return(_a0 state.Relationship, _a1 error) *mockBuddyListRetriever_Relationship_Call {
-	_c.Call.Return(_a0, _a1)
-	return _c
-}
-
-func (_c *mockBuddyListRetriever_Relationship_Call) RunAndReturn(run func(state.IdentScreenName, state.IdentScreenName) (state.Relationship, error)) *mockBuddyListRetriever_Relationship_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// newMockBuddyListRetriever creates a new instance of mockBuddyListRetriever. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func newMockBuddyListRetriever(t interface {
-	mock.TestingT
-	Cleanup(func())
-}) *mockBuddyListRetriever {
-	mock := &mockBuddyListRetriever{}
-	mock.Mock.Test(t)
-
-	t.Cleanup(func() { mock.AssertExpectations(t) })
-
-	return mock
-}

+ 43 - 38
foodgroup/mock_chat_room_registry_test.go

@@ -3,6 +3,8 @@
 package foodgroup
 
 import (
+	context "context"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 )
@@ -20,9 +22,9 @@ func (_m *mockChatRoomRegistry) EXPECT() *mockChatRoomRegistry_Expecter {
 	return &mockChatRoomRegistry_Expecter{mock: &_m.Mock}
 }
 
-// ChatRoomByCookie provides a mock function with given fields: chatCookie
-func (_m *mockChatRoomRegistry) ChatRoomByCookie(chatCookie string) (state.ChatRoom, error) {
-	ret := _m.Called(chatCookie)
+// ChatRoomByCookie provides a mock function with given fields: ctx, chatCookie
+func (_m *mockChatRoomRegistry) ChatRoomByCookie(ctx context.Context, chatCookie string) (state.ChatRoom, error) {
+	ret := _m.Called(ctx, chatCookie)
 
 	if len(ret) == 0 {
 		panic("no return value specified for ChatRoomByCookie")
@@ -30,17 +32,17 @@ func (_m *mockChatRoomRegistry) ChatRoomByCookie(chatCookie string) (state.ChatR
 
 	var r0 state.ChatRoom
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string) (state.ChatRoom, error)); ok {
-		return rf(chatCookie)
+	if rf, ok := ret.Get(0).(func(context.Context, string) (state.ChatRoom, error)); ok {
+		return rf(ctx, chatCookie)
 	}
-	if rf, ok := ret.Get(0).(func(string) state.ChatRoom); ok {
-		r0 = rf(chatCookie)
+	if rf, ok := ret.Get(0).(func(context.Context, string) state.ChatRoom); ok {
+		r0 = rf(ctx, chatCookie)
 	} else {
 		r0 = ret.Get(0).(state.ChatRoom)
 	}
 
-	if rf, ok := ret.Get(1).(func(string) error); ok {
-		r1 = rf(chatCookie)
+	if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
+		r1 = rf(ctx, chatCookie)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -54,14 +56,15 @@ type mockChatRoomRegistry_ChatRoomByCookie_Call struct {
 }
 
 // ChatRoomByCookie is a helper method to define mock.On call
+//   - ctx context.Context
 //   - chatCookie string
-func (_e *mockChatRoomRegistry_Expecter) ChatRoomByCookie(chatCookie interface{}) *mockChatRoomRegistry_ChatRoomByCookie_Call {
-	return &mockChatRoomRegistry_ChatRoomByCookie_Call{Call: _e.mock.On("ChatRoomByCookie", chatCookie)}
+func (_e *mockChatRoomRegistry_Expecter) ChatRoomByCookie(ctx interface{}, chatCookie interface{}) *mockChatRoomRegistry_ChatRoomByCookie_Call {
+	return &mockChatRoomRegistry_ChatRoomByCookie_Call{Call: _e.mock.On("ChatRoomByCookie", ctx, chatCookie)}
 }
 
-func (_c *mockChatRoomRegistry_ChatRoomByCookie_Call) Run(run func(chatCookie string)) *mockChatRoomRegistry_ChatRoomByCookie_Call {
+func (_c *mockChatRoomRegistry_ChatRoomByCookie_Call) Run(run func(ctx context.Context, chatCookie string)) *mockChatRoomRegistry_ChatRoomByCookie_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(context.Context), args[1].(string))
 	})
 	return _c
 }
@@ -71,14 +74,14 @@ func (_c *mockChatRoomRegistry_ChatRoomByCookie_Call) Return(_a0 state.ChatRoom,
 	return _c
 }
 
-func (_c *mockChatRoomRegistry_ChatRoomByCookie_Call) RunAndReturn(run func(string) (state.ChatRoom, error)) *mockChatRoomRegistry_ChatRoomByCookie_Call {
+func (_c *mockChatRoomRegistry_ChatRoomByCookie_Call) RunAndReturn(run func(context.Context, string) (state.ChatRoom, error)) *mockChatRoomRegistry_ChatRoomByCookie_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// ChatRoomByName provides a mock function with given fields: exchange, name
-func (_m *mockChatRoomRegistry) ChatRoomByName(exchange uint16, name string) (state.ChatRoom, error) {
-	ret := _m.Called(exchange, name)
+// ChatRoomByName provides a mock function with given fields: ctx, exchange, name
+func (_m *mockChatRoomRegistry) ChatRoomByName(ctx context.Context, exchange uint16, name string) (state.ChatRoom, error) {
+	ret := _m.Called(ctx, exchange, name)
 
 	if len(ret) == 0 {
 		panic("no return value specified for ChatRoomByName")
@@ -86,17 +89,17 @@ func (_m *mockChatRoomRegistry) ChatRoomByName(exchange uint16, name string) (st
 
 	var r0 state.ChatRoom
 	var r1 error
-	if rf, ok := ret.Get(0).(func(uint16, string) (state.ChatRoom, error)); ok {
-		return rf(exchange, name)
+	if rf, ok := ret.Get(0).(func(context.Context, uint16, string) (state.ChatRoom, error)); ok {
+		return rf(ctx, exchange, name)
 	}
-	if rf, ok := ret.Get(0).(func(uint16, string) state.ChatRoom); ok {
-		r0 = rf(exchange, name)
+	if rf, ok := ret.Get(0).(func(context.Context, uint16, string) state.ChatRoom); ok {
+		r0 = rf(ctx, exchange, name)
 	} else {
 		r0 = ret.Get(0).(state.ChatRoom)
 	}
 
-	if rf, ok := ret.Get(1).(func(uint16, string) error); ok {
-		r1 = rf(exchange, name)
+	if rf, ok := ret.Get(1).(func(context.Context, uint16, string) error); ok {
+		r1 = rf(ctx, exchange, name)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -110,15 +113,16 @@ type mockChatRoomRegistry_ChatRoomByName_Call struct {
 }
 
 // ChatRoomByName is a helper method to define mock.On call
+//   - ctx context.Context
 //   - exchange uint16
 //   - name string
-func (_e *mockChatRoomRegistry_Expecter) ChatRoomByName(exchange interface{}, name interface{}) *mockChatRoomRegistry_ChatRoomByName_Call {
-	return &mockChatRoomRegistry_ChatRoomByName_Call{Call: _e.mock.On("ChatRoomByName", exchange, name)}
+func (_e *mockChatRoomRegistry_Expecter) ChatRoomByName(ctx interface{}, exchange interface{}, name interface{}) *mockChatRoomRegistry_ChatRoomByName_Call {
+	return &mockChatRoomRegistry_ChatRoomByName_Call{Call: _e.mock.On("ChatRoomByName", ctx, exchange, name)}
 }
 
-func (_c *mockChatRoomRegistry_ChatRoomByName_Call) Run(run func(exchange uint16, name string)) *mockChatRoomRegistry_ChatRoomByName_Call {
+func (_c *mockChatRoomRegistry_ChatRoomByName_Call) Run(run func(ctx context.Context, exchange uint16, name string)) *mockChatRoomRegistry_ChatRoomByName_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(uint16), args[1].(string))
+		run(args[0].(context.Context), args[1].(uint16), args[2].(string))
 	})
 	return _c
 }
@@ -128,22 +132,22 @@ func (_c *mockChatRoomRegistry_ChatRoomByName_Call) Return(_a0 state.ChatRoom, _
 	return _c
 }
 
-func (_c *mockChatRoomRegistry_ChatRoomByName_Call) RunAndReturn(run func(uint16, string) (state.ChatRoom, error)) *mockChatRoomRegistry_ChatRoomByName_Call {
+func (_c *mockChatRoomRegistry_ChatRoomByName_Call) RunAndReturn(run func(context.Context, uint16, string) (state.ChatRoom, error)) *mockChatRoomRegistry_ChatRoomByName_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// CreateChatRoom provides a mock function with given fields: chatRoom
-func (_m *mockChatRoomRegistry) CreateChatRoom(chatRoom *state.ChatRoom) error {
-	ret := _m.Called(chatRoom)
+// CreateChatRoom provides a mock function with given fields: ctx, chatRoom
+func (_m *mockChatRoomRegistry) CreateChatRoom(ctx context.Context, chatRoom *state.ChatRoom) error {
+	ret := _m.Called(ctx, chatRoom)
 
 	if len(ret) == 0 {
 		panic("no return value specified for CreateChatRoom")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(*state.ChatRoom) error); ok {
-		r0 = rf(chatRoom)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.ChatRoom) error); ok {
+		r0 = rf(ctx, chatRoom)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -157,14 +161,15 @@ type mockChatRoomRegistry_CreateChatRoom_Call struct {
 }
 
 // CreateChatRoom is a helper method to define mock.On call
+//   - ctx context.Context
 //   - chatRoom *state.ChatRoom
-func (_e *mockChatRoomRegistry_Expecter) CreateChatRoom(chatRoom interface{}) *mockChatRoomRegistry_CreateChatRoom_Call {
-	return &mockChatRoomRegistry_CreateChatRoom_Call{Call: _e.mock.On("CreateChatRoom", chatRoom)}
+func (_e *mockChatRoomRegistry_Expecter) CreateChatRoom(ctx interface{}, chatRoom interface{}) *mockChatRoomRegistry_CreateChatRoom_Call {
+	return &mockChatRoomRegistry_CreateChatRoom_Call{Call: _e.mock.On("CreateChatRoom", ctx, chatRoom)}
 }
 
-func (_c *mockChatRoomRegistry_CreateChatRoom_Call) Run(run func(chatRoom *state.ChatRoom)) *mockChatRoomRegistry_CreateChatRoom_Call {
+func (_c *mockChatRoomRegistry_CreateChatRoom_Call) Run(run func(ctx context.Context, chatRoom *state.ChatRoom)) *mockChatRoomRegistry_CreateChatRoom_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(*state.ChatRoom))
+		run(args[0].(context.Context), args[1].(*state.ChatRoom))
 	})
 	return _c
 }
@@ -174,7 +179,7 @@ func (_c *mockChatRoomRegistry_CreateChatRoom_Call) Return(_a0 error) *mockChatR
 	return _c
 }
 
-func (_c *mockChatRoomRegistry_CreateChatRoom_Call) RunAndReturn(run func(*state.ChatRoom) error) *mockChatRoomRegistry_CreateChatRoom_Call {
+func (_c *mockChatRoomRegistry_CreateChatRoom_Call) RunAndReturn(run func(context.Context, *state.ChatRoom) error) *mockChatRoomRegistry_CreateChatRoom_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 375 - 0
foodgroup/mock_client_side_buddy_list_manager_test.go

@@ -0,0 +1,375 @@
+// Code generated by mockery v2.52.1. DO NOT EDIT.
+
+package foodgroup
+
+import (
+	context "context"
+
+	state "github.com/mk6i/retro-aim-server/state"
+	mock "github.com/stretchr/testify/mock"
+
+	wire "github.com/mk6i/retro-aim-server/wire"
+)
+
+// mockClientSideBuddyListManager is an autogenerated mock type for the ClientSideBuddyListManager type
+type mockClientSideBuddyListManager struct {
+	mock.Mock
+}
+
+type mockClientSideBuddyListManager_Expecter struct {
+	mock *mock.Mock
+}
+
+func (_m *mockClientSideBuddyListManager) EXPECT() *mockClientSideBuddyListManager_Expecter {
+	return &mockClientSideBuddyListManager_Expecter{mock: &_m.Mock}
+}
+
+// AddBuddy provides a mock function with given fields: ctx, me, them
+func (_m *mockClientSideBuddyListManager) AddBuddy(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName) error {
+	ret := _m.Called(ctx, me, them)
+
+	if len(ret) == 0 {
+		panic("no return value specified for AddBuddy")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, state.IdentScreenName) error); ok {
+		r0 = rf(ctx, me, them)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// mockClientSideBuddyListManager_AddBuddy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddBuddy'
+type mockClientSideBuddyListManager_AddBuddy_Call struct {
+	*mock.Call
+}
+
+// AddBuddy is a helper method to define mock.On call
+//   - ctx context.Context
+//   - me state.IdentScreenName
+//   - them state.IdentScreenName
+func (_e *mockClientSideBuddyListManager_Expecter) AddBuddy(ctx interface{}, me interface{}, them interface{}) *mockClientSideBuddyListManager_AddBuddy_Call {
+	return &mockClientSideBuddyListManager_AddBuddy_Call{Call: _e.mock.On("AddBuddy", ctx, me, them)}
+}
+
+func (_c *mockClientSideBuddyListManager_AddBuddy_Call) Run(run func(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName)) *mockClientSideBuddyListManager_AddBuddy_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(state.IdentScreenName))
+	})
+	return _c
+}
+
+func (_c *mockClientSideBuddyListManager_AddBuddy_Call) Return(_a0 error) *mockClientSideBuddyListManager_AddBuddy_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *mockClientSideBuddyListManager_AddBuddy_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, state.IdentScreenName) error) *mockClientSideBuddyListManager_AddBuddy_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// DenyBuddy provides a mock function with given fields: ctx, me, them
+func (_m *mockClientSideBuddyListManager) DenyBuddy(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName) error {
+	ret := _m.Called(ctx, me, them)
+
+	if len(ret) == 0 {
+		panic("no return value specified for DenyBuddy")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, state.IdentScreenName) error); ok {
+		r0 = rf(ctx, me, them)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// mockClientSideBuddyListManager_DenyBuddy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DenyBuddy'
+type mockClientSideBuddyListManager_DenyBuddy_Call struct {
+	*mock.Call
+}
+
+// DenyBuddy is a helper method to define mock.On call
+//   - ctx context.Context
+//   - me state.IdentScreenName
+//   - them state.IdentScreenName
+func (_e *mockClientSideBuddyListManager_Expecter) DenyBuddy(ctx interface{}, me interface{}, them interface{}) *mockClientSideBuddyListManager_DenyBuddy_Call {
+	return &mockClientSideBuddyListManager_DenyBuddy_Call{Call: _e.mock.On("DenyBuddy", ctx, me, them)}
+}
+
+func (_c *mockClientSideBuddyListManager_DenyBuddy_Call) Run(run func(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName)) *mockClientSideBuddyListManager_DenyBuddy_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(state.IdentScreenName))
+	})
+	return _c
+}
+
+func (_c *mockClientSideBuddyListManager_DenyBuddy_Call) Return(_a0 error) *mockClientSideBuddyListManager_DenyBuddy_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *mockClientSideBuddyListManager_DenyBuddy_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, state.IdentScreenName) error) *mockClientSideBuddyListManager_DenyBuddy_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// PermitBuddy provides a mock function with given fields: ctx, me, them
+func (_m *mockClientSideBuddyListManager) PermitBuddy(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName) error {
+	ret := _m.Called(ctx, me, them)
+
+	if len(ret) == 0 {
+		panic("no return value specified for PermitBuddy")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, state.IdentScreenName) error); ok {
+		r0 = rf(ctx, me, them)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// mockClientSideBuddyListManager_PermitBuddy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PermitBuddy'
+type mockClientSideBuddyListManager_PermitBuddy_Call struct {
+	*mock.Call
+}
+
+// PermitBuddy is a helper method to define mock.On call
+//   - ctx context.Context
+//   - me state.IdentScreenName
+//   - them state.IdentScreenName
+func (_e *mockClientSideBuddyListManager_Expecter) PermitBuddy(ctx interface{}, me interface{}, them interface{}) *mockClientSideBuddyListManager_PermitBuddy_Call {
+	return &mockClientSideBuddyListManager_PermitBuddy_Call{Call: _e.mock.On("PermitBuddy", ctx, me, them)}
+}
+
+func (_c *mockClientSideBuddyListManager_PermitBuddy_Call) Run(run func(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName)) *mockClientSideBuddyListManager_PermitBuddy_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(state.IdentScreenName))
+	})
+	return _c
+}
+
+func (_c *mockClientSideBuddyListManager_PermitBuddy_Call) Return(_a0 error) *mockClientSideBuddyListManager_PermitBuddy_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *mockClientSideBuddyListManager_PermitBuddy_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, state.IdentScreenName) error) *mockClientSideBuddyListManager_PermitBuddy_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// RemoveBuddy provides a mock function with given fields: ctx, me, them
+func (_m *mockClientSideBuddyListManager) RemoveBuddy(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName) error {
+	ret := _m.Called(ctx, me, them)
+
+	if len(ret) == 0 {
+		panic("no return value specified for RemoveBuddy")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, state.IdentScreenName) error); ok {
+		r0 = rf(ctx, me, them)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// mockClientSideBuddyListManager_RemoveBuddy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveBuddy'
+type mockClientSideBuddyListManager_RemoveBuddy_Call struct {
+	*mock.Call
+}
+
+// RemoveBuddy is a helper method to define mock.On call
+//   - ctx context.Context
+//   - me state.IdentScreenName
+//   - them state.IdentScreenName
+func (_e *mockClientSideBuddyListManager_Expecter) RemoveBuddy(ctx interface{}, me interface{}, them interface{}) *mockClientSideBuddyListManager_RemoveBuddy_Call {
+	return &mockClientSideBuddyListManager_RemoveBuddy_Call{Call: _e.mock.On("RemoveBuddy", ctx, me, them)}
+}
+
+func (_c *mockClientSideBuddyListManager_RemoveBuddy_Call) Run(run func(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName)) *mockClientSideBuddyListManager_RemoveBuddy_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(state.IdentScreenName))
+	})
+	return _c
+}
+
+func (_c *mockClientSideBuddyListManager_RemoveBuddy_Call) Return(_a0 error) *mockClientSideBuddyListManager_RemoveBuddy_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *mockClientSideBuddyListManager_RemoveBuddy_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, state.IdentScreenName) error) *mockClientSideBuddyListManager_RemoveBuddy_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// RemoveDenyBuddy provides a mock function with given fields: ctx, me, them
+func (_m *mockClientSideBuddyListManager) RemoveDenyBuddy(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName) error {
+	ret := _m.Called(ctx, me, them)
+
+	if len(ret) == 0 {
+		panic("no return value specified for RemoveDenyBuddy")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, state.IdentScreenName) error); ok {
+		r0 = rf(ctx, me, them)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// mockClientSideBuddyListManager_RemoveDenyBuddy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveDenyBuddy'
+type mockClientSideBuddyListManager_RemoveDenyBuddy_Call struct {
+	*mock.Call
+}
+
+// RemoveDenyBuddy is a helper method to define mock.On call
+//   - ctx context.Context
+//   - me state.IdentScreenName
+//   - them state.IdentScreenName
+func (_e *mockClientSideBuddyListManager_Expecter) RemoveDenyBuddy(ctx interface{}, me interface{}, them interface{}) *mockClientSideBuddyListManager_RemoveDenyBuddy_Call {
+	return &mockClientSideBuddyListManager_RemoveDenyBuddy_Call{Call: _e.mock.On("RemoveDenyBuddy", ctx, me, them)}
+}
+
+func (_c *mockClientSideBuddyListManager_RemoveDenyBuddy_Call) Run(run func(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName)) *mockClientSideBuddyListManager_RemoveDenyBuddy_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(state.IdentScreenName))
+	})
+	return _c
+}
+
+func (_c *mockClientSideBuddyListManager_RemoveDenyBuddy_Call) Return(_a0 error) *mockClientSideBuddyListManager_RemoveDenyBuddy_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *mockClientSideBuddyListManager_RemoveDenyBuddy_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, state.IdentScreenName) error) *mockClientSideBuddyListManager_RemoveDenyBuddy_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// RemovePermitBuddy provides a mock function with given fields: ctx, me, them
+func (_m *mockClientSideBuddyListManager) RemovePermitBuddy(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName) error {
+	ret := _m.Called(ctx, me, them)
+
+	if len(ret) == 0 {
+		panic("no return value specified for RemovePermitBuddy")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, state.IdentScreenName) error); ok {
+		r0 = rf(ctx, me, them)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// mockClientSideBuddyListManager_RemovePermitBuddy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemovePermitBuddy'
+type mockClientSideBuddyListManager_RemovePermitBuddy_Call struct {
+	*mock.Call
+}
+
+// RemovePermitBuddy is a helper method to define mock.On call
+//   - ctx context.Context
+//   - me state.IdentScreenName
+//   - them state.IdentScreenName
+func (_e *mockClientSideBuddyListManager_Expecter) RemovePermitBuddy(ctx interface{}, me interface{}, them interface{}) *mockClientSideBuddyListManager_RemovePermitBuddy_Call {
+	return &mockClientSideBuddyListManager_RemovePermitBuddy_Call{Call: _e.mock.On("RemovePermitBuddy", ctx, me, them)}
+}
+
+func (_c *mockClientSideBuddyListManager_RemovePermitBuddy_Call) Run(run func(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName)) *mockClientSideBuddyListManager_RemovePermitBuddy_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(state.IdentScreenName))
+	})
+	return _c
+}
+
+func (_c *mockClientSideBuddyListManager_RemovePermitBuddy_Call) Return(_a0 error) *mockClientSideBuddyListManager_RemovePermitBuddy_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *mockClientSideBuddyListManager_RemovePermitBuddy_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, state.IdentScreenName) error) *mockClientSideBuddyListManager_RemovePermitBuddy_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// SetPDMode provides a mock function with given fields: ctx, me, pdMode
+func (_m *mockClientSideBuddyListManager) SetPDMode(ctx context.Context, me state.IdentScreenName, pdMode wire.FeedbagPDMode) error {
+	ret := _m.Called(ctx, me, pdMode)
+
+	if len(ret) == 0 {
+		panic("no return value specified for SetPDMode")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, wire.FeedbagPDMode) error); ok {
+		r0 = rf(ctx, me, pdMode)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// mockClientSideBuddyListManager_SetPDMode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPDMode'
+type mockClientSideBuddyListManager_SetPDMode_Call struct {
+	*mock.Call
+}
+
+// SetPDMode is a helper method to define mock.On call
+//   - ctx context.Context
+//   - me state.IdentScreenName
+//   - pdMode wire.FeedbagPDMode
+func (_e *mockClientSideBuddyListManager_Expecter) SetPDMode(ctx interface{}, me interface{}, pdMode interface{}) *mockClientSideBuddyListManager_SetPDMode_Call {
+	return &mockClientSideBuddyListManager_SetPDMode_Call{Call: _e.mock.On("SetPDMode", ctx, me, pdMode)}
+}
+
+func (_c *mockClientSideBuddyListManager_SetPDMode_Call) Run(run func(ctx context.Context, me state.IdentScreenName, pdMode wire.FeedbagPDMode)) *mockClientSideBuddyListManager_SetPDMode_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(wire.FeedbagPDMode))
+	})
+	return _c
+}
+
+func (_c *mockClientSideBuddyListManager_SetPDMode_Call) Return(_a0 error) *mockClientSideBuddyListManager_SetPDMode_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *mockClientSideBuddyListManager_SetPDMode_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, wire.FeedbagPDMode) error) *mockClientSideBuddyListManager_SetPDMode_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// newMockClientSideBuddyListManager creates a new instance of mockClientSideBuddyListManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func newMockClientSideBuddyListManager(t interface {
+	mock.TestingT
+	Cleanup(func())
+}) *mockClientSideBuddyListManager {
+	mock := &mockClientSideBuddyListManager{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}

+ 66 - 59
foodgroup/mock_feedbag_manager_test.go

@@ -3,6 +3,8 @@
 package foodgroup
 
 import (
+	context "context"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 
@@ -24,9 +26,9 @@ func (_m *mockFeedbagManager) EXPECT() *mockFeedbagManager_Expecter {
 	return &mockFeedbagManager_Expecter{mock: &_m.Mock}
 }
 
-// Feedbag provides a mock function with given fields: screenName
-func (_m *mockFeedbagManager) Feedbag(screenName state.IdentScreenName) ([]wire.FeedbagItem, error) {
-	ret := _m.Called(screenName)
+// Feedbag provides a mock function with given fields: ctx, screenName
+func (_m *mockFeedbagManager) Feedbag(ctx context.Context, screenName state.IdentScreenName) ([]wire.FeedbagItem, error) {
+	ret := _m.Called(ctx, screenName)
 
 	if len(ret) == 0 {
 		panic("no return value specified for Feedbag")
@@ -34,19 +36,19 @@ func (_m *mockFeedbagManager) Feedbag(screenName state.IdentScreenName) ([]wire.
 
 	var r0 []wire.FeedbagItem
 	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) ([]wire.FeedbagItem, error)); ok {
-		return rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) ([]wire.FeedbagItem, error)); ok {
+		return rf(ctx, screenName)
 	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) []wire.FeedbagItem); ok {
-		r0 = rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) []wire.FeedbagItem); ok {
+		r0 = rf(ctx, screenName)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).([]wire.FeedbagItem)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -60,14 +62,15 @@ type mockFeedbagManager_Feedbag_Call struct {
 }
 
 // Feedbag is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockFeedbagManager_Expecter) Feedbag(screenName interface{}) *mockFeedbagManager_Feedbag_Call {
-	return &mockFeedbagManager_Feedbag_Call{Call: _e.mock.On("Feedbag", screenName)}
+func (_e *mockFeedbagManager_Expecter) Feedbag(ctx interface{}, screenName interface{}) *mockFeedbagManager_Feedbag_Call {
+	return &mockFeedbagManager_Feedbag_Call{Call: _e.mock.On("Feedbag", ctx, screenName)}
 }
 
-func (_c *mockFeedbagManager_Feedbag_Call) Run(run func(screenName state.IdentScreenName)) *mockFeedbagManager_Feedbag_Call {
+func (_c *mockFeedbagManager_Feedbag_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockFeedbagManager_Feedbag_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
@@ -77,22 +80,22 @@ func (_c *mockFeedbagManager_Feedbag_Call) Return(_a0 []wire.FeedbagItem, _a1 er
 	return _c
 }
 
-func (_c *mockFeedbagManager_Feedbag_Call) RunAndReturn(run func(state.IdentScreenName) ([]wire.FeedbagItem, error)) *mockFeedbagManager_Feedbag_Call {
+func (_c *mockFeedbagManager_Feedbag_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) ([]wire.FeedbagItem, error)) *mockFeedbagManager_Feedbag_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// FeedbagDelete provides a mock function with given fields: screenName, items
-func (_m *mockFeedbagManager) FeedbagDelete(screenName state.IdentScreenName, items []wire.FeedbagItem) error {
-	ret := _m.Called(screenName, items)
+// FeedbagDelete provides a mock function with given fields: ctx, screenName, items
+func (_m *mockFeedbagManager) FeedbagDelete(ctx context.Context, screenName state.IdentScreenName, items []wire.FeedbagItem) error {
+	ret := _m.Called(ctx, screenName, items)
 
 	if len(ret) == 0 {
 		panic("no return value specified for FeedbagDelete")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, []wire.FeedbagItem) error); ok {
-		r0 = rf(screenName, items)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, []wire.FeedbagItem) error); ok {
+		r0 = rf(ctx, screenName, items)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -106,15 +109,16 @@ type mockFeedbagManager_FeedbagDelete_Call struct {
 }
 
 // FeedbagDelete is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
 //   - items []wire.FeedbagItem
-func (_e *mockFeedbagManager_Expecter) FeedbagDelete(screenName interface{}, items interface{}) *mockFeedbagManager_FeedbagDelete_Call {
-	return &mockFeedbagManager_FeedbagDelete_Call{Call: _e.mock.On("FeedbagDelete", screenName, items)}
+func (_e *mockFeedbagManager_Expecter) FeedbagDelete(ctx interface{}, screenName interface{}, items interface{}) *mockFeedbagManager_FeedbagDelete_Call {
+	return &mockFeedbagManager_FeedbagDelete_Call{Call: _e.mock.On("FeedbagDelete", ctx, screenName, items)}
 }
 
-func (_c *mockFeedbagManager_FeedbagDelete_Call) Run(run func(screenName state.IdentScreenName, items []wire.FeedbagItem)) *mockFeedbagManager_FeedbagDelete_Call {
+func (_c *mockFeedbagManager_FeedbagDelete_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName, items []wire.FeedbagItem)) *mockFeedbagManager_FeedbagDelete_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].([]wire.FeedbagItem))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].([]wire.FeedbagItem))
 	})
 	return _c
 }
@@ -124,14 +128,14 @@ func (_c *mockFeedbagManager_FeedbagDelete_Call) Return(_a0 error) *mockFeedbagM
 	return _c
 }
 
-func (_c *mockFeedbagManager_FeedbagDelete_Call) RunAndReturn(run func(state.IdentScreenName, []wire.FeedbagItem) error) *mockFeedbagManager_FeedbagDelete_Call {
+func (_c *mockFeedbagManager_FeedbagDelete_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, []wire.FeedbagItem) error) *mockFeedbagManager_FeedbagDelete_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// FeedbagLastModified provides a mock function with given fields: screenName
-func (_m *mockFeedbagManager) FeedbagLastModified(screenName state.IdentScreenName) (time.Time, error) {
-	ret := _m.Called(screenName)
+// FeedbagLastModified provides a mock function with given fields: ctx, screenName
+func (_m *mockFeedbagManager) FeedbagLastModified(ctx context.Context, screenName state.IdentScreenName) (time.Time, error) {
+	ret := _m.Called(ctx, screenName)
 
 	if len(ret) == 0 {
 		panic("no return value specified for FeedbagLastModified")
@@ -139,17 +143,17 @@ func (_m *mockFeedbagManager) FeedbagLastModified(screenName state.IdentScreenNa
 
 	var r0 time.Time
 	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (time.Time, error)); ok {
-		return rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) (time.Time, error)); ok {
+		return rf(ctx, screenName)
 	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) time.Time); ok {
-		r0 = rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) time.Time); ok {
+		r0 = rf(ctx, screenName)
 	} else {
 		r0 = ret.Get(0).(time.Time)
 	}
 
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -163,14 +167,15 @@ type mockFeedbagManager_FeedbagLastModified_Call struct {
 }
 
 // FeedbagLastModified is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockFeedbagManager_Expecter) FeedbagLastModified(screenName interface{}) *mockFeedbagManager_FeedbagLastModified_Call {
-	return &mockFeedbagManager_FeedbagLastModified_Call{Call: _e.mock.On("FeedbagLastModified", screenName)}
+func (_e *mockFeedbagManager_Expecter) FeedbagLastModified(ctx interface{}, screenName interface{}) *mockFeedbagManager_FeedbagLastModified_Call {
+	return &mockFeedbagManager_FeedbagLastModified_Call{Call: _e.mock.On("FeedbagLastModified", ctx, screenName)}
 }
 
-func (_c *mockFeedbagManager_FeedbagLastModified_Call) Run(run func(screenName state.IdentScreenName)) *mockFeedbagManager_FeedbagLastModified_Call {
+func (_c *mockFeedbagManager_FeedbagLastModified_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockFeedbagManager_FeedbagLastModified_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
@@ -180,22 +185,22 @@ func (_c *mockFeedbagManager_FeedbagLastModified_Call) Return(_a0 time.Time, _a1
 	return _c
 }
 
-func (_c *mockFeedbagManager_FeedbagLastModified_Call) RunAndReturn(run func(state.IdentScreenName) (time.Time, error)) *mockFeedbagManager_FeedbagLastModified_Call {
+func (_c *mockFeedbagManager_FeedbagLastModified_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) (time.Time, error)) *mockFeedbagManager_FeedbagLastModified_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// FeedbagUpsert provides a mock function with given fields: screenName, items
-func (_m *mockFeedbagManager) FeedbagUpsert(screenName state.IdentScreenName, items []wire.FeedbagItem) error {
-	ret := _m.Called(screenName, items)
+// FeedbagUpsert provides a mock function with given fields: ctx, screenName, items
+func (_m *mockFeedbagManager) FeedbagUpsert(ctx context.Context, screenName state.IdentScreenName, items []wire.FeedbagItem) error {
+	ret := _m.Called(ctx, screenName, items)
 
 	if len(ret) == 0 {
 		panic("no return value specified for FeedbagUpsert")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, []wire.FeedbagItem) error); ok {
-		r0 = rf(screenName, items)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, []wire.FeedbagItem) error); ok {
+		r0 = rf(ctx, screenName, items)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -209,15 +214,16 @@ type mockFeedbagManager_FeedbagUpsert_Call struct {
 }
 
 // FeedbagUpsert is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
 //   - items []wire.FeedbagItem
-func (_e *mockFeedbagManager_Expecter) FeedbagUpsert(screenName interface{}, items interface{}) *mockFeedbagManager_FeedbagUpsert_Call {
-	return &mockFeedbagManager_FeedbagUpsert_Call{Call: _e.mock.On("FeedbagUpsert", screenName, items)}
+func (_e *mockFeedbagManager_Expecter) FeedbagUpsert(ctx interface{}, screenName interface{}, items interface{}) *mockFeedbagManager_FeedbagUpsert_Call {
+	return &mockFeedbagManager_FeedbagUpsert_Call{Call: _e.mock.On("FeedbagUpsert", ctx, screenName, items)}
 }
 
-func (_c *mockFeedbagManager_FeedbagUpsert_Call) Run(run func(screenName state.IdentScreenName, items []wire.FeedbagItem)) *mockFeedbagManager_FeedbagUpsert_Call {
+func (_c *mockFeedbagManager_FeedbagUpsert_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName, items []wire.FeedbagItem)) *mockFeedbagManager_FeedbagUpsert_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].([]wire.FeedbagItem))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].([]wire.FeedbagItem))
 	})
 	return _c
 }
@@ -227,22 +233,22 @@ func (_c *mockFeedbagManager_FeedbagUpsert_Call) Return(_a0 error) *mockFeedbagM
 	return _c
 }
 
-func (_c *mockFeedbagManager_FeedbagUpsert_Call) RunAndReturn(run func(state.IdentScreenName, []wire.FeedbagItem) error) *mockFeedbagManager_FeedbagUpsert_Call {
+func (_c *mockFeedbagManager_FeedbagUpsert_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, []wire.FeedbagItem) error) *mockFeedbagManager_FeedbagUpsert_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// UseFeedbag provides a mock function with given fields: user
-func (_m *mockFeedbagManager) UseFeedbag(user state.IdentScreenName) error {
-	ret := _m.Called(user)
+// UseFeedbag provides a mock function with given fields: ctx, screenName
+func (_m *mockFeedbagManager) UseFeedbag(ctx context.Context, screenName state.IdentScreenName) error {
+	ret := _m.Called(ctx, screenName)
 
 	if len(ret) == 0 {
 		panic("no return value specified for UseFeedbag")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) error); ok {
-		r0 = rf(user)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) error); ok {
+		r0 = rf(ctx, screenName)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -256,14 +262,15 @@ type mockFeedbagManager_UseFeedbag_Call struct {
 }
 
 // UseFeedbag is a helper method to define mock.On call
-//   - user state.IdentScreenName
-func (_e *mockFeedbagManager_Expecter) UseFeedbag(user interface{}) *mockFeedbagManager_UseFeedbag_Call {
-	return &mockFeedbagManager_UseFeedbag_Call{Call: _e.mock.On("UseFeedbag", user)}
+//   - ctx context.Context
+//   - screenName state.IdentScreenName
+func (_e *mockFeedbagManager_Expecter) UseFeedbag(ctx interface{}, screenName interface{}) *mockFeedbagManager_UseFeedbag_Call {
+	return &mockFeedbagManager_UseFeedbag_Call{Call: _e.mock.On("UseFeedbag", ctx, screenName)}
 }
 
-func (_c *mockFeedbagManager_UseFeedbag_Call) Run(run func(user state.IdentScreenName)) *mockFeedbagManager_UseFeedbag_Call {
+func (_c *mockFeedbagManager_UseFeedbag_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockFeedbagManager_UseFeedbag_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
@@ -273,7 +280,7 @@ func (_c *mockFeedbagManager_UseFeedbag_Call) Return(_a0 error) *mockFeedbagMana
 	return _c
 }
 
-func (_c *mockFeedbagManager_UseFeedbag_Call) RunAndReturn(run func(state.IdentScreenName) error) *mockFeedbagManager_UseFeedbag_Call {
+func (_c *mockFeedbagManager_UseFeedbag_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) error) *mockFeedbagManager_UseFeedbag_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 77 - 70
foodgroup/mock_icq_user_finder_test.go

@@ -3,6 +3,8 @@
 package foodgroup
 
 import (
+	context "context"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 )
@@ -20,9 +22,9 @@ func (_m *mockICQUserFinder) EXPECT() *mockICQUserFinder_Expecter {
 	return &mockICQUserFinder_Expecter{mock: &_m.Mock}
 }
 
-// FindByICQEmail provides a mock function with given fields: email
-func (_m *mockICQUserFinder) FindByICQEmail(email string) (state.User, error) {
-	ret := _m.Called(email)
+// FindByICQEmail provides a mock function with given fields: ctx, email
+func (_m *mockICQUserFinder) FindByICQEmail(ctx context.Context, email string) (state.User, error) {
+	ret := _m.Called(ctx, email)
 
 	if len(ret) == 0 {
 		panic("no return value specified for FindByICQEmail")
@@ -30,17 +32,17 @@ func (_m *mockICQUserFinder) FindByICQEmail(email string) (state.User, error) {
 
 	var r0 state.User
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string) (state.User, error)); ok {
-		return rf(email)
+	if rf, ok := ret.Get(0).(func(context.Context, string) (state.User, error)); ok {
+		return rf(ctx, email)
 	}
-	if rf, ok := ret.Get(0).(func(string) state.User); ok {
-		r0 = rf(email)
+	if rf, ok := ret.Get(0).(func(context.Context, string) state.User); ok {
+		r0 = rf(ctx, email)
 	} else {
 		r0 = ret.Get(0).(state.User)
 	}
 
-	if rf, ok := ret.Get(1).(func(string) error); ok {
-		r1 = rf(email)
+	if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
+		r1 = rf(ctx, email)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -54,14 +56,15 @@ type mockICQUserFinder_FindByICQEmail_Call struct {
 }
 
 // FindByICQEmail is a helper method to define mock.On call
+//   - ctx context.Context
 //   - email string
-func (_e *mockICQUserFinder_Expecter) FindByICQEmail(email interface{}) *mockICQUserFinder_FindByICQEmail_Call {
-	return &mockICQUserFinder_FindByICQEmail_Call{Call: _e.mock.On("FindByICQEmail", email)}
+func (_e *mockICQUserFinder_Expecter) FindByICQEmail(ctx interface{}, email interface{}) *mockICQUserFinder_FindByICQEmail_Call {
+	return &mockICQUserFinder_FindByICQEmail_Call{Call: _e.mock.On("FindByICQEmail", ctx, email)}
 }
 
-func (_c *mockICQUserFinder_FindByICQEmail_Call) Run(run func(email string)) *mockICQUserFinder_FindByICQEmail_Call {
+func (_c *mockICQUserFinder_FindByICQEmail_Call) Run(run func(ctx context.Context, email string)) *mockICQUserFinder_FindByICQEmail_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(context.Context), args[1].(string))
 	})
 	return _c
 }
@@ -71,14 +74,14 @@ func (_c *mockICQUserFinder_FindByICQEmail_Call) Return(_a0 state.User, _a1 erro
 	return _c
 }
 
-func (_c *mockICQUserFinder_FindByICQEmail_Call) RunAndReturn(run func(string) (state.User, error)) *mockICQUserFinder_FindByICQEmail_Call {
+func (_c *mockICQUserFinder_FindByICQEmail_Call) RunAndReturn(run func(context.Context, string) (state.User, error)) *mockICQUserFinder_FindByICQEmail_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// FindByICQInterests provides a mock function with given fields: code, keywords
-func (_m *mockICQUserFinder) FindByICQInterests(code uint16, keywords []string) ([]state.User, error) {
-	ret := _m.Called(code, keywords)
+// FindByICQInterests provides a mock function with given fields: ctx, code, keywords
+func (_m *mockICQUserFinder) FindByICQInterests(ctx context.Context, code uint16, keywords []string) ([]state.User, error) {
+	ret := _m.Called(ctx, code, keywords)
 
 	if len(ret) == 0 {
 		panic("no return value specified for FindByICQInterests")
@@ -86,19 +89,19 @@ func (_m *mockICQUserFinder) FindByICQInterests(code uint16, keywords []string)
 
 	var r0 []state.User
 	var r1 error
-	if rf, ok := ret.Get(0).(func(uint16, []string) ([]state.User, error)); ok {
-		return rf(code, keywords)
+	if rf, ok := ret.Get(0).(func(context.Context, uint16, []string) ([]state.User, error)); ok {
+		return rf(ctx, code, keywords)
 	}
-	if rf, ok := ret.Get(0).(func(uint16, []string) []state.User); ok {
-		r0 = rf(code, keywords)
+	if rf, ok := ret.Get(0).(func(context.Context, uint16, []string) []state.User); ok {
+		r0 = rf(ctx, code, keywords)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).([]state.User)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(uint16, []string) error); ok {
-		r1 = rf(code, keywords)
+	if rf, ok := ret.Get(1).(func(context.Context, uint16, []string) error); ok {
+		r1 = rf(ctx, code, keywords)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -112,15 +115,16 @@ type mockICQUserFinder_FindByICQInterests_Call struct {
 }
 
 // FindByICQInterests is a helper method to define mock.On call
+//   - ctx context.Context
 //   - code uint16
 //   - keywords []string
-func (_e *mockICQUserFinder_Expecter) FindByICQInterests(code interface{}, keywords interface{}) *mockICQUserFinder_FindByICQInterests_Call {
-	return &mockICQUserFinder_FindByICQInterests_Call{Call: _e.mock.On("FindByICQInterests", code, keywords)}
+func (_e *mockICQUserFinder_Expecter) FindByICQInterests(ctx interface{}, code interface{}, keywords interface{}) *mockICQUserFinder_FindByICQInterests_Call {
+	return &mockICQUserFinder_FindByICQInterests_Call{Call: _e.mock.On("FindByICQInterests", ctx, code, keywords)}
 }
 
-func (_c *mockICQUserFinder_FindByICQInterests_Call) Run(run func(code uint16, keywords []string)) *mockICQUserFinder_FindByICQInterests_Call {
+func (_c *mockICQUserFinder_FindByICQInterests_Call) Run(run func(ctx context.Context, code uint16, keywords []string)) *mockICQUserFinder_FindByICQInterests_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(uint16), args[1].([]string))
+		run(args[0].(context.Context), args[1].(uint16), args[2].([]string))
 	})
 	return _c
 }
@@ -130,14 +134,14 @@ func (_c *mockICQUserFinder_FindByICQInterests_Call) Return(_a0 []state.User, _a
 	return _c
 }
 
-func (_c *mockICQUserFinder_FindByICQInterests_Call) RunAndReturn(run func(uint16, []string) ([]state.User, error)) *mockICQUserFinder_FindByICQInterests_Call {
+func (_c *mockICQUserFinder_FindByICQInterests_Call) RunAndReturn(run func(context.Context, uint16, []string) ([]state.User, error)) *mockICQUserFinder_FindByICQInterests_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// FindByICQKeyword provides a mock function with given fields: keyword
-func (_m *mockICQUserFinder) FindByICQKeyword(keyword string) ([]state.User, error) {
-	ret := _m.Called(keyword)
+// FindByICQKeyword provides a mock function with given fields: ctx, keyword
+func (_m *mockICQUserFinder) FindByICQKeyword(ctx context.Context, keyword string) ([]state.User, error) {
+	ret := _m.Called(ctx, keyword)
 
 	if len(ret) == 0 {
 		panic("no return value specified for FindByICQKeyword")
@@ -145,19 +149,19 @@ func (_m *mockICQUserFinder) FindByICQKeyword(keyword string) ([]state.User, err
 
 	var r0 []state.User
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string) ([]state.User, error)); ok {
-		return rf(keyword)
+	if rf, ok := ret.Get(0).(func(context.Context, string) ([]state.User, error)); ok {
+		return rf(ctx, keyword)
 	}
-	if rf, ok := ret.Get(0).(func(string) []state.User); ok {
-		r0 = rf(keyword)
+	if rf, ok := ret.Get(0).(func(context.Context, string) []state.User); ok {
+		r0 = rf(ctx, keyword)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).([]state.User)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(string) error); ok {
-		r1 = rf(keyword)
+	if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
+		r1 = rf(ctx, keyword)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -171,14 +175,15 @@ type mockICQUserFinder_FindByICQKeyword_Call struct {
 }
 
 // FindByICQKeyword is a helper method to define mock.On call
+//   - ctx context.Context
 //   - keyword string
-func (_e *mockICQUserFinder_Expecter) FindByICQKeyword(keyword interface{}) *mockICQUserFinder_FindByICQKeyword_Call {
-	return &mockICQUserFinder_FindByICQKeyword_Call{Call: _e.mock.On("FindByICQKeyword", keyword)}
+func (_e *mockICQUserFinder_Expecter) FindByICQKeyword(ctx interface{}, keyword interface{}) *mockICQUserFinder_FindByICQKeyword_Call {
+	return &mockICQUserFinder_FindByICQKeyword_Call{Call: _e.mock.On("FindByICQKeyword", ctx, keyword)}
 }
 
-func (_c *mockICQUserFinder_FindByICQKeyword_Call) Run(run func(keyword string)) *mockICQUserFinder_FindByICQKeyword_Call {
+func (_c *mockICQUserFinder_FindByICQKeyword_Call) Run(run func(ctx context.Context, keyword string)) *mockICQUserFinder_FindByICQKeyword_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(context.Context), args[1].(string))
 	})
 	return _c
 }
@@ -188,14 +193,14 @@ func (_c *mockICQUserFinder_FindByICQKeyword_Call) Return(_a0 []state.User, _a1
 	return _c
 }
 
-func (_c *mockICQUserFinder_FindByICQKeyword_Call) RunAndReturn(run func(string) ([]state.User, error)) *mockICQUserFinder_FindByICQKeyword_Call {
+func (_c *mockICQUserFinder_FindByICQKeyword_Call) RunAndReturn(run func(context.Context, string) ([]state.User, error)) *mockICQUserFinder_FindByICQKeyword_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// FindByICQName provides a mock function with given fields: firstName, lastName, nickName
-func (_m *mockICQUserFinder) FindByICQName(firstName string, lastName string, nickName string) ([]state.User, error) {
-	ret := _m.Called(firstName, lastName, nickName)
+// FindByICQName provides a mock function with given fields: ctx, firstName, lastName, nickName
+func (_m *mockICQUserFinder) FindByICQName(ctx context.Context, firstName string, lastName string, nickName string) ([]state.User, error) {
+	ret := _m.Called(ctx, firstName, lastName, nickName)
 
 	if len(ret) == 0 {
 		panic("no return value specified for FindByICQName")
@@ -203,19 +208,19 @@ func (_m *mockICQUserFinder) FindByICQName(firstName string, lastName string, ni
 
 	var r0 []state.User
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string, string, string) ([]state.User, error)); ok {
-		return rf(firstName, lastName, nickName)
+	if rf, ok := ret.Get(0).(func(context.Context, string, string, string) ([]state.User, error)); ok {
+		return rf(ctx, firstName, lastName, nickName)
 	}
-	if rf, ok := ret.Get(0).(func(string, string, string) []state.User); ok {
-		r0 = rf(firstName, lastName, nickName)
+	if rf, ok := ret.Get(0).(func(context.Context, string, string, string) []state.User); ok {
+		r0 = rf(ctx, firstName, lastName, nickName)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).([]state.User)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(string, string, string) error); ok {
-		r1 = rf(firstName, lastName, nickName)
+	if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok {
+		r1 = rf(ctx, firstName, lastName, nickName)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -229,16 +234,17 @@ type mockICQUserFinder_FindByICQName_Call struct {
 }
 
 // FindByICQName is a helper method to define mock.On call
+//   - ctx context.Context
 //   - firstName string
 //   - lastName string
 //   - nickName string
-func (_e *mockICQUserFinder_Expecter) FindByICQName(firstName interface{}, lastName interface{}, nickName interface{}) *mockICQUserFinder_FindByICQName_Call {
-	return &mockICQUserFinder_FindByICQName_Call{Call: _e.mock.On("FindByICQName", firstName, lastName, nickName)}
+func (_e *mockICQUserFinder_Expecter) FindByICQName(ctx interface{}, firstName interface{}, lastName interface{}, nickName interface{}) *mockICQUserFinder_FindByICQName_Call {
+	return &mockICQUserFinder_FindByICQName_Call{Call: _e.mock.On("FindByICQName", ctx, firstName, lastName, nickName)}
 }
 
-func (_c *mockICQUserFinder_FindByICQName_Call) Run(run func(firstName string, lastName string, nickName string)) *mockICQUserFinder_FindByICQName_Call {
+func (_c *mockICQUserFinder_FindByICQName_Call) Run(run func(ctx context.Context, firstName string, lastName string, nickName string)) *mockICQUserFinder_FindByICQName_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string), args[1].(string), args[2].(string))
+		run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(string))
 	})
 	return _c
 }
@@ -248,14 +254,14 @@ func (_c *mockICQUserFinder_FindByICQName_Call) Return(_a0 []state.User, _a1 err
 	return _c
 }
 
-func (_c *mockICQUserFinder_FindByICQName_Call) RunAndReturn(run func(string, string, string) ([]state.User, error)) *mockICQUserFinder_FindByICQName_Call {
+func (_c *mockICQUserFinder_FindByICQName_Call) RunAndReturn(run func(context.Context, string, string, string) ([]state.User, error)) *mockICQUserFinder_FindByICQName_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// FindByUIN provides a mock function with given fields: UIN
-func (_m *mockICQUserFinder) FindByUIN(UIN uint32) (state.User, error) {
-	ret := _m.Called(UIN)
+// FindByUIN provides a mock function with given fields: ctx, UIN
+func (_m *mockICQUserFinder) FindByUIN(ctx context.Context, UIN uint32) (state.User, error) {
+	ret := _m.Called(ctx, UIN)
 
 	if len(ret) == 0 {
 		panic("no return value specified for FindByUIN")
@@ -263,17 +269,17 @@ func (_m *mockICQUserFinder) FindByUIN(UIN uint32) (state.User, error) {
 
 	var r0 state.User
 	var r1 error
-	if rf, ok := ret.Get(0).(func(uint32) (state.User, error)); ok {
-		return rf(UIN)
+	if rf, ok := ret.Get(0).(func(context.Context, uint32) (state.User, error)); ok {
+		return rf(ctx, UIN)
 	}
-	if rf, ok := ret.Get(0).(func(uint32) state.User); ok {
-		r0 = rf(UIN)
+	if rf, ok := ret.Get(0).(func(context.Context, uint32) state.User); ok {
+		r0 = rf(ctx, UIN)
 	} else {
 		r0 = ret.Get(0).(state.User)
 	}
 
-	if rf, ok := ret.Get(1).(func(uint32) error); ok {
-		r1 = rf(UIN)
+	if rf, ok := ret.Get(1).(func(context.Context, uint32) error); ok {
+		r1 = rf(ctx, UIN)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -287,14 +293,15 @@ type mockICQUserFinder_FindByUIN_Call struct {
 }
 
 // FindByUIN is a helper method to define mock.On call
+//   - ctx context.Context
 //   - UIN uint32
-func (_e *mockICQUserFinder_Expecter) FindByUIN(UIN interface{}) *mockICQUserFinder_FindByUIN_Call {
-	return &mockICQUserFinder_FindByUIN_Call{Call: _e.mock.On("FindByUIN", UIN)}
+func (_e *mockICQUserFinder_Expecter) FindByUIN(ctx interface{}, UIN interface{}) *mockICQUserFinder_FindByUIN_Call {
+	return &mockICQUserFinder_FindByUIN_Call{Call: _e.mock.On("FindByUIN", ctx, UIN)}
 }
 
-func (_c *mockICQUserFinder_FindByUIN_Call) Run(run func(UIN uint32)) *mockICQUserFinder_FindByUIN_Call {
+func (_c *mockICQUserFinder_FindByUIN_Call) Run(run func(ctx context.Context, UIN uint32)) *mockICQUserFinder_FindByUIN_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(uint32))
+		run(args[0].(context.Context), args[1].(uint32))
 	})
 	return _c
 }
@@ -304,7 +311,7 @@ func (_c *mockICQUserFinder_FindByUIN_Call) Return(_a0 state.User, _a1 error) *m
 	return _c
 }
 
-func (_c *mockICQUserFinder_FindByUIN_Call) RunAndReturn(run func(uint32) (state.User, error)) *mockICQUserFinder_FindByUIN_Call {
+func (_c *mockICQUserFinder_FindByUIN_Call) RunAndReturn(run func(context.Context, uint32) (state.User, error)) *mockICQUserFinder_FindByUIN_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 68 - 60
foodgroup/mock_icq_user_updater_test.go

@@ -3,6 +3,8 @@
 package foodgroup
 
 import (
+	context "context"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 )
@@ -20,17 +22,17 @@ func (_m *mockICQUserUpdater) EXPECT() *mockICQUserUpdater_Expecter {
 	return &mockICQUserUpdater_Expecter{mock: &_m.Mock}
 }
 
-// SetAffiliations provides a mock function with given fields: name, data
-func (_m *mockICQUserUpdater) SetAffiliations(name state.IdentScreenName, data state.ICQAffiliations) error {
-	ret := _m.Called(name, data)
+// SetAffiliations provides a mock function with given fields: ctx, name, data
+func (_m *mockICQUserUpdater) SetAffiliations(ctx context.Context, name state.IdentScreenName, data state.ICQAffiliations) error {
+	ret := _m.Called(ctx, name, data)
 
 	if len(ret) == 0 {
 		panic("no return value specified for SetAffiliations")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.ICQAffiliations) error); ok {
-		r0 = rf(name, data)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, state.ICQAffiliations) error); ok {
+		r0 = rf(ctx, name, data)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -44,15 +46,16 @@ type mockICQUserUpdater_SetAffiliations_Call struct {
 }
 
 // SetAffiliations is a helper method to define mock.On call
+//   - ctx context.Context
 //   - name state.IdentScreenName
 //   - data state.ICQAffiliations
-func (_e *mockICQUserUpdater_Expecter) SetAffiliations(name interface{}, data interface{}) *mockICQUserUpdater_SetAffiliations_Call {
-	return &mockICQUserUpdater_SetAffiliations_Call{Call: _e.mock.On("SetAffiliations", name, data)}
+func (_e *mockICQUserUpdater_Expecter) SetAffiliations(ctx interface{}, name interface{}, data interface{}) *mockICQUserUpdater_SetAffiliations_Call {
+	return &mockICQUserUpdater_SetAffiliations_Call{Call: _e.mock.On("SetAffiliations", ctx, name, data)}
 }
 
-func (_c *mockICQUserUpdater_SetAffiliations_Call) Run(run func(name state.IdentScreenName, data state.ICQAffiliations)) *mockICQUserUpdater_SetAffiliations_Call {
+func (_c *mockICQUserUpdater_SetAffiliations_Call) Run(run func(ctx context.Context, name state.IdentScreenName, data state.ICQAffiliations)) *mockICQUserUpdater_SetAffiliations_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(state.ICQAffiliations))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(state.ICQAffiliations))
 	})
 	return _c
 }
@@ -62,22 +65,22 @@ func (_c *mockICQUserUpdater_SetAffiliations_Call) Return(_a0 error) *mockICQUse
 	return _c
 }
 
-func (_c *mockICQUserUpdater_SetAffiliations_Call) RunAndReturn(run func(state.IdentScreenName, state.ICQAffiliations) error) *mockICQUserUpdater_SetAffiliations_Call {
+func (_c *mockICQUserUpdater_SetAffiliations_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, state.ICQAffiliations) error) *mockICQUserUpdater_SetAffiliations_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// SetBasicInfo provides a mock function with given fields: name, data
-func (_m *mockICQUserUpdater) SetBasicInfo(name state.IdentScreenName, data state.ICQBasicInfo) error {
-	ret := _m.Called(name, data)
+// SetBasicInfo provides a mock function with given fields: ctx, name, data
+func (_m *mockICQUserUpdater) SetBasicInfo(ctx context.Context, name state.IdentScreenName, data state.ICQBasicInfo) error {
+	ret := _m.Called(ctx, name, data)
 
 	if len(ret) == 0 {
 		panic("no return value specified for SetBasicInfo")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.ICQBasicInfo) error); ok {
-		r0 = rf(name, data)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, state.ICQBasicInfo) error); ok {
+		r0 = rf(ctx, name, data)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -91,15 +94,16 @@ type mockICQUserUpdater_SetBasicInfo_Call struct {
 }
 
 // SetBasicInfo is a helper method to define mock.On call
+//   - ctx context.Context
 //   - name state.IdentScreenName
 //   - data state.ICQBasicInfo
-func (_e *mockICQUserUpdater_Expecter) SetBasicInfo(name interface{}, data interface{}) *mockICQUserUpdater_SetBasicInfo_Call {
-	return &mockICQUserUpdater_SetBasicInfo_Call{Call: _e.mock.On("SetBasicInfo", name, data)}
+func (_e *mockICQUserUpdater_Expecter) SetBasicInfo(ctx interface{}, name interface{}, data interface{}) *mockICQUserUpdater_SetBasicInfo_Call {
+	return &mockICQUserUpdater_SetBasicInfo_Call{Call: _e.mock.On("SetBasicInfo", ctx, name, data)}
 }
 
-func (_c *mockICQUserUpdater_SetBasicInfo_Call) Run(run func(name state.IdentScreenName, data state.ICQBasicInfo)) *mockICQUserUpdater_SetBasicInfo_Call {
+func (_c *mockICQUserUpdater_SetBasicInfo_Call) Run(run func(ctx context.Context, name state.IdentScreenName, data state.ICQBasicInfo)) *mockICQUserUpdater_SetBasicInfo_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(state.ICQBasicInfo))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(state.ICQBasicInfo))
 	})
 	return _c
 }
@@ -109,22 +113,22 @@ func (_c *mockICQUserUpdater_SetBasicInfo_Call) Return(_a0 error) *mockICQUserUp
 	return _c
 }
 
-func (_c *mockICQUserUpdater_SetBasicInfo_Call) RunAndReturn(run func(state.IdentScreenName, state.ICQBasicInfo) error) *mockICQUserUpdater_SetBasicInfo_Call {
+func (_c *mockICQUserUpdater_SetBasicInfo_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, state.ICQBasicInfo) error) *mockICQUserUpdater_SetBasicInfo_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// SetInterests provides a mock function with given fields: name, data
-func (_m *mockICQUserUpdater) SetInterests(name state.IdentScreenName, data state.ICQInterests) error {
-	ret := _m.Called(name, data)
+// SetInterests provides a mock function with given fields: ctx, name, data
+func (_m *mockICQUserUpdater) SetInterests(ctx context.Context, name state.IdentScreenName, data state.ICQInterests) error {
+	ret := _m.Called(ctx, name, data)
 
 	if len(ret) == 0 {
 		panic("no return value specified for SetInterests")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.ICQInterests) error); ok {
-		r0 = rf(name, data)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, state.ICQInterests) error); ok {
+		r0 = rf(ctx, name, data)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -138,15 +142,16 @@ type mockICQUserUpdater_SetInterests_Call struct {
 }
 
 // SetInterests is a helper method to define mock.On call
+//   - ctx context.Context
 //   - name state.IdentScreenName
 //   - data state.ICQInterests
-func (_e *mockICQUserUpdater_Expecter) SetInterests(name interface{}, data interface{}) *mockICQUserUpdater_SetInterests_Call {
-	return &mockICQUserUpdater_SetInterests_Call{Call: _e.mock.On("SetInterests", name, data)}
+func (_e *mockICQUserUpdater_Expecter) SetInterests(ctx interface{}, name interface{}, data interface{}) *mockICQUserUpdater_SetInterests_Call {
+	return &mockICQUserUpdater_SetInterests_Call{Call: _e.mock.On("SetInterests", ctx, name, data)}
 }
 
-func (_c *mockICQUserUpdater_SetInterests_Call) Run(run func(name state.IdentScreenName, data state.ICQInterests)) *mockICQUserUpdater_SetInterests_Call {
+func (_c *mockICQUserUpdater_SetInterests_Call) Run(run func(ctx context.Context, name state.IdentScreenName, data state.ICQInterests)) *mockICQUserUpdater_SetInterests_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(state.ICQInterests))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(state.ICQInterests))
 	})
 	return _c
 }
@@ -156,22 +161,22 @@ func (_c *mockICQUserUpdater_SetInterests_Call) Return(_a0 error) *mockICQUserUp
 	return _c
 }
 
-func (_c *mockICQUserUpdater_SetInterests_Call) RunAndReturn(run func(state.IdentScreenName, state.ICQInterests) error) *mockICQUserUpdater_SetInterests_Call {
+func (_c *mockICQUserUpdater_SetInterests_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, state.ICQInterests) error) *mockICQUserUpdater_SetInterests_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// SetMoreInfo provides a mock function with given fields: name, data
-func (_m *mockICQUserUpdater) SetMoreInfo(name state.IdentScreenName, data state.ICQMoreInfo) error {
-	ret := _m.Called(name, data)
+// SetMoreInfo provides a mock function with given fields: ctx, name, data
+func (_m *mockICQUserUpdater) SetMoreInfo(ctx context.Context, name state.IdentScreenName, data state.ICQMoreInfo) error {
+	ret := _m.Called(ctx, name, data)
 
 	if len(ret) == 0 {
 		panic("no return value specified for SetMoreInfo")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.ICQMoreInfo) error); ok {
-		r0 = rf(name, data)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, state.ICQMoreInfo) error); ok {
+		r0 = rf(ctx, name, data)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -185,15 +190,16 @@ type mockICQUserUpdater_SetMoreInfo_Call struct {
 }
 
 // SetMoreInfo is a helper method to define mock.On call
+//   - ctx context.Context
 //   - name state.IdentScreenName
 //   - data state.ICQMoreInfo
-func (_e *mockICQUserUpdater_Expecter) SetMoreInfo(name interface{}, data interface{}) *mockICQUserUpdater_SetMoreInfo_Call {
-	return &mockICQUserUpdater_SetMoreInfo_Call{Call: _e.mock.On("SetMoreInfo", name, data)}
+func (_e *mockICQUserUpdater_Expecter) SetMoreInfo(ctx interface{}, name interface{}, data interface{}) *mockICQUserUpdater_SetMoreInfo_Call {
+	return &mockICQUserUpdater_SetMoreInfo_Call{Call: _e.mock.On("SetMoreInfo", ctx, name, data)}
 }
 
-func (_c *mockICQUserUpdater_SetMoreInfo_Call) Run(run func(name state.IdentScreenName, data state.ICQMoreInfo)) *mockICQUserUpdater_SetMoreInfo_Call {
+func (_c *mockICQUserUpdater_SetMoreInfo_Call) Run(run func(ctx context.Context, name state.IdentScreenName, data state.ICQMoreInfo)) *mockICQUserUpdater_SetMoreInfo_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(state.ICQMoreInfo))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(state.ICQMoreInfo))
 	})
 	return _c
 }
@@ -203,22 +209,22 @@ func (_c *mockICQUserUpdater_SetMoreInfo_Call) Return(_a0 error) *mockICQUserUpd
 	return _c
 }
 
-func (_c *mockICQUserUpdater_SetMoreInfo_Call) RunAndReturn(run func(state.IdentScreenName, state.ICQMoreInfo) error) *mockICQUserUpdater_SetMoreInfo_Call {
+func (_c *mockICQUserUpdater_SetMoreInfo_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, state.ICQMoreInfo) error) *mockICQUserUpdater_SetMoreInfo_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// SetUserNotes provides a mock function with given fields: name, data
-func (_m *mockICQUserUpdater) SetUserNotes(name state.IdentScreenName, data state.ICQUserNotes) error {
-	ret := _m.Called(name, data)
+// SetUserNotes provides a mock function with given fields: ctx, name, data
+func (_m *mockICQUserUpdater) SetUserNotes(ctx context.Context, name state.IdentScreenName, data state.ICQUserNotes) error {
+	ret := _m.Called(ctx, name, data)
 
 	if len(ret) == 0 {
 		panic("no return value specified for SetUserNotes")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.ICQUserNotes) error); ok {
-		r0 = rf(name, data)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, state.ICQUserNotes) error); ok {
+		r0 = rf(ctx, name, data)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -232,15 +238,16 @@ type mockICQUserUpdater_SetUserNotes_Call struct {
 }
 
 // SetUserNotes is a helper method to define mock.On call
+//   - ctx context.Context
 //   - name state.IdentScreenName
 //   - data state.ICQUserNotes
-func (_e *mockICQUserUpdater_Expecter) SetUserNotes(name interface{}, data interface{}) *mockICQUserUpdater_SetUserNotes_Call {
-	return &mockICQUserUpdater_SetUserNotes_Call{Call: _e.mock.On("SetUserNotes", name, data)}
+func (_e *mockICQUserUpdater_Expecter) SetUserNotes(ctx interface{}, name interface{}, data interface{}) *mockICQUserUpdater_SetUserNotes_Call {
+	return &mockICQUserUpdater_SetUserNotes_Call{Call: _e.mock.On("SetUserNotes", ctx, name, data)}
 }
 
-func (_c *mockICQUserUpdater_SetUserNotes_Call) Run(run func(name state.IdentScreenName, data state.ICQUserNotes)) *mockICQUserUpdater_SetUserNotes_Call {
+func (_c *mockICQUserUpdater_SetUserNotes_Call) Run(run func(ctx context.Context, name state.IdentScreenName, data state.ICQUserNotes)) *mockICQUserUpdater_SetUserNotes_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(state.ICQUserNotes))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(state.ICQUserNotes))
 	})
 	return _c
 }
@@ -250,22 +257,22 @@ func (_c *mockICQUserUpdater_SetUserNotes_Call) Return(_a0 error) *mockICQUserUp
 	return _c
 }
 
-func (_c *mockICQUserUpdater_SetUserNotes_Call) RunAndReturn(run func(state.IdentScreenName, state.ICQUserNotes) error) *mockICQUserUpdater_SetUserNotes_Call {
+func (_c *mockICQUserUpdater_SetUserNotes_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, state.ICQUserNotes) error) *mockICQUserUpdater_SetUserNotes_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// SetWorkInfo provides a mock function with given fields: name, data
-func (_m *mockICQUserUpdater) SetWorkInfo(name state.IdentScreenName, data state.ICQWorkInfo) error {
-	ret := _m.Called(name, data)
+// SetWorkInfo provides a mock function with given fields: ctx, name, data
+func (_m *mockICQUserUpdater) SetWorkInfo(ctx context.Context, name state.IdentScreenName, data state.ICQWorkInfo) error {
+	ret := _m.Called(ctx, name, data)
 
 	if len(ret) == 0 {
 		panic("no return value specified for SetWorkInfo")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.ICQWorkInfo) error); ok {
-		r0 = rf(name, data)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, state.ICQWorkInfo) error); ok {
+		r0 = rf(ctx, name, data)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -279,15 +286,16 @@ type mockICQUserUpdater_SetWorkInfo_Call struct {
 }
 
 // SetWorkInfo is a helper method to define mock.On call
+//   - ctx context.Context
 //   - name state.IdentScreenName
 //   - data state.ICQWorkInfo
-func (_e *mockICQUserUpdater_Expecter) SetWorkInfo(name interface{}, data interface{}) *mockICQUserUpdater_SetWorkInfo_Call {
-	return &mockICQUserUpdater_SetWorkInfo_Call{Call: _e.mock.On("SetWorkInfo", name, data)}
+func (_e *mockICQUserUpdater_Expecter) SetWorkInfo(ctx interface{}, name interface{}, data interface{}) *mockICQUserUpdater_SetWorkInfo_Call {
+	return &mockICQUserUpdater_SetWorkInfo_Call{Call: _e.mock.On("SetWorkInfo", ctx, name, data)}
 }
 
-func (_c *mockICQUserUpdater_SetWorkInfo_Call) Run(run func(name state.IdentScreenName, data state.ICQWorkInfo)) *mockICQUserUpdater_SetWorkInfo_Call {
+func (_c *mockICQUserUpdater_SetWorkInfo_Call) Run(run func(ctx context.Context, name state.IdentScreenName, data state.ICQWorkInfo)) *mockICQUserUpdater_SetWorkInfo_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(state.ICQWorkInfo))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(state.ICQWorkInfo))
 	})
 	return _c
 }
@@ -297,7 +305,7 @@ func (_c *mockICQUserUpdater_SetWorkInfo_Call) Return(_a0 error) *mockICQUserUpd
 	return _c
 }
 
-func (_c *mockICQUserUpdater_SetWorkInfo_Call) RunAndReturn(run func(state.IdentScreenName, state.ICQWorkInfo) error) *mockICQUserUpdater_SetWorkInfo_Call {
+func (_c *mockICQUserUpdater_SetWorkInfo_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, state.ICQWorkInfo) error) *mockICQUserUpdater_SetWorkInfo_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 0 - 366
foodgroup/mock_local_buddy_list_manager_test.go

@@ -1,366 +0,0 @@
-// Code generated by mockery v2.52.1. DO NOT EDIT.
-
-package foodgroup
-
-import (
-	state "github.com/mk6i/retro-aim-server/state"
-	mock "github.com/stretchr/testify/mock"
-
-	wire "github.com/mk6i/retro-aim-server/wire"
-)
-
-// mockLocalBuddyListManager is an autogenerated mock type for the LocalBuddyListManager type
-type mockLocalBuddyListManager struct {
-	mock.Mock
-}
-
-type mockLocalBuddyListManager_Expecter struct {
-	mock *mock.Mock
-}
-
-func (_m *mockLocalBuddyListManager) EXPECT() *mockLocalBuddyListManager_Expecter {
-	return &mockLocalBuddyListManager_Expecter{mock: &_m.Mock}
-}
-
-// AddBuddy provides a mock function with given fields: me, them
-func (_m *mockLocalBuddyListManager) AddBuddy(me state.IdentScreenName, them state.IdentScreenName) error {
-	ret := _m.Called(me, them)
-
-	if len(ret) == 0 {
-		panic("no return value specified for AddBuddy")
-	}
-
-	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.IdentScreenName) error); ok {
-		r0 = rf(me, them)
-	} else {
-		r0 = ret.Error(0)
-	}
-
-	return r0
-}
-
-// mockLocalBuddyListManager_AddBuddy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddBuddy'
-type mockLocalBuddyListManager_AddBuddy_Call struct {
-	*mock.Call
-}
-
-// AddBuddy is a helper method to define mock.On call
-//   - me state.IdentScreenName
-//   - them state.IdentScreenName
-func (_e *mockLocalBuddyListManager_Expecter) AddBuddy(me interface{}, them interface{}) *mockLocalBuddyListManager_AddBuddy_Call {
-	return &mockLocalBuddyListManager_AddBuddy_Call{Call: _e.mock.On("AddBuddy", me, them)}
-}
-
-func (_c *mockLocalBuddyListManager_AddBuddy_Call) Run(run func(me state.IdentScreenName, them state.IdentScreenName)) *mockLocalBuddyListManager_AddBuddy_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(state.IdentScreenName))
-	})
-	return _c
-}
-
-func (_c *mockLocalBuddyListManager_AddBuddy_Call) Return(_a0 error) *mockLocalBuddyListManager_AddBuddy_Call {
-	_c.Call.Return(_a0)
-	return _c
-}
-
-func (_c *mockLocalBuddyListManager_AddBuddy_Call) RunAndReturn(run func(state.IdentScreenName, state.IdentScreenName) error) *mockLocalBuddyListManager_AddBuddy_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// DenyBuddy provides a mock function with given fields: me, them
-func (_m *mockLocalBuddyListManager) DenyBuddy(me state.IdentScreenName, them state.IdentScreenName) error {
-	ret := _m.Called(me, them)
-
-	if len(ret) == 0 {
-		panic("no return value specified for DenyBuddy")
-	}
-
-	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.IdentScreenName) error); ok {
-		r0 = rf(me, them)
-	} else {
-		r0 = ret.Error(0)
-	}
-
-	return r0
-}
-
-// mockLocalBuddyListManager_DenyBuddy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DenyBuddy'
-type mockLocalBuddyListManager_DenyBuddy_Call struct {
-	*mock.Call
-}
-
-// DenyBuddy is a helper method to define mock.On call
-//   - me state.IdentScreenName
-//   - them state.IdentScreenName
-func (_e *mockLocalBuddyListManager_Expecter) DenyBuddy(me interface{}, them interface{}) *mockLocalBuddyListManager_DenyBuddy_Call {
-	return &mockLocalBuddyListManager_DenyBuddy_Call{Call: _e.mock.On("DenyBuddy", me, them)}
-}
-
-func (_c *mockLocalBuddyListManager_DenyBuddy_Call) Run(run func(me state.IdentScreenName, them state.IdentScreenName)) *mockLocalBuddyListManager_DenyBuddy_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(state.IdentScreenName))
-	})
-	return _c
-}
-
-func (_c *mockLocalBuddyListManager_DenyBuddy_Call) Return(_a0 error) *mockLocalBuddyListManager_DenyBuddy_Call {
-	_c.Call.Return(_a0)
-	return _c
-}
-
-func (_c *mockLocalBuddyListManager_DenyBuddy_Call) RunAndReturn(run func(state.IdentScreenName, state.IdentScreenName) error) *mockLocalBuddyListManager_DenyBuddy_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// PermitBuddy provides a mock function with given fields: me, them
-func (_m *mockLocalBuddyListManager) PermitBuddy(me state.IdentScreenName, them state.IdentScreenName) error {
-	ret := _m.Called(me, them)
-
-	if len(ret) == 0 {
-		panic("no return value specified for PermitBuddy")
-	}
-
-	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.IdentScreenName) error); ok {
-		r0 = rf(me, them)
-	} else {
-		r0 = ret.Error(0)
-	}
-
-	return r0
-}
-
-// mockLocalBuddyListManager_PermitBuddy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PermitBuddy'
-type mockLocalBuddyListManager_PermitBuddy_Call struct {
-	*mock.Call
-}
-
-// PermitBuddy is a helper method to define mock.On call
-//   - me state.IdentScreenName
-//   - them state.IdentScreenName
-func (_e *mockLocalBuddyListManager_Expecter) PermitBuddy(me interface{}, them interface{}) *mockLocalBuddyListManager_PermitBuddy_Call {
-	return &mockLocalBuddyListManager_PermitBuddy_Call{Call: _e.mock.On("PermitBuddy", me, them)}
-}
-
-func (_c *mockLocalBuddyListManager_PermitBuddy_Call) Run(run func(me state.IdentScreenName, them state.IdentScreenName)) *mockLocalBuddyListManager_PermitBuddy_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(state.IdentScreenName))
-	})
-	return _c
-}
-
-func (_c *mockLocalBuddyListManager_PermitBuddy_Call) Return(_a0 error) *mockLocalBuddyListManager_PermitBuddy_Call {
-	_c.Call.Return(_a0)
-	return _c
-}
-
-func (_c *mockLocalBuddyListManager_PermitBuddy_Call) RunAndReturn(run func(state.IdentScreenName, state.IdentScreenName) error) *mockLocalBuddyListManager_PermitBuddy_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// RemoveBuddy provides a mock function with given fields: me, them
-func (_m *mockLocalBuddyListManager) RemoveBuddy(me state.IdentScreenName, them state.IdentScreenName) error {
-	ret := _m.Called(me, them)
-
-	if len(ret) == 0 {
-		panic("no return value specified for RemoveBuddy")
-	}
-
-	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.IdentScreenName) error); ok {
-		r0 = rf(me, them)
-	} else {
-		r0 = ret.Error(0)
-	}
-
-	return r0
-}
-
-// mockLocalBuddyListManager_RemoveBuddy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveBuddy'
-type mockLocalBuddyListManager_RemoveBuddy_Call struct {
-	*mock.Call
-}
-
-// RemoveBuddy is a helper method to define mock.On call
-//   - me state.IdentScreenName
-//   - them state.IdentScreenName
-func (_e *mockLocalBuddyListManager_Expecter) RemoveBuddy(me interface{}, them interface{}) *mockLocalBuddyListManager_RemoveBuddy_Call {
-	return &mockLocalBuddyListManager_RemoveBuddy_Call{Call: _e.mock.On("RemoveBuddy", me, them)}
-}
-
-func (_c *mockLocalBuddyListManager_RemoveBuddy_Call) Run(run func(me state.IdentScreenName, them state.IdentScreenName)) *mockLocalBuddyListManager_RemoveBuddy_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(state.IdentScreenName))
-	})
-	return _c
-}
-
-func (_c *mockLocalBuddyListManager_RemoveBuddy_Call) Return(_a0 error) *mockLocalBuddyListManager_RemoveBuddy_Call {
-	_c.Call.Return(_a0)
-	return _c
-}
-
-func (_c *mockLocalBuddyListManager_RemoveBuddy_Call) RunAndReturn(run func(state.IdentScreenName, state.IdentScreenName) error) *mockLocalBuddyListManager_RemoveBuddy_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// RemoveDenyBuddy provides a mock function with given fields: me, them
-func (_m *mockLocalBuddyListManager) RemoveDenyBuddy(me state.IdentScreenName, them state.IdentScreenName) error {
-	ret := _m.Called(me, them)
-
-	if len(ret) == 0 {
-		panic("no return value specified for RemoveDenyBuddy")
-	}
-
-	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.IdentScreenName) error); ok {
-		r0 = rf(me, them)
-	} else {
-		r0 = ret.Error(0)
-	}
-
-	return r0
-}
-
-// mockLocalBuddyListManager_RemoveDenyBuddy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveDenyBuddy'
-type mockLocalBuddyListManager_RemoveDenyBuddy_Call struct {
-	*mock.Call
-}
-
-// RemoveDenyBuddy is a helper method to define mock.On call
-//   - me state.IdentScreenName
-//   - them state.IdentScreenName
-func (_e *mockLocalBuddyListManager_Expecter) RemoveDenyBuddy(me interface{}, them interface{}) *mockLocalBuddyListManager_RemoveDenyBuddy_Call {
-	return &mockLocalBuddyListManager_RemoveDenyBuddy_Call{Call: _e.mock.On("RemoveDenyBuddy", me, them)}
-}
-
-func (_c *mockLocalBuddyListManager_RemoveDenyBuddy_Call) Run(run func(me state.IdentScreenName, them state.IdentScreenName)) *mockLocalBuddyListManager_RemoveDenyBuddy_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(state.IdentScreenName))
-	})
-	return _c
-}
-
-func (_c *mockLocalBuddyListManager_RemoveDenyBuddy_Call) Return(_a0 error) *mockLocalBuddyListManager_RemoveDenyBuddy_Call {
-	_c.Call.Return(_a0)
-	return _c
-}
-
-func (_c *mockLocalBuddyListManager_RemoveDenyBuddy_Call) RunAndReturn(run func(state.IdentScreenName, state.IdentScreenName) error) *mockLocalBuddyListManager_RemoveDenyBuddy_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// RemovePermitBuddy provides a mock function with given fields: me, them
-func (_m *mockLocalBuddyListManager) RemovePermitBuddy(me state.IdentScreenName, them state.IdentScreenName) error {
-	ret := _m.Called(me, them)
-
-	if len(ret) == 0 {
-		panic("no return value specified for RemovePermitBuddy")
-	}
-
-	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.IdentScreenName) error); ok {
-		r0 = rf(me, them)
-	} else {
-		r0 = ret.Error(0)
-	}
-
-	return r0
-}
-
-// mockLocalBuddyListManager_RemovePermitBuddy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemovePermitBuddy'
-type mockLocalBuddyListManager_RemovePermitBuddy_Call struct {
-	*mock.Call
-}
-
-// RemovePermitBuddy is a helper method to define mock.On call
-//   - me state.IdentScreenName
-//   - them state.IdentScreenName
-func (_e *mockLocalBuddyListManager_Expecter) RemovePermitBuddy(me interface{}, them interface{}) *mockLocalBuddyListManager_RemovePermitBuddy_Call {
-	return &mockLocalBuddyListManager_RemovePermitBuddy_Call{Call: _e.mock.On("RemovePermitBuddy", me, them)}
-}
-
-func (_c *mockLocalBuddyListManager_RemovePermitBuddy_Call) Run(run func(me state.IdentScreenName, them state.IdentScreenName)) *mockLocalBuddyListManager_RemovePermitBuddy_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(state.IdentScreenName))
-	})
-	return _c
-}
-
-func (_c *mockLocalBuddyListManager_RemovePermitBuddy_Call) Return(_a0 error) *mockLocalBuddyListManager_RemovePermitBuddy_Call {
-	_c.Call.Return(_a0)
-	return _c
-}
-
-func (_c *mockLocalBuddyListManager_RemovePermitBuddy_Call) RunAndReturn(run func(state.IdentScreenName, state.IdentScreenName) error) *mockLocalBuddyListManager_RemovePermitBuddy_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// SetPDMode provides a mock function with given fields: user, pdMode
-func (_m *mockLocalBuddyListManager) SetPDMode(user state.IdentScreenName, pdMode wire.FeedbagPDMode) error {
-	ret := _m.Called(user, pdMode)
-
-	if len(ret) == 0 {
-		panic("no return value specified for SetPDMode")
-	}
-
-	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, wire.FeedbagPDMode) error); ok {
-		r0 = rf(user, pdMode)
-	} else {
-		r0 = ret.Error(0)
-	}
-
-	return r0
-}
-
-// mockLocalBuddyListManager_SetPDMode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPDMode'
-type mockLocalBuddyListManager_SetPDMode_Call struct {
-	*mock.Call
-}
-
-// SetPDMode is a helper method to define mock.On call
-//   - user state.IdentScreenName
-//   - pdMode wire.FeedbagPDMode
-func (_e *mockLocalBuddyListManager_Expecter) SetPDMode(user interface{}, pdMode interface{}) *mockLocalBuddyListManager_SetPDMode_Call {
-	return &mockLocalBuddyListManager_SetPDMode_Call{Call: _e.mock.On("SetPDMode", user, pdMode)}
-}
-
-func (_c *mockLocalBuddyListManager_SetPDMode_Call) Run(run func(user state.IdentScreenName, pdMode wire.FeedbagPDMode)) *mockLocalBuddyListManager_SetPDMode_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(wire.FeedbagPDMode))
-	})
-	return _c
-}
-
-func (_c *mockLocalBuddyListManager_SetPDMode_Call) Return(_a0 error) *mockLocalBuddyListManager_SetPDMode_Call {
-	_c.Call.Return(_a0)
-	return _c
-}
-
-func (_c *mockLocalBuddyListManager_SetPDMode_Call) RunAndReturn(run func(state.IdentScreenName, wire.FeedbagPDMode) error) *mockLocalBuddyListManager_SetPDMode_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// newMockLocalBuddyListManager creates a new instance of mockLocalBuddyListManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func newMockLocalBuddyListManager(t interface {
-	mock.TestingT
-	Cleanup(func())
-}) *mockLocalBuddyListManager {
-	mock := &mockLocalBuddyListManager{}
-	mock.Mock.Test(t)
-
-	t.Cleanup(func() { mock.AssertExpectations(t) })
-
-	return mock
-}

+ 39 - 34
foodgroup/mock_offline_message_manager_test.go

@@ -3,6 +3,8 @@
 package foodgroup
 
 import (
+	context "context"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 )
@@ -20,17 +22,17 @@ func (_m *mockOfflineMessageManager) EXPECT() *mockOfflineMessageManager_Expecte
 	return &mockOfflineMessageManager_Expecter{mock: &_m.Mock}
 }
 
-// DeleteMessages provides a mock function with given fields: recip
-func (_m *mockOfflineMessageManager) DeleteMessages(recip state.IdentScreenName) error {
-	ret := _m.Called(recip)
+// DeleteMessages provides a mock function with given fields: ctx, recip
+func (_m *mockOfflineMessageManager) DeleteMessages(ctx context.Context, recip state.IdentScreenName) error {
+	ret := _m.Called(ctx, recip)
 
 	if len(ret) == 0 {
 		panic("no return value specified for DeleteMessages")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) error); ok {
-		r0 = rf(recip)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) error); ok {
+		r0 = rf(ctx, recip)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -44,14 +46,15 @@ type mockOfflineMessageManager_DeleteMessages_Call struct {
 }
 
 // DeleteMessages is a helper method to define mock.On call
+//   - ctx context.Context
 //   - recip state.IdentScreenName
-func (_e *mockOfflineMessageManager_Expecter) DeleteMessages(recip interface{}) *mockOfflineMessageManager_DeleteMessages_Call {
-	return &mockOfflineMessageManager_DeleteMessages_Call{Call: _e.mock.On("DeleteMessages", recip)}
+func (_e *mockOfflineMessageManager_Expecter) DeleteMessages(ctx interface{}, recip interface{}) *mockOfflineMessageManager_DeleteMessages_Call {
+	return &mockOfflineMessageManager_DeleteMessages_Call{Call: _e.mock.On("DeleteMessages", ctx, recip)}
 }
 
-func (_c *mockOfflineMessageManager_DeleteMessages_Call) Run(run func(recip state.IdentScreenName)) *mockOfflineMessageManager_DeleteMessages_Call {
+func (_c *mockOfflineMessageManager_DeleteMessages_Call) Run(run func(ctx context.Context, recip state.IdentScreenName)) *mockOfflineMessageManager_DeleteMessages_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
@@ -61,14 +64,14 @@ func (_c *mockOfflineMessageManager_DeleteMessages_Call) Return(_a0 error) *mock
 	return _c
 }
 
-func (_c *mockOfflineMessageManager_DeleteMessages_Call) RunAndReturn(run func(state.IdentScreenName) error) *mockOfflineMessageManager_DeleteMessages_Call {
+func (_c *mockOfflineMessageManager_DeleteMessages_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) error) *mockOfflineMessageManager_DeleteMessages_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// RetrieveMessages provides a mock function with given fields: recip
-func (_m *mockOfflineMessageManager) RetrieveMessages(recip state.IdentScreenName) ([]state.OfflineMessage, error) {
-	ret := _m.Called(recip)
+// RetrieveMessages provides a mock function with given fields: ctx, recip
+func (_m *mockOfflineMessageManager) RetrieveMessages(ctx context.Context, recip state.IdentScreenName) ([]state.OfflineMessage, error) {
+	ret := _m.Called(ctx, recip)
 
 	if len(ret) == 0 {
 		panic("no return value specified for RetrieveMessages")
@@ -76,19 +79,19 @@ func (_m *mockOfflineMessageManager) RetrieveMessages(recip state.IdentScreenNam
 
 	var r0 []state.OfflineMessage
 	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) ([]state.OfflineMessage, error)); ok {
-		return rf(recip)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) ([]state.OfflineMessage, error)); ok {
+		return rf(ctx, recip)
 	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) []state.OfflineMessage); ok {
-		r0 = rf(recip)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) []state.OfflineMessage); ok {
+		r0 = rf(ctx, recip)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).([]state.OfflineMessage)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(recip)
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, recip)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -102,14 +105,15 @@ type mockOfflineMessageManager_RetrieveMessages_Call struct {
 }
 
 // RetrieveMessages is a helper method to define mock.On call
+//   - ctx context.Context
 //   - recip state.IdentScreenName
-func (_e *mockOfflineMessageManager_Expecter) RetrieveMessages(recip interface{}) *mockOfflineMessageManager_RetrieveMessages_Call {
-	return &mockOfflineMessageManager_RetrieveMessages_Call{Call: _e.mock.On("RetrieveMessages", recip)}
+func (_e *mockOfflineMessageManager_Expecter) RetrieveMessages(ctx interface{}, recip interface{}) *mockOfflineMessageManager_RetrieveMessages_Call {
+	return &mockOfflineMessageManager_RetrieveMessages_Call{Call: _e.mock.On("RetrieveMessages", ctx, recip)}
 }
 
-func (_c *mockOfflineMessageManager_RetrieveMessages_Call) Run(run func(recip state.IdentScreenName)) *mockOfflineMessageManager_RetrieveMessages_Call {
+func (_c *mockOfflineMessageManager_RetrieveMessages_Call) Run(run func(ctx context.Context, recip state.IdentScreenName)) *mockOfflineMessageManager_RetrieveMessages_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
@@ -119,22 +123,22 @@ func (_c *mockOfflineMessageManager_RetrieveMessages_Call) Return(_a0 []state.Of
 	return _c
 }
 
-func (_c *mockOfflineMessageManager_RetrieveMessages_Call) RunAndReturn(run func(state.IdentScreenName) ([]state.OfflineMessage, error)) *mockOfflineMessageManager_RetrieveMessages_Call {
+func (_c *mockOfflineMessageManager_RetrieveMessages_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) ([]state.OfflineMessage, error)) *mockOfflineMessageManager_RetrieveMessages_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// SaveMessage provides a mock function with given fields: offlineMessage
-func (_m *mockOfflineMessageManager) SaveMessage(offlineMessage state.OfflineMessage) error {
-	ret := _m.Called(offlineMessage)
+// SaveMessage provides a mock function with given fields: ctx, offlineMessage
+func (_m *mockOfflineMessageManager) SaveMessage(ctx context.Context, offlineMessage state.OfflineMessage) error {
+	ret := _m.Called(ctx, offlineMessage)
 
 	if len(ret) == 0 {
 		panic("no return value specified for SaveMessage")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.OfflineMessage) error); ok {
-		r0 = rf(offlineMessage)
+	if rf, ok := ret.Get(0).(func(context.Context, state.OfflineMessage) error); ok {
+		r0 = rf(ctx, offlineMessage)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -148,14 +152,15 @@ type mockOfflineMessageManager_SaveMessage_Call struct {
 }
 
 // SaveMessage is a helper method to define mock.On call
+//   - ctx context.Context
 //   - offlineMessage state.OfflineMessage
-func (_e *mockOfflineMessageManager_Expecter) SaveMessage(offlineMessage interface{}) *mockOfflineMessageManager_SaveMessage_Call {
-	return &mockOfflineMessageManager_SaveMessage_Call{Call: _e.mock.On("SaveMessage", offlineMessage)}
+func (_e *mockOfflineMessageManager_Expecter) SaveMessage(ctx interface{}, offlineMessage interface{}) *mockOfflineMessageManager_SaveMessage_Call {
+	return &mockOfflineMessageManager_SaveMessage_Call{Call: _e.mock.On("SaveMessage", ctx, offlineMessage)}
 }
 
-func (_c *mockOfflineMessageManager_SaveMessage_Call) Run(run func(offlineMessage state.OfflineMessage)) *mockOfflineMessageManager_SaveMessage_Call {
+func (_c *mockOfflineMessageManager_SaveMessage_Call) Run(run func(ctx context.Context, offlineMessage state.OfflineMessage)) *mockOfflineMessageManager_SaveMessage_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.OfflineMessage))
+		run(args[0].(context.Context), args[1].(state.OfflineMessage))
 	})
 	return _c
 }
@@ -165,7 +170,7 @@ func (_c *mockOfflineMessageManager_SaveMessage_Call) Return(_a0 error) *mockOff
 	return _c
 }
 
-func (_c *mockOfflineMessageManager_SaveMessage_Call) RunAndReturn(run func(state.OfflineMessage) error) *mockOfflineMessageManager_SaveMessage_Call {
+func (_c *mockOfflineMessageManager_SaveMessage_Call) RunAndReturn(run func(context.Context, state.OfflineMessage) error) *mockOfflineMessageManager_SaveMessage_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 127 - 116
foodgroup/mock_profile_manager_test.go

@@ -3,6 +3,8 @@
 package foodgroup
 
 import (
+	context "context"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 
@@ -22,9 +24,9 @@ func (_m *mockProfileManager) EXPECT() *mockProfileManager_Expecter {
 	return &mockProfileManager_Expecter{mock: &_m.Mock}
 }
 
-// FindByAIMEmail provides a mock function with given fields: email
-func (_m *mockProfileManager) FindByAIMEmail(email string) (state.User, error) {
-	ret := _m.Called(email)
+// FindByAIMEmail provides a mock function with given fields: ctx, email
+func (_m *mockProfileManager) FindByAIMEmail(ctx context.Context, email string) (state.User, error) {
+	ret := _m.Called(ctx, email)
 
 	if len(ret) == 0 {
 		panic("no return value specified for FindByAIMEmail")
@@ -32,17 +34,17 @@ func (_m *mockProfileManager) FindByAIMEmail(email string) (state.User, error) {
 
 	var r0 state.User
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string) (state.User, error)); ok {
-		return rf(email)
+	if rf, ok := ret.Get(0).(func(context.Context, string) (state.User, error)); ok {
+		return rf(ctx, email)
 	}
-	if rf, ok := ret.Get(0).(func(string) state.User); ok {
-		r0 = rf(email)
+	if rf, ok := ret.Get(0).(func(context.Context, string) state.User); ok {
+		r0 = rf(ctx, email)
 	} else {
 		r0 = ret.Get(0).(state.User)
 	}
 
-	if rf, ok := ret.Get(1).(func(string) error); ok {
-		r1 = rf(email)
+	if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
+		r1 = rf(ctx, email)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -56,14 +58,15 @@ type mockProfileManager_FindByAIMEmail_Call struct {
 }
 
 // FindByAIMEmail is a helper method to define mock.On call
+//   - ctx context.Context
 //   - email string
-func (_e *mockProfileManager_Expecter) FindByAIMEmail(email interface{}) *mockProfileManager_FindByAIMEmail_Call {
-	return &mockProfileManager_FindByAIMEmail_Call{Call: _e.mock.On("FindByAIMEmail", email)}
+func (_e *mockProfileManager_Expecter) FindByAIMEmail(ctx interface{}, email interface{}) *mockProfileManager_FindByAIMEmail_Call {
+	return &mockProfileManager_FindByAIMEmail_Call{Call: _e.mock.On("FindByAIMEmail", ctx, email)}
 }
 
-func (_c *mockProfileManager_FindByAIMEmail_Call) Run(run func(email string)) *mockProfileManager_FindByAIMEmail_Call {
+func (_c *mockProfileManager_FindByAIMEmail_Call) Run(run func(ctx context.Context, email string)) *mockProfileManager_FindByAIMEmail_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(context.Context), args[1].(string))
 	})
 	return _c
 }
@@ -73,14 +76,14 @@ func (_c *mockProfileManager_FindByAIMEmail_Call) Return(_a0 state.User, _a1 err
 	return _c
 }
 
-func (_c *mockProfileManager_FindByAIMEmail_Call) RunAndReturn(run func(string) (state.User, error)) *mockProfileManager_FindByAIMEmail_Call {
+func (_c *mockProfileManager_FindByAIMEmail_Call) RunAndReturn(run func(context.Context, string) (state.User, error)) *mockProfileManager_FindByAIMEmail_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// FindByAIMKeyword provides a mock function with given fields: keyword
-func (_m *mockProfileManager) FindByAIMKeyword(keyword string) ([]state.User, error) {
-	ret := _m.Called(keyword)
+// FindByAIMKeyword provides a mock function with given fields: ctx, keyword
+func (_m *mockProfileManager) FindByAIMKeyword(ctx context.Context, keyword string) ([]state.User, error) {
+	ret := _m.Called(ctx, keyword)
 
 	if len(ret) == 0 {
 		panic("no return value specified for FindByAIMKeyword")
@@ -88,19 +91,19 @@ func (_m *mockProfileManager) FindByAIMKeyword(keyword string) ([]state.User, er
 
 	var r0 []state.User
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string) ([]state.User, error)); ok {
-		return rf(keyword)
+	if rf, ok := ret.Get(0).(func(context.Context, string) ([]state.User, error)); ok {
+		return rf(ctx, keyword)
 	}
-	if rf, ok := ret.Get(0).(func(string) []state.User); ok {
-		r0 = rf(keyword)
+	if rf, ok := ret.Get(0).(func(context.Context, string) []state.User); ok {
+		r0 = rf(ctx, keyword)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).([]state.User)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(string) error); ok {
-		r1 = rf(keyword)
+	if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
+		r1 = rf(ctx, keyword)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -114,14 +117,15 @@ type mockProfileManager_FindByAIMKeyword_Call struct {
 }
 
 // FindByAIMKeyword is a helper method to define mock.On call
+//   - ctx context.Context
 //   - keyword string
-func (_e *mockProfileManager_Expecter) FindByAIMKeyword(keyword interface{}) *mockProfileManager_FindByAIMKeyword_Call {
-	return &mockProfileManager_FindByAIMKeyword_Call{Call: _e.mock.On("FindByAIMKeyword", keyword)}
+func (_e *mockProfileManager_Expecter) FindByAIMKeyword(ctx interface{}, keyword interface{}) *mockProfileManager_FindByAIMKeyword_Call {
+	return &mockProfileManager_FindByAIMKeyword_Call{Call: _e.mock.On("FindByAIMKeyword", ctx, keyword)}
 }
 
-func (_c *mockProfileManager_FindByAIMKeyword_Call) Run(run func(keyword string)) *mockProfileManager_FindByAIMKeyword_Call {
+func (_c *mockProfileManager_FindByAIMKeyword_Call) Run(run func(ctx context.Context, keyword string)) *mockProfileManager_FindByAIMKeyword_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(context.Context), args[1].(string))
 	})
 	return _c
 }
@@ -131,14 +135,14 @@ func (_c *mockProfileManager_FindByAIMKeyword_Call) Return(_a0 []state.User, _a1
 	return _c
 }
 
-func (_c *mockProfileManager_FindByAIMKeyword_Call) RunAndReturn(run func(string) ([]state.User, error)) *mockProfileManager_FindByAIMKeyword_Call {
+func (_c *mockProfileManager_FindByAIMKeyword_Call) RunAndReturn(run func(context.Context, string) ([]state.User, error)) *mockProfileManager_FindByAIMKeyword_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// FindByAIMNameAndAddr provides a mock function with given fields: info
-func (_m *mockProfileManager) FindByAIMNameAndAddr(info state.AIMNameAndAddr) ([]state.User, error) {
-	ret := _m.Called(info)
+// FindByAIMNameAndAddr provides a mock function with given fields: ctx, info
+func (_m *mockProfileManager) FindByAIMNameAndAddr(ctx context.Context, info state.AIMNameAndAddr) ([]state.User, error) {
+	ret := _m.Called(ctx, info)
 
 	if len(ret) == 0 {
 		panic("no return value specified for FindByAIMNameAndAddr")
@@ -146,19 +150,19 @@ func (_m *mockProfileManager) FindByAIMNameAndAddr(info state.AIMNameAndAddr) ([
 
 	var r0 []state.User
 	var r1 error
-	if rf, ok := ret.Get(0).(func(state.AIMNameAndAddr) ([]state.User, error)); ok {
-		return rf(info)
+	if rf, ok := ret.Get(0).(func(context.Context, state.AIMNameAndAddr) ([]state.User, error)); ok {
+		return rf(ctx, info)
 	}
-	if rf, ok := ret.Get(0).(func(state.AIMNameAndAddr) []state.User); ok {
-		r0 = rf(info)
+	if rf, ok := ret.Get(0).(func(context.Context, state.AIMNameAndAddr) []state.User); ok {
+		r0 = rf(ctx, info)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).([]state.User)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(state.AIMNameAndAddr) error); ok {
-		r1 = rf(info)
+	if rf, ok := ret.Get(1).(func(context.Context, state.AIMNameAndAddr) error); ok {
+		r1 = rf(ctx, info)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -172,14 +176,15 @@ type mockProfileManager_FindByAIMNameAndAddr_Call struct {
 }
 
 // FindByAIMNameAndAddr is a helper method to define mock.On call
+//   - ctx context.Context
 //   - info state.AIMNameAndAddr
-func (_e *mockProfileManager_Expecter) FindByAIMNameAndAddr(info interface{}) *mockProfileManager_FindByAIMNameAndAddr_Call {
-	return &mockProfileManager_FindByAIMNameAndAddr_Call{Call: _e.mock.On("FindByAIMNameAndAddr", info)}
+func (_e *mockProfileManager_Expecter) FindByAIMNameAndAddr(ctx interface{}, info interface{}) *mockProfileManager_FindByAIMNameAndAddr_Call {
+	return &mockProfileManager_FindByAIMNameAndAddr_Call{Call: _e.mock.On("FindByAIMNameAndAddr", ctx, info)}
 }
 
-func (_c *mockProfileManager_FindByAIMNameAndAddr_Call) Run(run func(info state.AIMNameAndAddr)) *mockProfileManager_FindByAIMNameAndAddr_Call {
+func (_c *mockProfileManager_FindByAIMNameAndAddr_Call) Run(run func(ctx context.Context, info state.AIMNameAndAddr)) *mockProfileManager_FindByAIMNameAndAddr_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.AIMNameAndAddr))
+		run(args[0].(context.Context), args[1].(state.AIMNameAndAddr))
 	})
 	return _c
 }
@@ -189,14 +194,14 @@ func (_c *mockProfileManager_FindByAIMNameAndAddr_Call) Return(_a0 []state.User,
 	return _c
 }
 
-func (_c *mockProfileManager_FindByAIMNameAndAddr_Call) RunAndReturn(run func(state.AIMNameAndAddr) ([]state.User, error)) *mockProfileManager_FindByAIMNameAndAddr_Call {
+func (_c *mockProfileManager_FindByAIMNameAndAddr_Call) RunAndReturn(run func(context.Context, state.AIMNameAndAddr) ([]state.User, error)) *mockProfileManager_FindByAIMNameAndAddr_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// InterestList provides a mock function with no fields
-func (_m *mockProfileManager) InterestList() ([]wire.ODirKeywordListItem, error) {
-	ret := _m.Called()
+// InterestList provides a mock function with given fields: ctx
+func (_m *mockProfileManager) InterestList(ctx context.Context) ([]wire.ODirKeywordListItem, error) {
+	ret := _m.Called(ctx)
 
 	if len(ret) == 0 {
 		panic("no return value specified for InterestList")
@@ -204,19 +209,19 @@ func (_m *mockProfileManager) InterestList() ([]wire.ODirKeywordListItem, error)
 
 	var r0 []wire.ODirKeywordListItem
 	var r1 error
-	if rf, ok := ret.Get(0).(func() ([]wire.ODirKeywordListItem, error)); ok {
-		return rf()
+	if rf, ok := ret.Get(0).(func(context.Context) ([]wire.ODirKeywordListItem, error)); ok {
+		return rf(ctx)
 	}
-	if rf, ok := ret.Get(0).(func() []wire.ODirKeywordListItem); ok {
-		r0 = rf()
+	if rf, ok := ret.Get(0).(func(context.Context) []wire.ODirKeywordListItem); ok {
+		r0 = rf(ctx)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).([]wire.ODirKeywordListItem)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func() error); ok {
-		r1 = rf()
+	if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+		r1 = rf(ctx)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -230,13 +235,14 @@ type mockProfileManager_InterestList_Call struct {
 }
 
 // InterestList is a helper method to define mock.On call
-func (_e *mockProfileManager_Expecter) InterestList() *mockProfileManager_InterestList_Call {
-	return &mockProfileManager_InterestList_Call{Call: _e.mock.On("InterestList")}
+//   - ctx context.Context
+func (_e *mockProfileManager_Expecter) InterestList(ctx interface{}) *mockProfileManager_InterestList_Call {
+	return &mockProfileManager_InterestList_Call{Call: _e.mock.On("InterestList", ctx)}
 }
 
-func (_c *mockProfileManager_InterestList_Call) Run(run func()) *mockProfileManager_InterestList_Call {
+func (_c *mockProfileManager_InterestList_Call) Run(run func(ctx context.Context)) *mockProfileManager_InterestList_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run()
+		run(args[0].(context.Context))
 	})
 	return _c
 }
@@ -246,14 +252,14 @@ func (_c *mockProfileManager_InterestList_Call) Return(_a0 []wire.ODirKeywordLis
 	return _c
 }
 
-func (_c *mockProfileManager_InterestList_Call) RunAndReturn(run func() ([]wire.ODirKeywordListItem, error)) *mockProfileManager_InterestList_Call {
+func (_c *mockProfileManager_InterestList_Call) RunAndReturn(run func(context.Context) ([]wire.ODirKeywordListItem, error)) *mockProfileManager_InterestList_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// Profile provides a mock function with given fields: screenName
-func (_m *mockProfileManager) Profile(screenName state.IdentScreenName) (string, error) {
-	ret := _m.Called(screenName)
+// Profile provides a mock function with given fields: ctx, screenName
+func (_m *mockProfileManager) Profile(ctx context.Context, screenName state.IdentScreenName) (string, error) {
+	ret := _m.Called(ctx, screenName)
 
 	if len(ret) == 0 {
 		panic("no return value specified for Profile")
@@ -261,17 +267,17 @@ func (_m *mockProfileManager) Profile(screenName state.IdentScreenName) (string,
 
 	var r0 string
 	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (string, error)); ok {
-		return rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) (string, error)); ok {
+		return rf(ctx, screenName)
 	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) string); ok {
-		r0 = rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) string); ok {
+		r0 = rf(ctx, screenName)
 	} else {
 		r0 = ret.Get(0).(string)
 	}
 
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -285,14 +291,15 @@ type mockProfileManager_Profile_Call struct {
 }
 
 // Profile is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockProfileManager_Expecter) Profile(screenName interface{}) *mockProfileManager_Profile_Call {
-	return &mockProfileManager_Profile_Call{Call: _e.mock.On("Profile", screenName)}
+func (_e *mockProfileManager_Expecter) Profile(ctx interface{}, screenName interface{}) *mockProfileManager_Profile_Call {
+	return &mockProfileManager_Profile_Call{Call: _e.mock.On("Profile", ctx, screenName)}
 }
 
-func (_c *mockProfileManager_Profile_Call) Run(run func(screenName state.IdentScreenName)) *mockProfileManager_Profile_Call {
+func (_c *mockProfileManager_Profile_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockProfileManager_Profile_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
@@ -302,22 +309,22 @@ func (_c *mockProfileManager_Profile_Call) Return(_a0 string, _a1 error) *mockPr
 	return _c
 }
 
-func (_c *mockProfileManager_Profile_Call) RunAndReturn(run func(state.IdentScreenName) (string, error)) *mockProfileManager_Profile_Call {
+func (_c *mockProfileManager_Profile_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) (string, error)) *mockProfileManager_Profile_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// SetDirectoryInfo provides a mock function with given fields: name, info
-func (_m *mockProfileManager) SetDirectoryInfo(name state.IdentScreenName, info state.AIMNameAndAddr) error {
-	ret := _m.Called(name, info)
+// SetDirectoryInfo provides a mock function with given fields: ctx, screenName, info
+func (_m *mockProfileManager) SetDirectoryInfo(ctx context.Context, screenName state.IdentScreenName, info state.AIMNameAndAddr) error {
+	ret := _m.Called(ctx, screenName, info)
 
 	if len(ret) == 0 {
 		panic("no return value specified for SetDirectoryInfo")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, state.AIMNameAndAddr) error); ok {
-		r0 = rf(name, info)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, state.AIMNameAndAddr) error); ok {
+		r0 = rf(ctx, screenName, info)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -331,15 +338,16 @@ type mockProfileManager_SetDirectoryInfo_Call struct {
 }
 
 // SetDirectoryInfo is a helper method to define mock.On call
-//   - name state.IdentScreenName
+//   - ctx context.Context
+//   - screenName state.IdentScreenName
 //   - info state.AIMNameAndAddr
-func (_e *mockProfileManager_Expecter) SetDirectoryInfo(name interface{}, info interface{}) *mockProfileManager_SetDirectoryInfo_Call {
-	return &mockProfileManager_SetDirectoryInfo_Call{Call: _e.mock.On("SetDirectoryInfo", name, info)}
+func (_e *mockProfileManager_Expecter) SetDirectoryInfo(ctx interface{}, screenName interface{}, info interface{}) *mockProfileManager_SetDirectoryInfo_Call {
+	return &mockProfileManager_SetDirectoryInfo_Call{Call: _e.mock.On("SetDirectoryInfo", ctx, screenName, info)}
 }
 
-func (_c *mockProfileManager_SetDirectoryInfo_Call) Run(run func(name state.IdentScreenName, info state.AIMNameAndAddr)) *mockProfileManager_SetDirectoryInfo_Call {
+func (_c *mockProfileManager_SetDirectoryInfo_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName, info state.AIMNameAndAddr)) *mockProfileManager_SetDirectoryInfo_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(state.AIMNameAndAddr))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(state.AIMNameAndAddr))
 	})
 	return _c
 }
@@ -349,22 +357,22 @@ func (_c *mockProfileManager_SetDirectoryInfo_Call) Return(_a0 error) *mockProfi
 	return _c
 }
 
-func (_c *mockProfileManager_SetDirectoryInfo_Call) RunAndReturn(run func(state.IdentScreenName, state.AIMNameAndAddr) error) *mockProfileManager_SetDirectoryInfo_Call {
+func (_c *mockProfileManager_SetDirectoryInfo_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, state.AIMNameAndAddr) error) *mockProfileManager_SetDirectoryInfo_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// SetKeywords provides a mock function with given fields: name, keywords
-func (_m *mockProfileManager) SetKeywords(name state.IdentScreenName, keywords [5]string) error {
-	ret := _m.Called(name, keywords)
+// SetKeywords provides a mock function with given fields: ctx, screenName, keywords
+func (_m *mockProfileManager) SetKeywords(ctx context.Context, screenName state.IdentScreenName, keywords [5]string) error {
+	ret := _m.Called(ctx, screenName, keywords)
 
 	if len(ret) == 0 {
 		panic("no return value specified for SetKeywords")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, [5]string) error); ok {
-		r0 = rf(name, keywords)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, [5]string) error); ok {
+		r0 = rf(ctx, screenName, keywords)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -378,15 +386,16 @@ type mockProfileManager_SetKeywords_Call struct {
 }
 
 // SetKeywords is a helper method to define mock.On call
-//   - name state.IdentScreenName
+//   - ctx context.Context
+//   - screenName state.IdentScreenName
 //   - keywords [5]string
-func (_e *mockProfileManager_Expecter) SetKeywords(name interface{}, keywords interface{}) *mockProfileManager_SetKeywords_Call {
-	return &mockProfileManager_SetKeywords_Call{Call: _e.mock.On("SetKeywords", name, keywords)}
+func (_e *mockProfileManager_Expecter) SetKeywords(ctx interface{}, screenName interface{}, keywords interface{}) *mockProfileManager_SetKeywords_Call {
+	return &mockProfileManager_SetKeywords_Call{Call: _e.mock.On("SetKeywords", ctx, screenName, keywords)}
 }
 
-func (_c *mockProfileManager_SetKeywords_Call) Run(run func(name state.IdentScreenName, keywords [5]string)) *mockProfileManager_SetKeywords_Call {
+func (_c *mockProfileManager_SetKeywords_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName, keywords [5]string)) *mockProfileManager_SetKeywords_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].([5]string))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].([5]string))
 	})
 	return _c
 }
@@ -396,22 +405,22 @@ func (_c *mockProfileManager_SetKeywords_Call) Return(_a0 error) *mockProfileMan
 	return _c
 }
 
-func (_c *mockProfileManager_SetKeywords_Call) RunAndReturn(run func(state.IdentScreenName, [5]string) error) *mockProfileManager_SetKeywords_Call {
+func (_c *mockProfileManager_SetKeywords_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, [5]string) error) *mockProfileManager_SetKeywords_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// SetProfile provides a mock function with given fields: screenName, body
-func (_m *mockProfileManager) SetProfile(screenName state.IdentScreenName, body string) error {
-	ret := _m.Called(screenName, body)
+// SetProfile provides a mock function with given fields: ctx, screenName, body
+func (_m *mockProfileManager) SetProfile(ctx context.Context, screenName state.IdentScreenName, body string) error {
+	ret := _m.Called(ctx, screenName, body)
 
 	if len(ret) == 0 {
 		panic("no return value specified for SetProfile")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, string) error); ok {
-		r0 = rf(screenName, body)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, string) error); ok {
+		r0 = rf(ctx, screenName, body)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -425,15 +434,16 @@ type mockProfileManager_SetProfile_Call struct {
 }
 
 // SetProfile is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
 //   - body string
-func (_e *mockProfileManager_Expecter) SetProfile(screenName interface{}, body interface{}) *mockProfileManager_SetProfile_Call {
-	return &mockProfileManager_SetProfile_Call{Call: _e.mock.On("SetProfile", screenName, body)}
+func (_e *mockProfileManager_Expecter) SetProfile(ctx interface{}, screenName interface{}, body interface{}) *mockProfileManager_SetProfile_Call {
+	return &mockProfileManager_SetProfile_Call{Call: _e.mock.On("SetProfile", ctx, screenName, body)}
 }
 
-func (_c *mockProfileManager_SetProfile_Call) Run(run func(screenName state.IdentScreenName, body string)) *mockProfileManager_SetProfile_Call {
+func (_c *mockProfileManager_SetProfile_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName, body string)) *mockProfileManager_SetProfile_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(string))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(string))
 	})
 	return _c
 }
@@ -443,14 +453,14 @@ func (_c *mockProfileManager_SetProfile_Call) Return(_a0 error) *mockProfileMana
 	return _c
 }
 
-func (_c *mockProfileManager_SetProfile_Call) RunAndReturn(run func(state.IdentScreenName, string) error) *mockProfileManager_SetProfile_Call {
+func (_c *mockProfileManager_SetProfile_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, string) error) *mockProfileManager_SetProfile_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// User provides a mock function with given fields: screenName
-func (_m *mockProfileManager) User(screenName state.IdentScreenName) (*state.User, error) {
-	ret := _m.Called(screenName)
+// User provides a mock function with given fields: ctx, screenName
+func (_m *mockProfileManager) User(ctx context.Context, screenName state.IdentScreenName) (*state.User, error) {
+	ret := _m.Called(ctx, screenName)
 
 	if len(ret) == 0 {
 		panic("no return value specified for User")
@@ -458,19 +468,19 @@ func (_m *mockProfileManager) User(screenName state.IdentScreenName) (*state.Use
 
 	var r0 *state.User
 	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (*state.User, error)); ok {
-		return rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) (*state.User, error)); ok {
+		return rf(ctx, screenName)
 	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) *state.User); ok {
-		r0 = rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) *state.User); ok {
+		r0 = rf(ctx, screenName)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*state.User)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -484,14 +494,15 @@ type mockProfileManager_User_Call struct {
 }
 
 // User is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockProfileManager_Expecter) User(screenName interface{}) *mockProfileManager_User_Call {
-	return &mockProfileManager_User_Call{Call: _e.mock.On("User", screenName)}
+func (_e *mockProfileManager_Expecter) User(ctx interface{}, screenName interface{}) *mockProfileManager_User_Call {
+	return &mockProfileManager_User_Call{Call: _e.mock.On("User", ctx, screenName)}
 }
 
-func (_c *mockProfileManager_User_Call) Run(run func(screenName state.IdentScreenName)) *mockProfileManager_User_Call {
+func (_c *mockProfileManager_User_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockProfileManager_User_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
@@ -501,7 +512,7 @@ func (_c *mockProfileManager_User_Call) Return(_a0 *state.User, _a1 error) *mock
 	return _c
 }
 
-func (_c *mockProfileManager_User_Call) RunAndReturn(run func(state.IdentScreenName) (*state.User, error)) *mockProfileManager_User_Call {
+func (_c *mockProfileManager_User_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) (*state.User, error)) *mockProfileManager_User_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 155 - 0
foodgroup/mock_relationship_fetcher_test.go

@@ -0,0 +1,155 @@
+// Code generated by mockery v2.52.1. DO NOT EDIT.
+
+package foodgroup
+
+import (
+	context "context"
+
+	state "github.com/mk6i/retro-aim-server/state"
+	mock "github.com/stretchr/testify/mock"
+)
+
+// mockRelationshipFetcher is an autogenerated mock type for the RelationshipFetcher type
+type mockRelationshipFetcher struct {
+	mock.Mock
+}
+
+type mockRelationshipFetcher_Expecter struct {
+	mock *mock.Mock
+}
+
+func (_m *mockRelationshipFetcher) EXPECT() *mockRelationshipFetcher_Expecter {
+	return &mockRelationshipFetcher_Expecter{mock: &_m.Mock}
+}
+
+// AllRelationships provides a mock function with given fields: ctx, me, filter
+func (_m *mockRelationshipFetcher) AllRelationships(ctx context.Context, me state.IdentScreenName, filter []state.IdentScreenName) ([]state.Relationship, error) {
+	ret := _m.Called(ctx, me, filter)
+
+	if len(ret) == 0 {
+		panic("no return value specified for AllRelationships")
+	}
+
+	var r0 []state.Relationship
+	var r1 error
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, []state.IdentScreenName) ([]state.Relationship, error)); ok {
+		return rf(ctx, me, filter)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, []state.IdentScreenName) []state.Relationship); ok {
+		r0 = rf(ctx, me, filter)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).([]state.Relationship)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName, []state.IdentScreenName) error); ok {
+		r1 = rf(ctx, me, filter)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// mockRelationshipFetcher_AllRelationships_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AllRelationships'
+type mockRelationshipFetcher_AllRelationships_Call struct {
+	*mock.Call
+}
+
+// AllRelationships is a helper method to define mock.On call
+//   - ctx context.Context
+//   - me state.IdentScreenName
+//   - filter []state.IdentScreenName
+func (_e *mockRelationshipFetcher_Expecter) AllRelationships(ctx interface{}, me interface{}, filter interface{}) *mockRelationshipFetcher_AllRelationships_Call {
+	return &mockRelationshipFetcher_AllRelationships_Call{Call: _e.mock.On("AllRelationships", ctx, me, filter)}
+}
+
+func (_c *mockRelationshipFetcher_AllRelationships_Call) Run(run func(ctx context.Context, me state.IdentScreenName, filter []state.IdentScreenName)) *mockRelationshipFetcher_AllRelationships_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].([]state.IdentScreenName))
+	})
+	return _c
+}
+
+func (_c *mockRelationshipFetcher_AllRelationships_Call) Return(_a0 []state.Relationship, _a1 error) *mockRelationshipFetcher_AllRelationships_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *mockRelationshipFetcher_AllRelationships_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, []state.IdentScreenName) ([]state.Relationship, error)) *mockRelationshipFetcher_AllRelationships_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// Relationship provides a mock function with given fields: ctx, me, them
+func (_m *mockRelationshipFetcher) Relationship(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName) (state.Relationship, error) {
+	ret := _m.Called(ctx, me, them)
+
+	if len(ret) == 0 {
+		panic("no return value specified for Relationship")
+	}
+
+	var r0 state.Relationship
+	var r1 error
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, state.IdentScreenName) (state.Relationship, error)); ok {
+		return rf(ctx, me, them)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, state.IdentScreenName) state.Relationship); ok {
+		r0 = rf(ctx, me, them)
+	} else {
+		r0 = ret.Get(0).(state.Relationship)
+	}
+
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, me, them)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// mockRelationshipFetcher_Relationship_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Relationship'
+type mockRelationshipFetcher_Relationship_Call struct {
+	*mock.Call
+}
+
+// Relationship is a helper method to define mock.On call
+//   - ctx context.Context
+//   - me state.IdentScreenName
+//   - them state.IdentScreenName
+func (_e *mockRelationshipFetcher_Expecter) Relationship(ctx interface{}, me interface{}, them interface{}) *mockRelationshipFetcher_Relationship_Call {
+	return &mockRelationshipFetcher_Relationship_Call{Call: _e.mock.On("Relationship", ctx, me, them)}
+}
+
+func (_c *mockRelationshipFetcher_Relationship_Call) Run(run func(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName)) *mockRelationshipFetcher_Relationship_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(state.IdentScreenName))
+	})
+	return _c
+}
+
+func (_c *mockRelationshipFetcher_Relationship_Call) Return(_a0 state.Relationship, _a1 error) *mockRelationshipFetcher_Relationship_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *mockRelationshipFetcher_Relationship_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, state.IdentScreenName) (state.Relationship, error)) *mockRelationshipFetcher_Relationship_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// newMockRelationshipFetcher creates a new instance of mockRelationshipFetcher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func newMockRelationshipFetcher(t interface {
+	mock.TestingT
+	Cleanup(func())
+}) *mockRelationshipFetcher {
+	mock := &mockRelationshipFetcher{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}

+ 28 - 24
foodgroup/mock_user_manager_manager_test.go

@@ -3,6 +3,8 @@
 package foodgroup
 
 import (
+	context "context"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 )
@@ -20,17 +22,17 @@ func (_m *mockUserManager) EXPECT() *mockUserManager_Expecter {
 	return &mockUserManager_Expecter{mock: &_m.Mock}
 }
 
-// InsertUser provides a mock function with given fields: u
-func (_m *mockUserManager) InsertUser(u state.User) error {
-	ret := _m.Called(u)
+// InsertUser provides a mock function with given fields: ctx, u
+func (_m *mockUserManager) InsertUser(ctx context.Context, u state.User) error {
+	ret := _m.Called(ctx, u)
 
 	if len(ret) == 0 {
 		panic("no return value specified for InsertUser")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.User) error); ok {
-		r0 = rf(u)
+	if rf, ok := ret.Get(0).(func(context.Context, state.User) error); ok {
+		r0 = rf(ctx, u)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -44,14 +46,15 @@ type mockUserManager_InsertUser_Call struct {
 }
 
 // InsertUser is a helper method to define mock.On call
+//   - ctx context.Context
 //   - u state.User
-func (_e *mockUserManager_Expecter) InsertUser(u interface{}) *mockUserManager_InsertUser_Call {
-	return &mockUserManager_InsertUser_Call{Call: _e.mock.On("InsertUser", u)}
+func (_e *mockUserManager_Expecter) InsertUser(ctx interface{}, u interface{}) *mockUserManager_InsertUser_Call {
+	return &mockUserManager_InsertUser_Call{Call: _e.mock.On("InsertUser", ctx, u)}
 }
 
-func (_c *mockUserManager_InsertUser_Call) Run(run func(u state.User)) *mockUserManager_InsertUser_Call {
+func (_c *mockUserManager_InsertUser_Call) Run(run func(ctx context.Context, u state.User)) *mockUserManager_InsertUser_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.User))
+		run(args[0].(context.Context), args[1].(state.User))
 	})
 	return _c
 }
@@ -61,14 +64,14 @@ func (_c *mockUserManager_InsertUser_Call) Return(_a0 error) *mockUserManager_In
 	return _c
 }
 
-func (_c *mockUserManager_InsertUser_Call) RunAndReturn(run func(state.User) error) *mockUserManager_InsertUser_Call {
+func (_c *mockUserManager_InsertUser_Call) RunAndReturn(run func(context.Context, state.User) error) *mockUserManager_InsertUser_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// User provides a mock function with given fields: screenName
-func (_m *mockUserManager) User(screenName state.IdentScreenName) (*state.User, error) {
-	ret := _m.Called(screenName)
+// User provides a mock function with given fields: ctx, screenName
+func (_m *mockUserManager) User(ctx context.Context, screenName state.IdentScreenName) (*state.User, error) {
+	ret := _m.Called(ctx, screenName)
 
 	if len(ret) == 0 {
 		panic("no return value specified for User")
@@ -76,19 +79,19 @@ func (_m *mockUserManager) User(screenName state.IdentScreenName) (*state.User,
 
 	var r0 *state.User
 	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (*state.User, error)); ok {
-		return rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) (*state.User, error)); ok {
+		return rf(ctx, screenName)
 	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) *state.User); ok {
-		r0 = rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) *state.User); ok {
+		r0 = rf(ctx, screenName)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*state.User)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -102,14 +105,15 @@ type mockUserManager_User_Call struct {
 }
 
 // User is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockUserManager_Expecter) User(screenName interface{}) *mockUserManager_User_Call {
-	return &mockUserManager_User_Call{Call: _e.mock.On("User", screenName)}
+func (_e *mockUserManager_Expecter) User(ctx interface{}, screenName interface{}) *mockUserManager_User_Call {
+	return &mockUserManager_User_Call{Call: _e.mock.On("User", ctx, screenName)}
 }
 
-func (_c *mockUserManager_User_Call) Run(run func(screenName state.IdentScreenName)) *mockUserManager_User_Call {
+func (_c *mockUserManager_User_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockUserManager_User_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
@@ -119,7 +123,7 @@ func (_c *mockUserManager_User_Call) Return(_a0 *state.User, _a1 error) *mockUse
 	return _c
 }
 
-func (_c *mockUserManager_User_Call) RunAndReturn(run func(state.IdentScreenName) (*state.User, error)) *mockUserManager_User_Call {
+func (_c *mockUserManager_User_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) (*state.User, error)) *mockUserManager_User_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 6 - 6
foodgroup/odir.go

@@ -39,7 +39,7 @@ type ODirService struct {
 // ignored in order to be backwards compatible with older versions that do not
 // send it. It doesn't appear to make a difference, since AIM 5.x sends the
 // same TLV types for each search type.
-func (s ODirService) InfoQuery(_ context.Context, inFrame wire.SNACFrame, inBody wire.SNAC_0x0F_0x02_InfoQuery) (wire.SNACMessage, error) {
+func (s ODirService) InfoQuery(ctx context.Context, inFrame wire.SNACFrame, inBody wire.SNAC_0x0F_0x02_InfoQuery) (wire.SNACMessage, error) {
 	response := wire.SNACMessage{
 		Frame: wire.SNACFrame{
 			FoodGroup: wire.ODir,
@@ -50,7 +50,7 @@ func (s ODirService) InfoQuery(_ context.Context, inFrame wire.SNACFrame, inBody
 
 	// search by email address
 	if email, hasEmail := inBody.String(wire.ODirTLVEmailAddress); hasEmail {
-		foundUser, err := s.profileManager.FindByAIMEmail(email)
+		foundUser, err := s.profileManager.FindByAIMEmail(ctx, email)
 		if err != nil {
 			if errors.Is(err, state.ErrNoUser) {
 				response.Body = s.searchResponse(nil)
@@ -64,7 +64,7 @@ func (s ODirService) InfoQuery(_ context.Context, inFrame wire.SNACFrame, inBody
 
 	// search by interest keyword
 	if interest, hasInterest := inBody.String(wire.ODirTLVInterest); hasInterest {
-		foundUsers, err := s.profileManager.FindByAIMKeyword(interest)
+		foundUsers, err := s.profileManager.FindByAIMKeyword(ctx, interest)
 		if err != nil {
 			return wire.SNACMessage{}, fmt.Errorf("FindByAIMKeyword: %w", err)
 		}
@@ -74,7 +74,7 @@ func (s ODirService) InfoQuery(_ context.Context, inFrame wire.SNACFrame, inBody
 
 	// search by name and address
 	if inBody.HasTag(wire.ODirTLVFirstName) || inBody.HasTag(wire.ODirTLVLastName) {
-		foundUsers, err := s.profileManager.FindByAIMNameAndAddr(newAIMNameAndAddrFromTLVList(inBody.TLVList))
+		foundUsers, err := s.profileManager.FindByAIMNameAndAddr(ctx, newAIMNameAndAddrFromTLVList(inBody.TLVList))
 		if err != nil {
 			return wire.SNACMessage{}, fmt.Errorf("FindByAIMNameAndAddr: %w", err)
 		}
@@ -91,8 +91,8 @@ func (s ODirService) InfoQuery(_ context.Context, inFrame wire.SNACFrame, inBody
 
 // KeywordListQuery returns a list of keywords that can be searched in the user
 // directory.
-func (s ODirService) KeywordListQuery(_ context.Context, inFrame wire.SNACFrame) (wire.SNACMessage, error) {
-	interests, err := s.profileManager.InterestList()
+func (s ODirService) KeywordListQuery(ctx context.Context, inFrame wire.SNACFrame) (wire.SNACMessage, error) {
+	interests, err := s.profileManager.InterestList(ctx)
 	if err != nil {
 		return wire.SNACMessage{}, fmt.Errorf("InterestList: %w", err)
 	}

+ 7 - 6
foodgroup/odir_test.go

@@ -1,6 +1,7 @@
 package foodgroup
 
 import (
+	"context"
 	"log/slog"
 	"testing"
 
@@ -102,12 +103,12 @@ func TestODirService_KeywordListQuery(t *testing.T) {
 			profileManager := newMockProfileManager(t)
 			for _, params := range tc.mockParams.interestListParams {
 				profileManager.EXPECT().
-					InterestList().
+					InterestList(matchContext()).
 					Return(params.result, params.err)
 			}
 
 			svc := NewODirService(slog.Default(), profileManager)
-			actual, err := svc.KeywordListQuery(nil, tc.inputSNAC.Frame)
+			actual, err := svc.KeywordListQuery(context.Background(), tc.inputSNAC.Frame)
 			assert.NoError(t, err)
 			assert.Equal(t, tc.expectOutput, actual)
 		})
@@ -493,22 +494,22 @@ func TestODirService_InfoQuery(t *testing.T) {
 			profileManager := newMockProfileManager(t)
 			for _, params := range tc.mockParams.findByAIMNameAndAddrParams {
 				profileManager.EXPECT().
-					FindByAIMNameAndAddr(params.info).
+					FindByAIMNameAndAddr(matchContext(), params.info).
 					Return(params.result, params.err)
 			}
 			for _, params := range tc.mockParams.findByAIMEmailParams {
 				profileManager.EXPECT().
-					FindByAIMEmail(params.email).
+					FindByAIMEmail(matchContext(), params.email).
 					Return(params.result, params.err)
 			}
 			for _, params := range tc.mockParams.findByAIMKeywordParams {
 				profileManager.EXPECT().
-					FindByAIMKeyword(params.keyword).
+					FindByAIMKeyword(matchContext(), params.keyword).
 					Return(params.result, params.err)
 			}
 
 			svc := NewODirService(slog.Default(), profileManager)
-			actual, err := svc.InfoQuery(nil, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x0F_0x02_InfoQuery))
+			actual, err := svc.InfoQuery(context.Background(), tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x0F_0x02_InfoQuery))
 			assert.NoError(t, err)
 			assert.Equal(t, tc.expectOutput, actual)
 		})

+ 20 - 14
foodgroup/oservice.go

@@ -611,15 +611,16 @@ func NewOServiceServiceForBOS(
 	logger *slog.Logger,
 	cookieIssuer CookieBaker,
 	chatRoomManager ChatRoomRegistry,
-	buddyListRetriever BuddyListRetriever,
+	relationshipFetcher RelationshipFetcher,
 	sessionRetriever SessionRetriever,
+	buddyIconManager BuddyIconManager,
 ) *OServiceServiceForBOS {
 	return &OServiceServiceForBOS{
 		chatRoomManager: chatRoomManager,
 		cookieIssuer:    cookieIssuer,
 		messageRelayer:  messageRelayer,
 		OServiceService: OServiceService{
-			buddyBroadcaster: newBuddyNotifier(buddyListRetriever, messageRelayer, sessionRetriever),
+			buddyBroadcaster: newBuddyNotifier(buddyIconManager, relationshipFetcher, messageRelayer, sessionRetriever),
 			cfg:              cfg,
 			logger:           logger,
 			foodGroups: []uint16{
@@ -780,7 +781,7 @@ func (s OServiceServiceForBOS) ServiceRequest(ctx context.Context, sess *state.S
 			return wire.SNACMessage{}, err
 		}
 
-		room, err := s.chatRoomManager.ChatRoomByCookie(roomSNAC.Cookie)
+		room, err := s.chatRoomManager.ChatRoomByCookie(ctx, roomSNAC.Cookie)
 		if err != nil {
 			return wire.SNACMessage{}, fmt.Errorf("unable to retrieve room info: %w", err)
 		}
@@ -871,12 +872,13 @@ func NewOServiceServiceForChat(
 	messageRelayer MessageRelayer,
 	chatRoomManager ChatRoomRegistry,
 	chatMessageRelayer ChatMessageRelayer,
-	buddyListRetriever BuddyListRetriever,
+	relationshipFetcher RelationshipFetcher,
 	sessionRetriever SessionRetriever,
+	buddyIconManager BuddyIconManager,
 ) *OServiceServiceForChat {
 	return &OServiceServiceForChat{
 		OServiceService: OServiceService{
-			buddyBroadcaster: newBuddyNotifier(buddyListRetriever, messageRelayer, sessionRetriever),
+			buddyBroadcaster: newBuddyNotifier(buddyIconManager, relationshipFetcher, messageRelayer, sessionRetriever),
 			cfg:              cfg,
 			logger:           logger,
 			foodGroups: []uint16{
@@ -903,7 +905,7 @@ type OServiceServiceForChat struct {
 //   - Announce current user's arrival to other chat room participants
 //   - Send current user the chat room participant list
 func (s OServiceServiceForChat) ClientOnline(ctx context.Context, _ wire.SNAC_0x01_0x02_OServiceClientOnline, sess *state.Session) error {
-	room, err := s.chatRoomManager.ChatRoomByCookie(sess.ChatRoomCookie())
+	room, err := s.chatRoomManager.ChatRoomByCookie(ctx, sess.ChatRoomCookie())
 	if err != nil {
 		return fmt.Errorf("error getting chat room: %w", err)
 	}
@@ -924,11 +926,12 @@ func NewOServiceServiceForChatNav(
 	cfg config.Config,
 	logger *slog.Logger,
 	messageRelayer MessageRelayer,
-	buddyListRetriever BuddyListRetriever,
+	relationshipFetcher RelationshipFetcher,
 	sessionRetriever SessionRetriever,
+	buddyIconManager BuddyIconManager,
 ) *OServiceService {
 	return &OServiceService{
-		buddyBroadcaster: newBuddyNotifier(buddyListRetriever, messageRelayer, sessionRetriever),
+		buddyBroadcaster: newBuddyNotifier(buddyIconManager, relationshipFetcher, messageRelayer, sessionRetriever),
 		cfg:              cfg,
 		logger:           logger,
 		foodGroups: []uint16{
@@ -944,11 +947,12 @@ func NewOServiceServiceForAlert(
 	cfg config.Config,
 	logger *slog.Logger,
 	messageRelayer MessageRelayer,
-	buddyListRetriever BuddyListRetriever,
+	relationshipFetcher RelationshipFetcher,
 	sessionRetriever SessionRetriever,
+	buddyIconManager BuddyIconManager,
 ) *OServiceService {
 	return &OServiceService{
-		buddyBroadcaster: newBuddyNotifier(buddyListRetriever, messageRelayer, sessionRetriever),
+		buddyBroadcaster: newBuddyNotifier(buddyIconManager, relationshipFetcher, messageRelayer, sessionRetriever),
 		cfg:              cfg,
 		logger:           logger,
 		foodGroups: []uint16{
@@ -976,11 +980,12 @@ func NewOServiceServiceForAdmin(
 	cfg config.Config,
 	logger *slog.Logger,
 	messageRelayer MessageRelayer,
-	buddyListRetriever BuddyListRetriever,
+	relationshipFetcher RelationshipFetcher,
 	sessionRetriever SessionRetriever,
+	buddyIconManager BuddyIconManager,
 ) *OServiceService {
 	return &OServiceService{
-		buddyBroadcaster: newBuddyNotifier(buddyListRetriever, messageRelayer, sessionRetriever),
+		buddyBroadcaster: newBuddyNotifier(buddyIconManager, relationshipFetcher, messageRelayer, sessionRetriever),
 		cfg:              cfg,
 		logger:           logger,
 		foodGroups: []uint16{
@@ -996,11 +1001,12 @@ func NewOServiceServiceForBART(
 	cfg config.Config,
 	logger *slog.Logger,
 	messageRelayer MessageRelayer,
-	buddyListRetriever BuddyListRetriever,
+	relationshipFetcher RelationshipFetcher,
 	sessionRetriever SessionRetriever,
+	buddyIconManager BuddyIconManager,
 ) *OServiceService {
 	return &OServiceService{
-		buddyBroadcaster: newBuddyNotifier(buddyListRetriever, messageRelayer, sessionRetriever),
+		buddyBroadcaster: newBuddyNotifier(buddyIconManager, relationshipFetcher, messageRelayer, sessionRetriever),
 		cfg:              cfg,
 		logger:           logger,
 		foodGroups: []uint16{

+ 11 - 11
foodgroup/oservice_test.go

@@ -311,7 +311,7 @@ func TestOServiceServiceForBOS_ServiceRequest(t *testing.T) {
 			chatRoomManager := newMockChatRoomRegistry(t)
 			for _, params := range tc.mockParams.chatRoomByCookieParams {
 				chatRoomManager.EXPECT().
-					ChatRoomByCookie(params.cookie).
+					ChatRoomByCookie(context.Background(), params.cookie).
 					Return(params.room, params.err)
 			}
 			cookieIssuer := newMockCookieBaker(t)
@@ -323,9 +323,9 @@ func TestOServiceServiceForBOS_ServiceRequest(t *testing.T) {
 			//
 			// send input SNAC
 			//
-			svc := NewOServiceServiceForBOS(tc.cfg, nil, slog.Default(), cookieIssuer, chatRoomManager, nil, nil)
+			svc := NewOServiceServiceForBOS(tc.cfg, nil, slog.Default(), cookieIssuer, chatRoomManager, nil, nil, nil)
 
-			outputSNAC, err := svc.ServiceRequest(nil, tc.userSession, tc.inputSNAC.Frame,
+			outputSNAC, err := svc.ServiceRequest(context.Background(), tc.userSession, tc.inputSNAC.Frame,
 				tc.inputSNAC.Body.(wire.SNAC_0x01_0x04_OServiceServiceRequest))
 			assert.ErrorIs(t, err, tc.expectErr)
 			if tc.expectErr != nil {
@@ -1557,7 +1557,7 @@ func TestOServiceService_RateParamsQuery(t *testing.T) {
 
 func TestOServiceServiceForBOS_OServiceHostOnline(t *testing.T) {
 	cookieIssuer := newMockCookieBaker(t)
-	svc := NewOServiceServiceForBOS(config.Config{}, nil, slog.Default(), cookieIssuer, nil, nil, nil)
+	svc := NewOServiceServiceForBOS(config.Config{}, nil, slog.Default(), cookieIssuer, nil, nil, nil, nil)
 
 	want := wire.SNACMessage{
 		Frame: wire.SNACFrame{
@@ -1589,7 +1589,7 @@ func TestOServiceServiceForBOS_OServiceHostOnline(t *testing.T) {
 }
 
 func TestOServiceServiceForChat_OServiceHostOnline(t *testing.T) {
-	svc := NewOServiceServiceForChat(config.Config{}, slog.Default(), nil, nil, nil, nil, nil)
+	svc := NewOServiceServiceForChat(config.Config{}, slog.Default(), nil, nil, nil, nil, nil, nil)
 
 	want := wire.SNACMessage{
 		Frame: wire.SNACFrame{
@@ -1764,7 +1764,7 @@ func TestOServiceServiceForBOS_ClientOnline(t *testing.T) {
 					Return(params.err)
 			}
 
-			svc := NewOServiceServiceForBOS(config.Config{}, nil, slog.Default(), nil, nil, nil, nil)
+			svc := NewOServiceServiceForBOS(config.Config{}, nil, slog.Default(), nil, nil, nil, nil, nil)
 			svc.buddyBroadcaster = buddyUpdateBroadcaster
 			haveErr := svc.ClientOnline(nil, tt.bodyIn, tt.sess)
 			assert.ErrorIs(t, tt.wantErr, haveErr)
@@ -1877,7 +1877,7 @@ func TestOServiceServiceForChat_ClientOnline(t *testing.T) {
 			chatRoomManager := newMockChatRoomRegistry(t)
 			for _, params := range tt.mockParams.chatRoomByCookieParams {
 				chatRoomManager.EXPECT().
-					ChatRoomByCookie(params.cookie).
+					ChatRoomByCookie(context.Background(), params.cookie).
 					Return(params.room, params.err)
 			}
 			chatMessageRelayer := newMockChatMessageRelayer(t)
@@ -1895,16 +1895,16 @@ func TestOServiceServiceForChat_ClientOnline(t *testing.T) {
 					RelayToScreenName(mock.Anything, params.cookie, params.screenName, params.message)
 			}
 
-			svc := NewOServiceServiceForChat(config.Config{}, slog.Default(), nil, chatRoomManager, chatMessageRelayer, nil, nil)
+			svc := NewOServiceServiceForChat(config.Config{}, slog.Default(), nil, chatRoomManager, chatMessageRelayer, nil, nil, nil)
 
-			haveErr := svc.ClientOnline(nil, wire.SNAC_0x01_0x02_OServiceClientOnline{}, tt.joiningChatter)
+			haveErr := svc.ClientOnline(context.Background(), wire.SNAC_0x01_0x02_OServiceClientOnline{}, tt.joiningChatter)
 			assert.ErrorIs(t, tt.wantErr, haveErr)
 		})
 	}
 }
 
 func TestOServiceServiceForChatNav_HostOnline(t *testing.T) {
-	svc := NewOServiceServiceForChatNav(config.Config{}, slog.Default(), nil, nil, nil)
+	svc := NewOServiceServiceForChatNav(config.Config{}, slog.Default(), nil, nil, nil, nil)
 
 	want := wire.SNACMessage{
 		Frame: wire.SNACFrame{
@@ -1925,7 +1925,7 @@ func TestOServiceServiceForChatNav_HostOnline(t *testing.T) {
 }
 
 func TestOServiceServiceForAlert_HostOnline(t *testing.T) {
-	svc := NewOServiceServiceForAlert(config.Config{}, slog.Default(), nil, nil, nil)
+	svc := NewOServiceServiceForAlert(config.Config{}, slog.Default(), nil, nil, nil, nil)
 
 	want := wire.SNACMessage{
 		Frame: wire.SNACFrame{

+ 15 - 14
foodgroup/permit_deny.go

@@ -9,14 +9,15 @@ import (
 
 // NewPermitDenyService creates an instance of PermitDenyService.
 func NewPermitDenyService(
-	buddyListRetriever BuddyListRetriever,
-	localBuddyListManager LocalBuddyListManager,
+	buddyIconManager BuddyIconManager,
+	relationshipFetcher RelationshipFetcher,
+	clientSideBuddyListManager ClientSideBuddyListManager,
 	messageRelayer MessageRelayer,
 	sessionRetriever SessionRetriever,
 ) PermitDenyService {
 	return PermitDenyService{
-		buddyBroadcaster:      newBuddyNotifier(buddyListRetriever, messageRelayer, sessionRetriever),
-		localBuddyListManager: localBuddyListManager,
+		buddyBroadcaster:           newBuddyNotifier(buddyIconManager, relationshipFetcher, messageRelayer, sessionRetriever),
+		clientSideBuddyListManager: clientSideBuddyListManager,
 	}
 }
 
@@ -24,8 +25,8 @@ func NewPermitDenyService(
 // The PD food group manages settings for permit/deny (allow/block) for
 // pre-feedbag (sever-side buddy list) AIM clients.
 type PermitDenyService struct {
-	buddyBroadcaster      buddyBroadcaster
-	localBuddyListManager LocalBuddyListManager
+	buddyBroadcaster           buddyBroadcaster
+	clientSideBuddyListManager ClientSideBuddyListManager
 }
 
 // AddDenyListEntries adds users to your block list and sets your visibility
@@ -41,20 +42,20 @@ func (s PermitDenyService) AddDenyListEntries(
 	if len(body.Users) == 1 {
 		sn := state.NewIdentScreenName(body.Users[0].ScreenName)
 		if sn.String() == sess.IdentScreenName().String() {
-			if err := s.localBuddyListManager.SetPDMode(sess.IdentScreenName(), wire.FeedbagPDModePermitAll); err != nil {
+			if err := s.clientSideBuddyListManager.SetPDMode(ctx, sess.IdentScreenName(), wire.FeedbagPDModePermitAll); err != nil {
 				return err
 			}
 			return s.maybeBroadcastVisibility(ctx, sess, nil)
 		}
 	}
 
-	if err := s.localBuddyListManager.SetPDMode(sess.IdentScreenName(), wire.FeedbagPDModeDenySome); err != nil {
+	if err := s.clientSideBuddyListManager.SetPDMode(ctx, sess.IdentScreenName(), wire.FeedbagPDModeDenySome); err != nil {
 		return err
 	}
 
 	for _, user := range body.Users {
 		sn := state.NewIdentScreenName(user.ScreenName)
-		if err := s.localBuddyListManager.DenyBuddy(sess.IdentScreenName(), sn); err != nil {
+		if err := s.clientSideBuddyListManager.DenyBuddy(ctx, sess.IdentScreenName(), sn); err != nil {
 			return err
 		}
 	}
@@ -77,20 +78,20 @@ func (s PermitDenyService) AddPermListEntries(
 	if len(body.Users) == 1 {
 		sn := state.NewIdentScreenName(body.Users[0].ScreenName)
 		if sn.String() == sess.IdentScreenName().String() {
-			if err := s.localBuddyListManager.SetPDMode(sess.IdentScreenName(), wire.FeedbagPDModeDenyAll); err != nil {
+			if err := s.clientSideBuddyListManager.SetPDMode(ctx, sess.IdentScreenName(), wire.FeedbagPDModeDenyAll); err != nil {
 				return err
 			}
 			return s.maybeBroadcastVisibility(ctx, sess, nil)
 		}
 	}
 
-	if err := s.localBuddyListManager.SetPDMode(sess.IdentScreenName(), wire.FeedbagPDModePermitSome); err != nil {
+	if err := s.clientSideBuddyListManager.SetPDMode(ctx, sess.IdentScreenName(), wire.FeedbagPDModePermitSome); err != nil {
 		return err
 	}
 
 	for _, user := range body.Users {
 		sn := state.NewIdentScreenName(user.ScreenName)
-		if err := s.localBuddyListManager.PermitBuddy(sess.IdentScreenName(), sn); err != nil {
+		if err := s.clientSideBuddyListManager.PermitBuddy(ctx, sess.IdentScreenName(), sn); err != nil {
 			return err
 		}
 	}
@@ -113,7 +114,7 @@ func (s PermitDenyService) DelDenyListEntries(
 
 	for _, user := range body.Users {
 		sn := state.NewIdentScreenName(user.ScreenName)
-		if err := s.localBuddyListManager.RemoveDenyBuddy(sess.IdentScreenName(), sn); err != nil {
+		if err := s.clientSideBuddyListManager.RemoveDenyBuddy(ctx, sess.IdentScreenName(), sn); err != nil {
 			return err
 		}
 	}
@@ -134,7 +135,7 @@ func (s PermitDenyService) DelPermListEntries(
 
 	for _, user := range body.Users {
 		sn := state.NewIdentScreenName(user.ScreenName)
-		if err := s.localBuddyListManager.RemovePermitBuddy(sess.IdentScreenName(), sn); err != nil {
+		if err := s.clientSideBuddyListManager.RemovePermitBuddy(ctx, sess.IdentScreenName(), sn); err != nil {
 			return err
 		}
 	}

+ 39 - 39
foodgroup/permit_deny_test.go

@@ -11,7 +11,7 @@ import (
 )
 
 func TestPermitDenyService_RightsQuery(t *testing.T) {
-	svc := NewPermitDenyService(nil, nil, nil, nil)
+	svc := NewPermitDenyService(nil, nil, nil, nil, nil)
 
 	have := svc.RightsQuery(nil, wire.SNACFrame{RequestID: 1234})
 	want := wire.SNACMessage{
@@ -61,7 +61,7 @@ func TestPermitDenyService_AddDenyListEntries(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					setPDModeParams: setPDModeParams{
 						{
 							userScreenName: state.NewIdentScreenName("me"),
@@ -84,7 +84,7 @@ func TestPermitDenyService_AddDenyListEntries(t *testing.T) {
 			sess:   newTestSession("me", sessOptSignonComplete),
 			bodyIn: wire.SNAC_0x09_0x07_PermitDenyAddDenyListEntries{},
 			mockParams: mockParams{
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					setPDModeParams: setPDModeParams{
 						{
 							userScreenName: state.NewIdentScreenName("me"),
@@ -113,7 +113,7 @@ func TestPermitDenyService_AddDenyListEntries(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					setPDModeParams: setPDModeParams{
 						{
 							userScreenName: state.NewIdentScreenName("me"),
@@ -148,7 +148,7 @@ func TestPermitDenyService_AddDenyListEntries(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					setPDModeParams: setPDModeParams{
 						{
 							userScreenName: state.NewIdentScreenName("me"),
@@ -179,7 +179,7 @@ func TestPermitDenyService_AddDenyListEntries(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					setPDModeParams: setPDModeParams{
 						{
 							userScreenName: state.NewIdentScreenName("me"),
@@ -210,15 +210,15 @@ func TestPermitDenyService_AddDenyListEntries(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			localBuddyListManager := newMockLocalBuddyListManager(t)
+			clientSideBuddyListManager := newMockClientSideBuddyListManager(t)
 			for _, item := range tt.mockParams.setPDModeParams {
-				localBuddyListManager.EXPECT().
-					SetPDMode(item.userScreenName, item.pdMode).
+				clientSideBuddyListManager.EXPECT().
+					SetPDMode(matchContext(), item.userScreenName, item.pdMode).
 					Return(item.err)
 			}
 			for _, item := range tt.mockParams.denyBuddyParams {
-				localBuddyListManager.EXPECT().
-					DenyBuddy(item.me, item.them).
+				clientSideBuddyListManager.EXPECT().
+					DenyBuddy(matchContext(), item.me, item.them).
 					Return(item.err)
 			}
 			mockBuddyBroadcaster := newMockbuddyBroadcaster(t)
@@ -229,8 +229,8 @@ func TestPermitDenyService_AddDenyListEntries(t *testing.T) {
 			}
 
 			svc := PermitDenyService{
-				buddyBroadcaster:      mockBuddyBroadcaster,
-				localBuddyListManager: localBuddyListManager,
+				buddyBroadcaster:           mockBuddyBroadcaster,
+				clientSideBuddyListManager: clientSideBuddyListManager,
 			}
 			err := svc.AddDenyListEntries(context.TODO(), tt.sess, tt.bodyIn)
 			assert.Equal(t, tt.wantErr, err)
@@ -265,7 +265,7 @@ func TestPermitDenyService_AddPermListEntries(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					setPDModeParams: setPDModeParams{
 						{
 							userScreenName: state.NewIdentScreenName("me"),
@@ -288,7 +288,7 @@ func TestPermitDenyService_AddPermListEntries(t *testing.T) {
 			sess:   newTestSession("me", sessOptSignonComplete),
 			bodyIn: wire.SNAC_0x09_0x05_PermitDenyAddPermListEntries{},
 			mockParams: mockParams{
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					setPDModeParams: setPDModeParams{
 						{
 							userScreenName: state.NewIdentScreenName("me"),
@@ -317,7 +317,7 @@ func TestPermitDenyService_AddPermListEntries(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					setPDModeParams: setPDModeParams{
 						{
 							userScreenName: state.NewIdentScreenName("me"),
@@ -352,7 +352,7 @@ func TestPermitDenyService_AddPermListEntries(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					setPDModeParams: setPDModeParams{
 						{
 							userScreenName: state.NewIdentScreenName("me"),
@@ -383,7 +383,7 @@ func TestPermitDenyService_AddPermListEntries(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					setPDModeParams: setPDModeParams{
 						{
 							userScreenName: state.NewIdentScreenName("me"),
@@ -414,15 +414,15 @@ func TestPermitDenyService_AddPermListEntries(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			localBuddyListManager := newMockLocalBuddyListManager(t)
+			clientSideBuddyListManager := newMockClientSideBuddyListManager(t)
 			for _, item := range tt.mockParams.setPDModeParams {
-				localBuddyListManager.EXPECT().
-					SetPDMode(item.userScreenName, item.pdMode).
+				clientSideBuddyListManager.EXPECT().
+					SetPDMode(matchContext(), item.userScreenName, item.pdMode).
 					Return(item.err)
 			}
 			for _, item := range tt.mockParams.permitBuddyParams {
-				localBuddyListManager.EXPECT().
-					PermitBuddy(item.me, item.them).
+				clientSideBuddyListManager.EXPECT().
+					PermitBuddy(matchContext(), item.me, item.them).
 					Return(item.err)
 			}
 			mockBuddyBroadcaster := newMockbuddyBroadcaster(t)
@@ -433,8 +433,8 @@ func TestPermitDenyService_AddPermListEntries(t *testing.T) {
 			}
 
 			svc := PermitDenyService{
-				buddyBroadcaster:      mockBuddyBroadcaster,
-				localBuddyListManager: localBuddyListManager,
+				buddyBroadcaster:           mockBuddyBroadcaster,
+				clientSideBuddyListManager: clientSideBuddyListManager,
 			}
 			err := svc.AddPermListEntries(context.TODO(), tt.sess, tt.bodyIn)
 			assert.Equal(t, tt.wantErr, err)
@@ -478,7 +478,7 @@ func TestPermitDenyService_DelDenyListEntries(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					removeDenyBuddyParams: removeDenyBuddyParams{
 						{
 							me:   state.NewIdentScreenName("me"),
@@ -503,7 +503,7 @@ func TestPermitDenyService_DelDenyListEntries(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					removeDenyBuddyParams: removeDenyBuddyParams{
 						{
 							me:   state.NewIdentScreenName("me"),
@@ -531,10 +531,10 @@ func TestPermitDenyService_DelDenyListEntries(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			localBuddyListManager := newMockLocalBuddyListManager(t)
+			clientSideBuddyListManager := newMockClientSideBuddyListManager(t)
 			for _, item := range tt.mockParams.removeDenyBuddyParams {
-				localBuddyListManager.EXPECT().
-					RemoveDenyBuddy(item.me, item.them).
+				clientSideBuddyListManager.EXPECT().
+					RemoveDenyBuddy(matchContext(), item.me, item.them).
 					Return(item.err)
 			}
 			mockBuddyBroadcaster := newMockbuddyBroadcaster(t)
@@ -545,8 +545,8 @@ func TestPermitDenyService_DelDenyListEntries(t *testing.T) {
 			}
 
 			svc := PermitDenyService{
-				buddyBroadcaster:      mockBuddyBroadcaster,
-				localBuddyListManager: localBuddyListManager,
+				buddyBroadcaster:           mockBuddyBroadcaster,
+				clientSideBuddyListManager: clientSideBuddyListManager,
 			}
 			err := svc.DelDenyListEntries(context.TODO(), tt.sess, tt.bodyIn)
 			assert.Equal(t, tt.wantErr, err)
@@ -590,7 +590,7 @@ func TestPermitDenyService_DelPermListEntries(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					removePermitBuddyParams: removePermitBuddyParams{
 						{
 							me:   state.NewIdentScreenName("me"),
@@ -615,7 +615,7 @@ func TestPermitDenyService_DelPermListEntries(t *testing.T) {
 				},
 			},
 			mockParams: mockParams{
-				localBuddyListManagerParams: localBuddyListManagerParams{
+				clientSideBuddyListManagerParams: clientSideBuddyListManagerParams{
 					removePermitBuddyParams: removePermitBuddyParams{
 						{
 							me:   state.NewIdentScreenName("me"),
@@ -643,10 +643,10 @@ func TestPermitDenyService_DelPermListEntries(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			localBuddyListManager := newMockLocalBuddyListManager(t)
+			clientSideBuddyListManager := newMockClientSideBuddyListManager(t)
 			for _, item := range tt.mockParams.removePermitBuddyParams {
-				localBuddyListManager.EXPECT().
-					RemovePermitBuddy(item.me, item.them).
+				clientSideBuddyListManager.EXPECT().
+					RemovePermitBuddy(matchContext(), item.me, item.them).
 					Return(item.err)
 			}
 			mockBuddyBroadcaster := newMockbuddyBroadcaster(t)
@@ -657,8 +657,8 @@ func TestPermitDenyService_DelPermListEntries(t *testing.T) {
 			}
 
 			svc := PermitDenyService{
-				buddyBroadcaster:      mockBuddyBroadcaster,
-				localBuddyListManager: localBuddyListManager,
+				buddyBroadcaster:           mockBuddyBroadcaster,
+				clientSideBuddyListManager: clientSideBuddyListManager,
 			}
 			err := svc.DelPermListEntries(context.TODO(), tt.sess, tt.bodyIn)
 			assert.Equal(t, tt.wantErr, err)

+ 235 - 73
foodgroup/types.go

@@ -42,33 +42,83 @@ import (
 	"github.com/mk6i/retro-aim-server/wire"
 )
 
+// AccountManager is the interface for managing a user's account settings.
 type AccountManager interface {
-	UpdateDisplayScreenName(displayScreenName state.DisplayScreenName) error
-	UpdateEmailAddress(emailAddress *mail.Address, screenName state.IdentScreenName) error
-	EmailAddressByName(screenName state.IdentScreenName) (*mail.Address, error)
-	UpdateRegStatus(regStatus uint16, screenName state.IdentScreenName) error
-	RegStatusByName(screenName state.IdentScreenName) (uint16, error)
-	UpdateConfirmStatus(confirmStatus bool, screenName state.IdentScreenName) error
-	ConfirmStatusByName(screenName state.IdentScreenName) (bool, error)
-	SetUserPassword(screenName state.IdentScreenName, newPassword string) error
-	User(screenName state.IdentScreenName) (*state.User, error)
-}
+	// ConfirmStatus returns whether a user account has been confirmed.
+	ConfirmStatus(ctx context.Context, screenName state.IdentScreenName) (bool, error)
+
+	// EmailAddress looks up a user's email address by screen name.
+	EmailAddress(ctx context.Context, screenName state.IdentScreenName) (*mail.Address, error)
+
+	// RegStatus looks up a user's registration status by screen name.
+	// It returns one of the following values:
+	//   - wire.AdminInfoRegStatusFullDisclosure
+	//   - wire.AdminInfoRegStatusLimitDisclosure
+	//   - wire.AdminInfoRegStatusNoDisclosure
+	RegStatus(ctx context.Context, screenName state.IdentScreenName) (uint16, error)
+
+	// SetUserPassword sets the user's password hashes and auth key.
+	SetUserPassword(ctx context.Context, screenName state.IdentScreenName, newPassword string) error
+
+	// UpdateConfirmStatus sets whether a user account has been confirmed.
+	UpdateConfirmStatus(ctx context.Context, screenName state.IdentScreenName, confirmStatus bool) error
+
+	// UpdateDisplayScreenName updates the user's display screen name, which is
+	// the screen name visible in the OSCAR client. It derives the user
+	// identifier from the display screen name.
+	UpdateDisplayScreenName(ctx context.Context, displayScreenName state.DisplayScreenName) error
+
+	// UpdateEmailAddress changes a user's email address.
+	UpdateEmailAddress(ctx context.Context, screenName state.IdentScreenName, emailAddress *mail.Address) error
 
-type BARTManager interface {
-	BARTUpsert(itemHash []byte, payload []byte) error
-	BARTRetrieve(itemHash []byte) ([]byte, error)
+	// UpdateRegStatus updates a user's registration status.
+	// The regStatus param can be one of the following values:
+	//   - wire.AdminInfoRegStatusFullDisclosure
+	//   - wire.AdminInfoRegStatusLimitDisclosure
+	//   - wire.AdminInfoRegStatusNoDisclosure
+	UpdateRegStatus(ctx context.Context, screenName state.IdentScreenName, regStatus uint16) error
+
+	// User returns all attributes for a user.
+	User(ctx context.Context, screenName state.IdentScreenName) (*state.User, error)
 }
 
+// buddyBroadcaster defines methods for broadcasting buddy presence and visibility events
+// to other sessions. These events notify users when a buddy comes online, goes offline,
+// or changes visibility status.
 type buddyBroadcaster interface {
+	// BroadcastBuddyArrived notifies all relevant users that the given user has come online.
 	BroadcastBuddyArrived(ctx context.Context, sess *state.Session) error
+
+	// BroadcastBuddyDeparted notifies all relevant users that the given user has gone offline.
 	BroadcastBuddyDeparted(ctx context.Context, sess *state.Session) error
+
+	// BroadcastVisibility sends presence updates to the specified filter list.
+	// If sendDepartures is true, departure events are sent as well.
 	BroadcastVisibility(ctx context.Context, you *state.Session, filter []state.IdentScreenName, sendDepartures bool) error
 }
 
-type BuddyListRetriever interface {
-	AllRelationships(screenName state.IdentScreenName, filter []state.IdentScreenName) ([]state.Relationship, error)
-	BuddyIconRefByName(screenName state.IdentScreenName) (*wire.BARTID, error)
-	Relationship(me state.IdentScreenName, them state.IdentScreenName) (state.Relationship, error)
+// BuddyIconManager is the interface for managing AIM buddy icons.
+type BuddyIconManager interface {
+	// BuddyIcon retrieves a buddy icon image by its md5 hash.
+	BuddyIcon(ctx context.Context, md5 []byte) ([]byte, error)
+
+	// BuddyIconMetadata retrieves a user's buddy icon metadata. It returns nil
+	// if the user does not have a buddy icon.
+	BuddyIconMetadata(ctx context.Context, screenName state.IdentScreenName) (*wire.BARTID, error)
+
+	// SetBuddyIcon creates or updates a buddy icon image and image hash.
+	SetBuddyIcon(ctx context.Context, md5 []byte, image []byte) error
+}
+
+// RelationshipFetcher is the interface for retrieving relationships between users.
+type RelationshipFetcher interface {
+	// AllRelationships retrieves the relationships between the specified user (`me`)
+	// and other users.
+	AllRelationships(ctx context.Context, me state.IdentScreenName, filter []state.IdentScreenName) ([]state.Relationship, error)
+
+	// Relationship retrieves the relationship between the specified user (`me`)
+	// and another user (`them`).
+	Relationship(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName) (state.Relationship, error)
 }
 
 // ChatMessageRelayer defines the interface for sending messages to chat room
@@ -90,21 +140,21 @@ type ChatMessageRelayer interface {
 
 // ChatRoomRegistry defines the interface for storing and retrieving chat
 // rooms in a persistent store. The persistent store has two purposes:
-// - Remember user-created chat rooms (exchange 4) so that clients can
-// reconnect to the rooms following server restarts.
-// - Keep track of public chat room created by the server operator (exchange
-// 5). User's can only join public chat rooms that exist in the room registry.
+//   - Remember user-created chat rooms (exchange 4) so that clients can reconnect
+//     to the rooms following server restarts.
+//   - Keep track of public chat room created by the server operator (exchange 5).
+//     User's can only join public chat rooms that exist in the room registry.
 type ChatRoomRegistry interface {
 	// ChatRoomByCookie looks up a chat room by exchange. Returns
-	// ErrChatRoomNotFound if the room does not exist for cookie.
-	ChatRoomByCookie(chatCookie string) (state.ChatRoom, error)
+	// state.ErrChatRoomNotFound if the room does not exist for cookie.
+	ChatRoomByCookie(ctx context.Context, chatCookie string) (state.ChatRoom, error)
 
 	// ChatRoomByName looks up a chat room by exchange and name. Returns
-	// ErrChatRoomNotFound if the room does not exist for exchange and name.
-	ChatRoomByName(exchange uint16, name string) (state.ChatRoom, error)
+	// state.ErrChatRoomNotFound if the room does not exist for exchange and name.
+	ChatRoomByName(ctx context.Context, exchange uint16, name string) (state.ChatRoom, error)
 
 	// CreateChatRoom creates a new chat room.
-	CreateChatRoom(chatRoom *state.ChatRoom) error
+	CreateChatRoom(ctx context.Context, chatRoom *state.ChatRoom) error
 }
 
 // ChatSessionRegistry defines the interface for adding and removing chat
@@ -120,87 +170,199 @@ type ChatSessionRegistry interface {
 	RemoveSession(sess *state.Session)
 }
 
+// ClientSideBuddyListManager defines operations for managing a user's buddy list,
+// including permissions like allow/deny and buddy group modifications.
+//
+// This interface manages a client-side buddy list that is temporarily copied
+// to the server on a per-session basis. The list is cleared when the user signs out.
+type ClientSideBuddyListManager interface {
+	// AddBuddy adds 'them' to 'me's buddy list.
+	AddBuddy(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName) error
+
+	// DenyBuddy blocks messages and presence visibility from 'them' to 'me'.
+	DenyBuddy(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName) error
+
+	// PermitBuddy allows messages and presence visibility from 'them' to 'me',
+	// potentially overriding deny settings.
+	PermitBuddy(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName) error
+
+	// RemoveBuddy removes 'them' from 'me's buddy list. Does not affect permit/deny status.
+	RemoveBuddy(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName) error
+
+	// RemoveDenyBuddy removes 'them' from 'me's deny list, restoring default
+	// visibility and messaging behavior.
+	RemoveDenyBuddy(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName) error
+
+	// RemovePermitBuddy removes 'them' from 'me's permit list, restoring default
+	// visibility and messaging behavior.
+	RemovePermitBuddy(ctx context.Context, me state.IdentScreenName, them state.IdentScreenName) error
+
+	// SetPDMode sets the permit/deny mode (e.g., allow all, deny all, permit
+	// some) for 'me'. It clears any existing permit/deny records.
+	SetPDMode(ctx context.Context, me state.IdentScreenName, pdMode wire.FeedbagPDMode) error
+}
+
+// CookieBaker defines methods for issuing and verifying AIM authentication tokens ("cookies").
+// These tokens are used for authenticating client sessions with AIM services.
 type CookieBaker interface {
+	// Crack verifies and decodes a previously issued authentication token.
+	// Returns the original payload if the token is valid.
 	Crack(data []byte) ([]byte, error)
+
+	// Issue creates a new authentication token from the given payload.
+	// The resulting token can later be verified using Crack.
 	Issue(data []byte) ([]byte, error)
 }
 
+// FeedbagManager is the interface for reading and modifying server-side buddy
+// lists (feedbag).
 type FeedbagManager interface {
-	Feedbag(screenName state.IdentScreenName) ([]wire.FeedbagItem, error)
-	FeedbagDelete(screenName state.IdentScreenName, items []wire.FeedbagItem) error
-	FeedbagLastModified(screenName state.IdentScreenName) (time.Time, error)
-	FeedbagUpsert(screenName state.IdentScreenName, items []wire.FeedbagItem) error
-	UseFeedbag(user state.IdentScreenName) error
+	// Feedbag fetches the contents of a user's feedbag.
+	Feedbag(ctx context.Context, screenName state.IdentScreenName) ([]wire.FeedbagItem, error)
+
+	// FeedbagDelete deletes an entry from a user's feedbag.
+	FeedbagDelete(ctx context.Context, screenName state.IdentScreenName, items []wire.FeedbagItem) error
+
+	// FeedbagLastModified returns the last time a user's feedbag was updated.
+	FeedbagLastModified(ctx context.Context, screenName state.IdentScreenName) (time.Time, error)
+
+	// FeedbagUpsert upserts an entry to a user's feedbag.
+	FeedbagUpsert(ctx context.Context, screenName state.IdentScreenName, items []wire.FeedbagItem) error
+
+	// UseFeedbag sets the user's session to use feedbag instead of the default
+	// client-side buddy list.
+	UseFeedbag(ctx context.Context, screenName state.IdentScreenName) error
 }
 
+// ICQUserFinder defines methods for searching ICQ users by various attributes.
 type ICQUserFinder interface {
-	// FindByUIN returns a user with a matching UIN.
-	FindByUIN(UIN uint32) (state.User, error)
-	// FindByICQEmail returns a user with a matching email address.
-	FindByICQEmail(email string) (state.User, error)
-	// FindByICQName returns users with matching first name, last name, and
-	// nickname. Empty values are not included in the search parameters.
-	FindByICQName(firstName, lastName, nickName string) ([]state.User, error)
-	// FindByICQInterests returns users who have at least one matching interest
-	// for a given category code.
-	FindByICQInterests(code uint16, keywords []string) ([]state.User, error)
-	// FindByICQKeyword returns users with matching interest keyword across all
-	// interest categories.
-	FindByICQKeyword(keyword string) ([]state.User, error)
+	// FindByUIN returns the user with a matching UIN.
+	FindByUIN(ctx context.Context, UIN uint32) (state.User, error)
+
+	// FindByICQEmail returns the user with a matching ICQ-registered email address.
+	FindByICQEmail(ctx context.Context, email string) (state.User, error)
+
+	// FindByICQName returns users matching the given first name, last name, and/or nickname.
+	// Empty values are ignored and not included in the search criteria.
+	FindByICQName(ctx context.Context, firstName, lastName, nickName string) ([]state.User, error)
+
+	// FindByICQInterests returns users who share at least one keyword under the
+	// specified interest category code.
+	FindByICQInterests(ctx context.Context, code uint16, keywords []string) ([]state.User, error)
+
+	// FindByICQKeyword returns users who have the specified keyword in any interest category.
+	FindByICQKeyword(ctx context.Context, keyword string) ([]state.User, error)
 }
 
+// ICQUserUpdater defines methods for updating various fields of an ICQ user's profile.
 type ICQUserUpdater interface {
-	SetAffiliations(name state.IdentScreenName, data state.ICQAffiliations) error
-	SetBasicInfo(name state.IdentScreenName, data state.ICQBasicInfo) error
-	SetInterests(name state.IdentScreenName, data state.ICQInterests) error
-	SetMoreInfo(name state.IdentScreenName, data state.ICQMoreInfo) error
-	SetUserNotes(name state.IdentScreenName, data state.ICQUserNotes) error
-	SetWorkInfo(name state.IdentScreenName, data state.ICQWorkInfo) error
-}
+	// SetAffiliations updates the user's affiliations, such as memberships in organizations or groups.
+	SetAffiliations(ctx context.Context, name state.IdentScreenName, data state.ICQAffiliations) error
+
+	// SetBasicInfo updates the user's basic profile information.
+	SetBasicInfo(ctx context.Context, name state.IdentScreenName, data state.ICQBasicInfo) error
+
+	// SetInterests updates the user's interests.
+	SetInterests(ctx context.Context, name state.IdentScreenName, data state.ICQInterests) error
+
+	// SetMoreInfo updates additional personal details beyond the basic profile.
+	SetMoreInfo(ctx context.Context, name state.IdentScreenName, data state.ICQMoreInfo) error
+
+	// SetUserNotes updates the user's profile notes.
+	SetUserNotes(ctx context.Context, name state.IdentScreenName, data state.ICQUserNotes) error
 
-type LocalBuddyListManager interface {
-	AddBuddy(me state.IdentScreenName, them state.IdentScreenName) error
-	RemoveBuddy(me state.IdentScreenName, them state.IdentScreenName) error
-	DenyBuddy(me state.IdentScreenName, them state.IdentScreenName) error
-	PermitBuddy(me state.IdentScreenName, them state.IdentScreenName) error
-	RemoveDenyBuddy(me state.IdentScreenName, them state.IdentScreenName) error
-	RemovePermitBuddy(me state.IdentScreenName, them state.IdentScreenName) error
-	SetPDMode(user state.IdentScreenName, pdMode wire.FeedbagPDMode) error
+	// SetWorkInfo updates the user's professional or employment-related details.
+	SetWorkInfo(ctx context.Context, name state.IdentScreenName, data state.ICQWorkInfo) error
 }
 
+// MessageRelayer defines methods for delivering SNAC messages to one or more
+// AIM screen names.
 type MessageRelayer interface {
+	// RelayToScreenNames sends the given SNAC message to all specified screen names.
 	RelayToScreenNames(ctx context.Context, screenNames []state.IdentScreenName, msg wire.SNACMessage)
+
+	// RelayToScreenName sends the given SNAC message to a single screen name.
 	RelayToScreenName(ctx context.Context, screenName state.IdentScreenName, msg wire.SNACMessage)
 }
 
+// OfflineMessageManager defines operations for managing offline messages.
+// These messages are stored temporarily when a recipient is unavailable,
+// and are retrieved once the recipient comes online. Offline messages are
+// available in all ICQ versions and AIM 6+.
 type OfflineMessageManager interface {
-	DeleteMessages(recip state.IdentScreenName) error
-	RetrieveMessages(recip state.IdentScreenName) ([]state.OfflineMessage, error)
-	SaveMessage(offlineMessage state.OfflineMessage) error
+	// DeleteMessages removes all offline messages for the specified recipient.
+	DeleteMessages(ctx context.Context, recip state.IdentScreenName) error
+
+	// RetrieveMessages returns all offline messages for the specified recipient.
+	RetrieveMessages(ctx context.Context, recip state.IdentScreenName) ([]state.OfflineMessage, error)
+
+	// SaveMessage stores a new offline message for delivery when the recipient comes online.
+	SaveMessage(ctx context.Context, offlineMessage state.OfflineMessage) error
 }
 
+// ProfileManager defines methods for managing and querying AIM user profiles,
+// including directory information, interest keywords, and free-form profile content.
 type ProfileManager interface {
-	FindByAIMEmail(email string) (state.User, error)
-	FindByAIMKeyword(keyword string) ([]state.User, error)
-	FindByAIMNameAndAddr(info state.AIMNameAndAddr) ([]state.User, error)
-	InterestList() ([]wire.ODirKeywordListItem, error)
-	Profile(screenName state.IdentScreenName) (string, error)
-	SetDirectoryInfo(name state.IdentScreenName, info state.AIMNameAndAddr) error
-	SetKeywords(name state.IdentScreenName, keywords [5]string) error
-	SetProfile(screenName state.IdentScreenName, body string) error
-	User(screenName state.IdentScreenName) (*state.User, error)
+	// FindByAIMEmail returns the user with the given AIM-associated email address.
+	FindByAIMEmail(ctx context.Context, email string) (state.User, error)
+
+	// FindByAIMKeyword returns users who have the specified keyword in their profile interests.
+	FindByAIMKeyword(ctx context.Context, keyword string) ([]state.User, error)
+
+	// FindByAIMNameAndAddr returns users matching the specified name and address directory info.
+	// Fields left empty in the input are ignored in the query.
+	FindByAIMNameAndAddr(ctx context.Context, info state.AIMNameAndAddr) ([]state.User, error)
+
+	// InterestList returns the list of available interest categories and keywords
+	// that users can associate with their profiles.
+	InterestList(ctx context.Context) ([]wire.ODirKeywordListItem, error)
+
+	// Profile returns the free-form profile body for the given screen name.
+	Profile(ctx context.Context, screenName state.IdentScreenName) (string, error)
+
+	// SetDirectoryInfo updates the user's directory listing with name, city, state, zip, and country info.
+	SetDirectoryInfo(ctx context.Context, screenName state.IdentScreenName, info state.AIMNameAndAddr) error
+
+	// SetKeywords sets up to five interest keywords for the user's profile.
+	SetKeywords(ctx context.Context, screenName state.IdentScreenName, keywords [5]string) error
+
+	// SetProfile sets the free-form profile body content for the user.
+	SetProfile(ctx context.Context, screenName state.IdentScreenName, body string) error
+
+	// User returns the full user record associated with the given screen name.
+	User(ctx context.Context, screenName state.IdentScreenName) (*state.User, error)
 }
 
+// SessionRegistry defines methods for managing active user sessions.
+// It ensures that only one session is active per screen name at any given time.
 type SessionRegistry interface {
+	// AddSession adds a new session to the pool, enforcing a one-session-per-screen-name policy.
+	// If a session for the given screen name is already active, this call blocks until the active
+	// session is removed via [SessionRegistry.RemoveSession] or the context is canceled.
+	//
+	// When multiple concurrent calls are made for the same screen name, only one will succeed;
+	// the others will return an error once the context is done.
 	AddSession(ctx context.Context, screenName state.DisplayScreenName) (*state.Session, error)
+
+	// RemoveSession removes the given session from the registry, allowing future sessions
+	// to be created for the same screen name.
 	RemoveSession(sess *state.Session)
 }
 
+// SessionRetriever defines a method for retrieving an active session
+// associated with a given screen name.
 type SessionRetriever interface {
+	// RetrieveSession returns the session associated with the given screen name,
+	// or nil if no active session exists.
 	RetrieveSession(screenName state.IdentScreenName) *state.Session
 }
 
+// UserManager defines methods for accessing and inserting AIM user records.
 type UserManager interface {
-	User(screenName state.IdentScreenName) (*state.User, error)
-	InsertUser(u state.User) error
+	// InsertUser inserts a new user into the system. Return state.ErrDupUser
+	// if a user with the same screen name already exists.
+	InsertUser(ctx context.Context, u state.User) error
+
+	// User returns the user record associated with the given screen name.
+	User(ctx context.Context, screenName state.IdentScreenName) (*state.User, error)
 }

+ 2 - 2
foodgroup/user_lookup.go

@@ -21,8 +21,8 @@ type UserLookupService struct {
 }
 
 // FindByEmail searches for a user by email address.
-func (s UserLookupService) FindByEmail(_ context.Context, inFrame wire.SNACFrame, inBody wire.SNAC_0x0A_0x02_UserLookupFindByEmail) (wire.SNACMessage, error) {
-	user, err := s.profileManager.FindByAIMEmail(string(inBody.Email))
+func (s UserLookupService) FindByEmail(ctx context.Context, inFrame wire.SNACFrame, inBody wire.SNAC_0x0A_0x02_UserLookupFindByEmail) (wire.SNACMessage, error) {
+	user, err := s.profileManager.FindByAIMEmail(ctx, string(inBody.Email))
 
 	switch {
 	case errors.Is(err, state.ErrNoUser):

+ 3 - 2
foodgroup/user_lookup_test.go

@@ -1,6 +1,7 @@
 package foodgroup
 
 import (
+	"context"
 	"io"
 	"testing"
 
@@ -122,12 +123,12 @@ func TestUserLookupService_FindByEmail(t *testing.T) {
 
 			for _, params := range tc.mockParams.findByAIMEmailParams {
 				profileManager.EXPECT().
-					FindByAIMEmail(params.email).
+					FindByAIMEmail(matchContext(), params.email).
 					Return(params.result, params.err)
 			}
 
 			svc := NewUserLookupService(profileManager)
-			actual, err := svc.FindByEmail(nil, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x0A_0x02_UserLookupFindByEmail))
+			actual, err := svc.FindByEmail(context.Background(), tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x0A_0x02_UserLookupFindByEmail))
 			assert.ErrorIs(t, err, tc.expectErr)
 			assert.Equal(t, tc.expectOutput, actual)
 		})

+ 28 - 18
server/http/test_helpers.go → server/http/helpers_test.go

@@ -1,10 +1,12 @@
 package http
 
 import (
+	"context"
 	"net/mail"
 
 	"github.com/mk6i/retro-aim-server/state"
 	"github.com/mk6i/retro-aim-server/wire"
+	"github.com/stretchr/testify/mock"
 )
 
 type mockParams struct {
@@ -22,31 +24,31 @@ type mockParams struct {
 // accountManagerParams is a helper struct that contains mock parameters for
 // accountManager methods
 type accountManagerParams struct {
-	emailAddressByNameParams
-	regStatusByNameParams
-	confirmStatusByNameParams
+	EmailAddressParams
+	RegStatusParams
+	ConfirmStatusParams
 	updateSuspendedStatusParams
 }
 
-// emailAddressByNameParams is the list of parameters passed at the mock
-// accountManager.EmailAddressByName call site
-type emailAddressByNameParams []struct {
+// EmailAddressParams is the list of parameters passed at the mock
+// accountManager.EmailAddress call site
+type EmailAddressParams []struct {
 	screenName state.IdentScreenName
 	result     *mail.Address
 	err        error
 }
 
-// regStatusByNameParams is the list of parameters passed at the mock
-// accountManager.RegStatusByName call site
-type regStatusByNameParams []struct {
+// RegStatusParams is the list of parameters passed at the mock
+// accountManager.RegStatus call site
+type RegStatusParams []struct {
 	screenName state.IdentScreenName
 	result     uint16
 	err        error
 }
 
-// confirmStatusByNameParams is the list of parameters passed at the mock
-// accountManager.ConfirmStatusByName call site
-type confirmStatusByNameParams []struct {
+// ConfirmStatusParams is the list of parameters passed at the mock
+// accountManager.ConfirmStatus call site
+type ConfirmStatusParams []struct {
 	screenName state.IdentScreenName
 	result     bool
 	err        error
@@ -61,13 +63,13 @@ type updateSuspendedStatusParams []struct {
 }
 
 // bartRetrieverParams is a helper struct that contains mock parameters for
-// BARTRetriever methods
+// BuddyIconRetriever methods
 type bartRetrieverParams struct {
 	bartRetrieveParams
 }
 
 // bartRetrieveParams is the list of parameters passed at the mock
-// BARTRetriever.BARTRetrieveParams call site
+// BuddyIconRetriever.BuddyIconParams call site
 type bartRetrieveParams []struct {
 	itemHash []byte
 	result   []byte
@@ -159,12 +161,12 @@ type keywordsByCategoryParams []struct {
 // feedBagRetrieverParams is a helper struct that contains mock parameters for
 // FeedBagRetriever methods
 type feedBagRetrieverParams struct {
-	buddyIconRefByNameParams
+	buddyIconMetadataParams
 }
 
-// buddyIconRefByNameParams is the list of parameters passed at the mock
-// FeedBagRetriever.BuddyIconRefByNameParams call site
-type buddyIconRefByNameParams []struct {
+// buddyIconMetadataParams is the list of parameters passed at the mock
+// FeedBagRetriever.BuddyIconMetadataParams call site
+type buddyIconMetadataParams []struct {
 	screenName state.IdentScreenName
 	result     *wire.BARTID
 	err        error
@@ -250,3 +252,11 @@ type setUserPasswordParams []struct {
 	newPassword string
 	err         error
 }
+
+// matchContext matches any instance of Context interface.
+func matchContext() interface{} {
+	return mock.MatchedBy(func(ctx any) bool {
+		_, ok := ctx.(context.Context)
+		return ok
+	})
+}

+ 32 - 32
server/http/mgmt_api.go

@@ -31,7 +31,7 @@ func NewManagementAPI(
 	chatSessionRetriever ChatSessionRetriever,
 	directoryManager DirectoryManager,
 	messageRelayer MessageRelayer,
-	bartRetriever BARTRetriever,
+	bartRetriever BuddyIconRetriever,
 	feedbagRetriever FeedBagRetriever,
 	accountManager AccountManager,
 	profileRetriever ProfileRetriever,
@@ -44,7 +44,7 @@ func NewManagementAPI(
 		deleteUserHandler(w, r, userManager, logger)
 	})
 	mux.HandleFunc("GET /user", func(w http.ResponseWriter, r *http.Request) {
-		getUserHandler(w, userManager, logger)
+		getUserHandler(w, r, userManager, logger)
 	})
 	mux.HandleFunc("POST /user", func(w http.ResponseWriter, r *http.Request) {
 		postUserHandler(w, r, userManager, uuid.New, logger)
@@ -111,7 +111,7 @@ func NewManagementAPI(
 
 	// Handlers for '/directory/category' route
 	mux.HandleFunc("GET /directory/category", func(w http.ResponseWriter, r *http.Request) {
-		getDirectoryCategoryHandler(w, directoryManager, logger)
+		getDirectoryCategoryHandler(w, r, directoryManager, logger)
 	})
 	mux.HandleFunc("POST /directory/category", func(w http.ResponseWriter, r *http.Request) {
 		postDirectoryCategoryHandler(w, r, directoryManager, logger)
@@ -185,7 +185,7 @@ func deleteUserHandler(w http.ResponseWriter, r *http.Request, manager UserManag
 		return
 	}
 
-	err = manager.DeleteUser(state.NewIdentScreenName(user.ScreenName))
+	err = manager.DeleteUser(r.Context(), state.NewIdentScreenName(user.ScreenName))
 	switch {
 	case errors.Is(err, state.ErrNoUser):
 		http.Error(w, "user does not exist", http.StatusNotFound)
@@ -210,7 +210,7 @@ func putUserPasswordHandler(w http.ResponseWriter, r *http.Request, userManager
 
 	sn := state.NewIdentScreenName(input.ScreenName)
 
-	if err := userManager.SetUserPassword(sn, input.Password); err != nil {
+	if err := userManager.SetUserPassword(r.Context(), sn, input.Password); err != nil {
 		switch {
 		case errors.Is(err, state.ErrNoUser):
 			http.Error(w, "user does not exist", http.StatusNotFound)
@@ -297,10 +297,10 @@ func deleteSessionHandler(w http.ResponseWriter, r *http.Request, sessionRetriev
 }
 
 // getUserHandler handles the GET /user endpoint.
-func getUserHandler(w http.ResponseWriter, userManager UserManager, logger *slog.Logger) {
+func getUserHandler(w http.ResponseWriter, r *http.Request, userManager UserManager, logger *slog.Logger) {
 	w.Header().Set("Content-Type", "application/json")
 
-	users, err := userManager.AllUsers()
+	users, err := userManager.AllUsers(r.Context())
 	if err != nil {
 		logger.Error("error in GET /user", "err", err.Error())
 		http.Error(w, "internal server error", http.StatusInternalServerError)
@@ -363,7 +363,7 @@ func postUserHandler(w http.ResponseWriter, r *http.Request, userManager UserMan
 		return
 	}
 
-	err = userManager.InsertUser(user)
+	err = userManager.InsertUser(r.Context(), user)
 	switch {
 	case errors.Is(err, state.ErrDupUser):
 		http.Error(w, "user already exists", http.StatusConflict)
@@ -421,7 +421,7 @@ func getUserLoginHandler(w http.ResponseWriter, r *http.Request, userManager Use
 
 	username, password := state.NewIdentScreenName(pair[0]), pair[1]
 
-	user, err := userManager.User(username)
+	user, err := userManager.User(r.Context(), username)
 	if err != nil {
 		w.WriteHeader(http.StatusInternalServerError)
 		_, _ = w.Write([]byte("500 InternalServerError\n"))
@@ -440,9 +440,9 @@ func getUserLoginHandler(w http.ResponseWriter, r *http.Request, userManager Use
 }
 
 // getPublicChatHandler handles the GET /chat/room/public endpoint.
-func getPublicChatHandler(w http.ResponseWriter, _ *http.Request, chatRoomRetriever ChatRoomRetriever, chatSessionRetriever ChatSessionRetriever, logger *slog.Logger) {
+func getPublicChatHandler(w http.ResponseWriter, r *http.Request, chatRoomRetriever ChatRoomRetriever, chatSessionRetriever ChatSessionRetriever, logger *slog.Logger) {
 	w.Header().Set("Content-Type", "application/json")
-	rooms, err := chatRoomRetriever.AllChatRooms(state.PublicExchange)
+	rooms, err := chatRoomRetriever.AllChatRooms(r.Context(), state.PublicExchange)
 	if err != nil {
 		logger.Error("error in GET /chat/rooms/public", "err", err.Error())
 		http.Error(w, "internal server error", http.StatusInternalServerError)
@@ -487,7 +487,7 @@ func postPublicChatHandler(w http.ResponseWriter, r *http.Request, chatRoomCreat
 
 	cr := state.NewChatRoom(input.Name, state.NewIdentScreenName("system"), state.PublicExchange)
 
-	err := chatRoomCreator.CreateChatRoom(&cr)
+	err := chatRoomCreator.CreateChatRoom(r.Context(), &cr)
 	switch {
 	case errors.Is(err, state.ErrDupChatRoom):
 		http.Error(w, "Chat room already exists.", http.StatusConflict)
@@ -503,9 +503,9 @@ func postPublicChatHandler(w http.ResponseWriter, r *http.Request, chatRoomCreat
 }
 
 // getPrivateChatHandler handles the GET /chat/room/private endpoint.
-func getPrivateChatHandler(w http.ResponseWriter, _ *http.Request, chatRoomRetriever ChatRoomRetriever, chatSessionRetriever ChatSessionRetriever, logger *slog.Logger) {
+func getPrivateChatHandler(w http.ResponseWriter, r *http.Request, chatRoomRetriever ChatRoomRetriever, chatSessionRetriever ChatSessionRetriever, logger *slog.Logger) {
 	w.Header().Set("Content-Type", "application/json")
-	rooms, err := chatRoomRetriever.AllChatRooms(state.PrivateExchange)
+	rooms, err := chatRoomRetriever.AllChatRooms(r.Context(), state.PrivateExchange)
 	if err != nil {
 		logger.Error("error in GET /chat/rooms/private", "err", err.Error())
 		http.Error(w, "internal server error", http.StatusInternalServerError)
@@ -596,9 +596,9 @@ func postInstantMessageHandler(w http.ResponseWriter, r *http.Request, messageRe
 }
 
 // getUserBuddyIconHandler handles the GET /user/{screenname}/icon endpoint.
-func getUserBuddyIconHandler(w http.ResponseWriter, r *http.Request, u UserManager, f FeedBagRetriever, b BARTRetriever, logger *slog.Logger) {
+func getUserBuddyIconHandler(w http.ResponseWriter, r *http.Request, u UserManager, f FeedBagRetriever, b BuddyIconRetriever, logger *slog.Logger) {
 	screenName := state.NewIdentScreenName(r.PathValue("screenname"))
-	user, err := u.User(screenName)
+	user, err := u.User(r.Context(), screenName)
 	if err != nil {
 		logger.Error("error retrieving user", "err", err.Error())
 		http.Error(w, "internal server error", http.StatusInternalServerError)
@@ -608,7 +608,7 @@ func getUserBuddyIconHandler(w http.ResponseWriter, r *http.Request, u UserManag
 		http.Error(w, "user not found", http.StatusNotFound)
 		return
 	}
-	iconRef, err := f.BuddyIconRefByName(screenName)
+	iconRef, err := f.BuddyIconMetadata(r.Context(), screenName)
 	if err != nil {
 		logger.Error("error retrieving buddy icon ref", "err", err.Error())
 		http.Error(w, "internal server error", http.StatusInternalServerError)
@@ -618,7 +618,7 @@ func getUserBuddyIconHandler(w http.ResponseWriter, r *http.Request, u UserManag
 		http.Error(w, "icon not found", http.StatusNotFound)
 		return
 	}
-	icon, err := b.BARTRetrieve(iconRef.Hash)
+	icon, err := b.BuddyIcon(r.Context(), iconRef.Hash)
 	if err != nil {
 		logger.Error("error retrieving buddy icon bart item", "err", err.Error())
 		http.Error(w, "internal server error", http.StatusInternalServerError)
@@ -633,7 +633,7 @@ func getUserAccountHandler(w http.ResponseWriter, r *http.Request, userManager U
 	w.Header().Set("Content-Type", "application/json")
 
 	screenName := r.PathValue("screenname")
-	user, err := userManager.User(state.NewIdentScreenName(screenName))
+	user, err := userManager.User(r.Context(), state.NewIdentScreenName(screenName))
 	if err != nil {
 		logger.Error("error in GET /user/{screenname}/account", "err", err.Error())
 		http.Error(w, "internal server error", http.StatusInternalServerError)
@@ -645,25 +645,25 @@ func getUserAccountHandler(w http.ResponseWriter, r *http.Request, userManager U
 	}
 
 	emailAddress := ""
-	email, err := a.EmailAddressByName(user.IdentScreenName)
+	email, err := a.EmailAddress(r.Context(), user.IdentScreenName)
 	if err != nil {
 		emailAddress = ""
 	} else {
 		emailAddress = email.String()
 	}
-	regStatus, err := a.RegStatusByName(user.IdentScreenName)
+	regStatus, err := a.RegStatus(r.Context(), user.IdentScreenName)
 	if err != nil {
 		logger.Error("error in GET /user/*/account RegStatus", "err", err.Error())
 		http.Error(w, "internal server error", http.StatusInternalServerError)
 		return
 	}
-	confirmStatus, err := a.ConfirmStatusByName(user.IdentScreenName)
+	confirmStatus, err := a.ConfirmStatus(r.Context(), user.IdentScreenName)
 	if err != nil {
 		logger.Error("error in GET /user/*/account ConfirmStatus", "err", err.Error())
 		http.Error(w, "internal server error", http.StatusInternalServerError)
 		return
 	}
-	profile, err := p.Profile(user.IdentScreenName)
+	profile, err := p.Profile(r.Context(), user.IdentScreenName)
 	if err != nil {
 		logger.Error("error in GET /user/*/account Profile", "err", err.Error())
 		http.Error(w, "internal server error", http.StatusInternalServerError)
@@ -697,7 +697,7 @@ func patchUserAccountHandler(w http.ResponseWriter, r *http.Request, userManager
 	w.Header().Set("Content-Type", "application/json")
 
 	screenName := r.PathValue("screenname")
-	user, err := userManager.User(state.NewIdentScreenName(screenName))
+	user, err := userManager.User(r.Context(), state.NewIdentScreenName(screenName))
 	if err != nil {
 		logger.Error("error in PATCH /user/{screenname}/account", "err", err.Error())
 		http.Error(w, "internal server error", http.StatusInternalServerError)
@@ -729,7 +729,7 @@ func patchUserAccountHandler(w http.ResponseWriter, r *http.Request, userManager
 				return
 			}
 			if suspendedStatus != user.SuspendedStatus {
-				err := a.UpdateSuspendedStatus(suspendedStatus, user.IdentScreenName)
+				err := a.UpdateSuspendedStatus(r.Context(), suspendedStatus, user.IdentScreenName)
 				if err != nil {
 					logger.Error("error in PATCH /user/{screenname}/account", "err", err.Error())
 					http.Error(w, "internal server error", http.StatusInternalServerError)
@@ -794,9 +794,9 @@ func getVersionHandler(w http.ResponseWriter, bld config.Build) {
 }
 
 // getDirectoryCategoryHandler handles the GET /directory/category endpoint.
-func getDirectoryCategoryHandler(w http.ResponseWriter, manager DirectoryManager, logger *slog.Logger) {
+func getDirectoryCategoryHandler(w http.ResponseWriter, r *http.Request, manager DirectoryManager, logger *slog.Logger) {
 	w.Header().Set("Content-Type", "application/json")
-	categories, err := manager.Categories()
+	categories, err := manager.Categories(r.Context())
 	if err != nil {
 		logger.Error("error in GET /directory/category", "err", err.Error())
 		errorMsg(w, "internal server error", http.StatusInternalServerError)
@@ -824,7 +824,7 @@ func postDirectoryCategoryHandler(w http.ResponseWriter, r *http.Request, manage
 		return
 	}
 
-	category, err := manager.CreateCategory(input.Name)
+	category, err := manager.CreateCategory(r.Context(), input.Name)
 	if err != nil {
 		if errors.Is(err, state.ErrKeywordCategoryExists) {
 			errorMsg(w, "category already exists", http.StatusConflict)
@@ -853,7 +853,7 @@ func deleteDirectoryCategoryHandler(w http.ResponseWriter, r *http.Request, mana
 		return
 	}
 
-	if err := manager.DeleteCategory(uint8(categoryID)); err != nil {
+	if err := manager.DeleteCategory(r.Context(), uint8(categoryID)); err != nil {
 		switch {
 		case errors.Is(err, state.ErrKeywordCategoryNotFound):
 			errorMsg(w, "category not found", http.StatusNotFound)
@@ -881,7 +881,7 @@ func getDirectoryCategoryKeywordHandler(w http.ResponseWriter, r *http.Request,
 		return
 	}
 
-	categories, err := manager.KeywordsByCategory(uint8(categoryID))
+	categories, err := manager.KeywordsByCategory(r.Context(), uint8(categoryID))
 	if err != nil {
 		if errors.Is(err, state.ErrKeywordCategoryNotFound) {
 			errorMsg(w, "category not found", http.StatusNotFound)
@@ -915,7 +915,7 @@ func postDirectoryKeywordHandler(w http.ResponseWriter, r *http.Request, manager
 		return
 	}
 
-	kw, err := manager.CreateKeyword(input.Name, input.CategoryID)
+	kw, err := manager.CreateKeyword(r.Context(), input.Name, input.CategoryID)
 	if err != nil {
 		switch {
 		case errors.Is(err, state.ErrKeywordCategoryNotFound):
@@ -950,7 +950,7 @@ func deleteDirectoryKeywordHandler(w http.ResponseWriter, r *http.Request, manag
 		return
 	}
 
-	if err := manager.DeleteKeyword(uint8(keywordID)); err != nil {
+	if err := manager.DeleteKeyword(r.Context(), uint8(keywordID)); err != nil {
 		switch {
 		case errors.Is(err, state.ErrKeywordInUse):
 			errorMsg(w, "can't delete because category in use by a user", http.StatusConflict)

+ 42 - 40
server/http/mgmt_api_test.go

@@ -292,7 +292,7 @@ func TestUserAccountHandler_GET(t *testing.T) {
 					},
 				},
 				accountManagerParams: accountManagerParams{
-					emailAddressByNameParams: emailAddressByNameParams{
+					EmailAddressParams: EmailAddressParams{
 						{
 							screenName: state.NewIdentScreenName("userA"),
 							result: &mail.Address{
@@ -300,13 +300,13 @@ func TestUserAccountHandler_GET(t *testing.T) {
 							},
 						},
 					},
-					regStatusByNameParams: regStatusByNameParams{
+					RegStatusParams: RegStatusParams{
 						{
 							screenName: state.NewIdentScreenName("userA"),
 							result:     uint16(0x02),
 						},
 					},
-					confirmStatusByNameParams: confirmStatusByNameParams{
+					ConfirmStatusParams: ConfirmStatusParams{
 						{
 							screenName: state.NewIdentScreenName("userA"),
 							result:     true,
@@ -342,7 +342,7 @@ func TestUserAccountHandler_GET(t *testing.T) {
 					},
 				},
 				accountManagerParams: accountManagerParams{
-					emailAddressByNameParams: emailAddressByNameParams{
+					EmailAddressParams: EmailAddressParams{
 						{
 							screenName: state.NewIdentScreenName("userB"),
 							result: &mail.Address{
@@ -350,13 +350,13 @@ func TestUserAccountHandler_GET(t *testing.T) {
 							},
 						},
 					},
-					regStatusByNameParams: regStatusByNameParams{
+					RegStatusParams: RegStatusParams{
 						{
 							screenName: state.NewIdentScreenName("userB"),
 							result:     uint16(0x02),
 						},
 					},
-					confirmStatusByNameParams: confirmStatusByNameParams{
+					ConfirmStatusParams: ConfirmStatusParams{
 						{
 							screenName: state.NewIdentScreenName("userB"),
 							result:     true,
@@ -384,31 +384,31 @@ func TestUserAccountHandler_GET(t *testing.T) {
 			userManager := newMockUserManager(t)
 			for _, params := range tc.mockParams.userManagerParams.getUserParams {
 				userManager.EXPECT().
-					User(params.screenName).
+					User(matchContext(), params.screenName).
 					Return(params.result, params.err)
 			}
 
 			accountManager := newMockAccountManager(t)
-			for _, params := range tc.mockParams.accountManagerParams.emailAddressByNameParams {
+			for _, params := range tc.mockParams.accountManagerParams.EmailAddressParams {
 				accountManager.EXPECT().
-					EmailAddressByName(params.screenName).
+					EmailAddress(matchContext(), params.screenName).
 					Return(params.result, params.err)
 			}
-			for _, params := range tc.mockParams.accountManagerParams.regStatusByNameParams {
+			for _, params := range tc.mockParams.accountManagerParams.RegStatusParams {
 				accountManager.EXPECT().
-					RegStatusByName(params.screenName).
+					RegStatus(matchContext(), params.screenName).
 					Return(params.result, params.err)
 			}
-			for _, params := range tc.mockParams.accountManagerParams.confirmStatusByNameParams {
+			for _, params := range tc.mockParams.accountManagerParams.ConfirmStatusParams {
 				accountManager.EXPECT().
-					ConfirmStatusByName(params.screenName).
+					ConfirmStatus(matchContext(), params.screenName).
 					Return(params.result, params.err)
 			}
 
 			profileRetriever := newMockProfileRetriever(t)
 			for _, params := range tc.mockParams.profileRetrieverParams.retrieveProfileParams {
 				profileRetriever.EXPECT().
-					Profile(params.screenName).
+					Profile(matchContext(), params.screenName).
 					Return(params.result, params.err)
 			}
 
@@ -557,14 +557,14 @@ func TestUserAccountHandler_PATCH(t *testing.T) {
 			userManager := newMockUserManager(t)
 			for _, params := range tc.mockParams.userManagerParams.getUserParams {
 				userManager.EXPECT().
-					User(params.screenName).
+					User(matchContext(), params.screenName).
 					Return(params.result, params.err)
 			}
 
 			accountManager := newMockAccountManager(t)
 			for _, params := range tc.mockParams.accountManagerParams.updateSuspendedStatusParams {
 				accountManager.EXPECT().
-					UpdateSuspendedStatus(params.suspendedStatus, params.screenName).
+					UpdateSuspendedStatus(matchContext(), params.suspendedStatus, params.screenName).
 					Return(params.err)
 			}
 
@@ -632,7 +632,7 @@ func TestUserBuddyIconHandler_GET(t *testing.T) {
 					},
 				},
 				feedBagRetrieverParams: feedBagRetrieverParams{
-					buddyIconRefByNameParams: buddyIconRefByNameParams{
+					buddyIconMetadataParams: buddyIconMetadataParams{
 						{
 							screenName: state.NewIdentScreenName("userA"),
 							result: &wire.BARTID{
@@ -674,7 +674,7 @@ func TestUserBuddyIconHandler_GET(t *testing.T) {
 					},
 				},
 				feedBagRetrieverParams: feedBagRetrieverParams{
-					buddyIconRefByNameParams: buddyIconRefByNameParams{
+					buddyIconMetadataParams: buddyIconMetadataParams{
 						{
 							screenName: state.NewIdentScreenName("userA"),
 							result: &wire.BARTID{
@@ -716,7 +716,7 @@ func TestUserBuddyIconHandler_GET(t *testing.T) {
 					},
 				},
 				feedBagRetrieverParams: feedBagRetrieverParams{
-					buddyIconRefByNameParams: buddyIconRefByNameParams{
+					buddyIconMetadataParams: buddyIconMetadataParams{
 						{
 							screenName: state.NewIdentScreenName("userA"),
 							result: &wire.BARTID{
@@ -758,7 +758,7 @@ func TestUserBuddyIconHandler_GET(t *testing.T) {
 					},
 				},
 				feedBagRetrieverParams: feedBagRetrieverParams{
-					buddyIconRefByNameParams: buddyIconRefByNameParams{
+					buddyIconMetadataParams: buddyIconMetadataParams{
 						{
 							screenName: state.NewIdentScreenName("userA"),
 							result: &wire.BARTID{
@@ -792,7 +792,7 @@ func TestUserBuddyIconHandler_GET(t *testing.T) {
 					},
 				},
 				feedBagRetrieverParams: feedBagRetrieverParams{
-					buddyIconRefByNameParams: buddyIconRefByNameParams{
+					buddyIconMetadataParams: buddyIconMetadataParams{
 						{
 							screenName: state.NewIdentScreenName("userA"),
 							result:     nil,
@@ -812,21 +812,21 @@ func TestUserBuddyIconHandler_GET(t *testing.T) {
 			userManager := newMockUserManager(t)
 			for _, params := range tc.mockParams.userManagerParams.getUserParams {
 				userManager.EXPECT().
-					User(params.screenName).
+					User(matchContext(), params.screenName).
 					Return(params.result, params.err)
 			}
 
 			feedbagRetriever := newMockFeedBagRetriever(t)
-			for _, params := range tc.mockParams.feedBagRetrieverParams.buddyIconRefByNameParams {
+			for _, params := range tc.mockParams.feedBagRetrieverParams.buddyIconMetadataParams {
 				feedbagRetriever.EXPECT().
-					BuddyIconRefByName(params.screenName).
+					BuddyIconMetadata(matchContext(), params.screenName).
 					Return(params.result, params.err)
 			}
 
-			bartRetriever := newMockBARTRetriever(t)
+			bartRetriever := newMockBuddyIconRetriever(t)
 			for _, params := range tc.mockParams.bartRetrieverParams.bartRetrieveParams {
 				bartRetriever.EXPECT().
-					BARTRetrieve(params.itemHash).
+					BuddyIcon(matchContext(), params.itemHash).
 					Return(params.result, params.err)
 			}
 
@@ -916,16 +916,17 @@ func TestUserHandler_GET(t *testing.T) {
 
 	for _, tc := range tt {
 		t.Run(tc.name, func(t *testing.T) {
+			request := httptest.NewRequest(http.MethodGet, "/user", nil)
 			responseRecorder := httptest.NewRecorder()
 
 			userManager := newMockUserManager(t)
 			for _, params := range tc.mockParams.userManagerParams.allUsersParams {
 				userManager.EXPECT().
-					AllUsers().
+					AllUsers(matchContext()).
 					Return(params.result, params.err)
 			}
 
-			getUserHandler(responseRecorder, userManager, slog.Default())
+			getUserHandler(responseRecorder, request, userManager, slog.Default())
 
 			if responseRecorder.Code != tc.statusCode {
 				t.Errorf("Want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)
@@ -1083,7 +1084,7 @@ func TestUserHandler_POST(t *testing.T) {
 			for _, params := range tc.mockParams.userManagerParams.insertUserParams {
 				assert.NoError(t, params.u.HashPassword(tc.password))
 				userManager.EXPECT().
-					InsertUser(params.u).
+					InsertUser(matchContext(), params.u).
 					Return(params.err)
 			}
 
@@ -1172,7 +1173,7 @@ func TestUserHandler_DELETE(t *testing.T) {
 			userManager := newMockUserManager(t)
 			for _, params := range tc.mockParams.userManagerParams.deleteUserParams {
 				userManager.EXPECT().
-					DeleteUser(params.screenName).
+					DeleteUser(matchContext(), params.screenName).
 					Return(params.err)
 			}
 
@@ -1280,7 +1281,7 @@ func TestUserPasswordHandler_PUT(t *testing.T) {
 			userManager := newMockUserManager(t)
 			for _, params := range tc.mockParams.userManagerParams.setUserPasswordParams {
 				userManager.EXPECT().
-					SetUserPassword(params.screenName, params.newPassword).
+					SetUserPassword(matchContext(), params.screenName, params.newPassword).
 					Return(params.err)
 			}
 
@@ -1400,7 +1401,7 @@ func TestPublicChatHandler_GET(t *testing.T) {
 			chatRoomRetriever := newMockChatRoomRetriever(t)
 			for _, params := range tc.mockParams.chatRoomRetrieverParams.allChatRoomsParams {
 				chatRoomRetriever.EXPECT().
-					AllChatRooms(params.exchange).
+					AllChatRooms(matchContext(), params.exchange).
 					Return(params.result, params.err)
 			}
 
@@ -1527,7 +1528,7 @@ func TestPrivateChatHandler_GET(t *testing.T) {
 			chatRoomRetriever := newMockChatRoomRetriever(t)
 			for _, params := range tc.mockParams.chatRoomRetrieverParams.allChatRoomsParams {
 				chatRoomRetriever.EXPECT().
-					AllChatRooms(params.exchange).
+					AllChatRooms(matchContext(), params.exchange).
 					Return(params.result, params.err)
 			}
 
@@ -1723,15 +1724,16 @@ func TestDirectoryCategoryHandler_GET(t *testing.T) {
 	for _, tc := range tt {
 		t.Run(tc.name, func(t *testing.T) {
 			responseRecorder := httptest.NewRecorder()
+			request := httptest.NewRequest(http.MethodGet, "/directory/category", nil)
 
 			directoryManager := newMockDirectoryManager(t)
 			for _, params := range tc.mockParams.categoriesParams {
 				directoryManager.EXPECT().
-					Categories().
+					Categories(matchContext()).
 					Return(params.result, params.err)
 			}
 
-			getDirectoryCategoryHandler(responseRecorder, directoryManager, slog.Default())
+			getDirectoryCategoryHandler(responseRecorder, request, directoryManager, slog.Default())
 
 			if responseRecorder.Code != tc.statusCode {
 				t.Errorf("Want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)
@@ -1849,7 +1851,7 @@ func TestDirectoryCategoryKeywordHandler_GET(t *testing.T) {
 			directoryManager := newMockDirectoryManager(t)
 			for _, params := range tc.mockParams.keywordsByCategoryParams {
 				directoryManager.EXPECT().
-					KeywordsByCategory(params.categoryID).
+					KeywordsByCategory(matchContext(), params.categoryID).
 					Return(params.result, params.err)
 			}
 
@@ -1959,7 +1961,7 @@ func TestDirectoryCategoryHandler_DELETE(t *testing.T) {
 			directoryManager := newMockDirectoryManager(t)
 			for _, params := range tc.mockParams.deleteCategoryParams {
 				directoryManager.EXPECT().
-					DeleteCategory(params.categoryID).
+					DeleteCategory(matchContext(), params.categoryID).
 					Return(params.err)
 			}
 
@@ -2056,7 +2058,7 @@ func TestDirectoryCategoryHandler_POST(t *testing.T) {
 			directoryManager := newMockDirectoryManager(t)
 			for _, params := range tc.mockParams.createCategoryParams {
 				directoryManager.EXPECT().
-					CreateCategory(params.name).
+					CreateCategory(matchContext(), params.name).
 					Return(params.result, params.err)
 			}
 
@@ -2173,7 +2175,7 @@ func TestDirectoryKeywordHandler_POST(t *testing.T) {
 			directoryManager := newMockDirectoryManager(t)
 			for _, params := range tc.mockParams.createKeywordParams {
 				directoryManager.EXPECT().
-					CreateKeyword(params.name, params.categoryID).
+					CreateKeyword(matchContext(), params.name, params.categoryID).
 					Return(params.result, params.err)
 			}
 
@@ -2283,7 +2285,7 @@ func TestDirectoryKeywordHandler_DELETE(t *testing.T) {
 			directoryManager := newMockDirectoryManager(t)
 			for _, params := range tc.mockParams.deleteKeywordParams {
 				directoryManager.EXPECT().
-					DeleteKeyword(params.id).
+					DeleteKeyword(matchContext(), params.id).
 					Return(params.err)
 			}
 

+ 0 - 254
server/http/mock_AccountManager.go

@@ -1,254 +0,0 @@
-// Code generated by mockery v2.52.1. DO NOT EDIT.
-
-package http
-
-import (
-	mail "net/mail"
-
-	state "github.com/mk6i/retro-aim-server/state"
-	mock "github.com/stretchr/testify/mock"
-)
-
-// mockAccountManager is an autogenerated mock type for the AccountManager type
-type mockAccountManager struct {
-	mock.Mock
-}
-
-type mockAccountManager_Expecter struct {
-	mock *mock.Mock
-}
-
-func (_m *mockAccountManager) EXPECT() *mockAccountManager_Expecter {
-	return &mockAccountManager_Expecter{mock: &_m.Mock}
-}
-
-// ConfirmStatusByName provides a mock function with given fields: screenName
-func (_m *mockAccountManager) ConfirmStatusByName(screenName state.IdentScreenName) (bool, error) {
-	ret := _m.Called(screenName)
-
-	if len(ret) == 0 {
-		panic("no return value specified for ConfirmStatusByName")
-	}
-
-	var r0 bool
-	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (bool, error)); ok {
-		return rf(screenName)
-	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) bool); ok {
-		r0 = rf(screenName)
-	} else {
-		r0 = ret.Get(0).(bool)
-	}
-
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
-	} else {
-		r1 = ret.Error(1)
-	}
-
-	return r0, r1
-}
-
-// mockAccountManager_ConfirmStatusByName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConfirmStatusByName'
-type mockAccountManager_ConfirmStatusByName_Call struct {
-	*mock.Call
-}
-
-// ConfirmStatusByName is a helper method to define mock.On call
-//   - screenName state.IdentScreenName
-func (_e *mockAccountManager_Expecter) ConfirmStatusByName(screenName interface{}) *mockAccountManager_ConfirmStatusByName_Call {
-	return &mockAccountManager_ConfirmStatusByName_Call{Call: _e.mock.On("ConfirmStatusByName", screenName)}
-}
-
-func (_c *mockAccountManager_ConfirmStatusByName_Call) Run(run func(screenName state.IdentScreenName)) *mockAccountManager_ConfirmStatusByName_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
-	})
-	return _c
-}
-
-func (_c *mockAccountManager_ConfirmStatusByName_Call) Return(_a0 bool, _a1 error) *mockAccountManager_ConfirmStatusByName_Call {
-	_c.Call.Return(_a0, _a1)
-	return _c
-}
-
-func (_c *mockAccountManager_ConfirmStatusByName_Call) RunAndReturn(run func(state.IdentScreenName) (bool, error)) *mockAccountManager_ConfirmStatusByName_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// EmailAddressByName provides a mock function with given fields: screenName
-func (_m *mockAccountManager) EmailAddressByName(screenName state.IdentScreenName) (*mail.Address, error) {
-	ret := _m.Called(screenName)
-
-	if len(ret) == 0 {
-		panic("no return value specified for EmailAddressByName")
-	}
-
-	var r0 *mail.Address
-	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (*mail.Address, error)); ok {
-		return rf(screenName)
-	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) *mail.Address); ok {
-		r0 = rf(screenName)
-	} else {
-		if ret.Get(0) != nil {
-			r0 = ret.Get(0).(*mail.Address)
-		}
-	}
-
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
-	} else {
-		r1 = ret.Error(1)
-	}
-
-	return r0, r1
-}
-
-// mockAccountManager_EmailAddressByName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EmailAddressByName'
-type mockAccountManager_EmailAddressByName_Call struct {
-	*mock.Call
-}
-
-// EmailAddressByName is a helper method to define mock.On call
-//   - screenName state.IdentScreenName
-func (_e *mockAccountManager_Expecter) EmailAddressByName(screenName interface{}) *mockAccountManager_EmailAddressByName_Call {
-	return &mockAccountManager_EmailAddressByName_Call{Call: _e.mock.On("EmailAddressByName", screenName)}
-}
-
-func (_c *mockAccountManager_EmailAddressByName_Call) Run(run func(screenName state.IdentScreenName)) *mockAccountManager_EmailAddressByName_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
-	})
-	return _c
-}
-
-func (_c *mockAccountManager_EmailAddressByName_Call) Return(_a0 *mail.Address, _a1 error) *mockAccountManager_EmailAddressByName_Call {
-	_c.Call.Return(_a0, _a1)
-	return _c
-}
-
-func (_c *mockAccountManager_EmailAddressByName_Call) RunAndReturn(run func(state.IdentScreenName) (*mail.Address, error)) *mockAccountManager_EmailAddressByName_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// RegStatusByName provides a mock function with given fields: screenName
-func (_m *mockAccountManager) RegStatusByName(screenName state.IdentScreenName) (uint16, error) {
-	ret := _m.Called(screenName)
-
-	if len(ret) == 0 {
-		panic("no return value specified for RegStatusByName")
-	}
-
-	var r0 uint16
-	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (uint16, error)); ok {
-		return rf(screenName)
-	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) uint16); ok {
-		r0 = rf(screenName)
-	} else {
-		r0 = ret.Get(0).(uint16)
-	}
-
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
-	} else {
-		r1 = ret.Error(1)
-	}
-
-	return r0, r1
-}
-
-// mockAccountManager_RegStatusByName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RegStatusByName'
-type mockAccountManager_RegStatusByName_Call struct {
-	*mock.Call
-}
-
-// RegStatusByName is a helper method to define mock.On call
-//   - screenName state.IdentScreenName
-func (_e *mockAccountManager_Expecter) RegStatusByName(screenName interface{}) *mockAccountManager_RegStatusByName_Call {
-	return &mockAccountManager_RegStatusByName_Call{Call: _e.mock.On("RegStatusByName", screenName)}
-}
-
-func (_c *mockAccountManager_RegStatusByName_Call) Run(run func(screenName state.IdentScreenName)) *mockAccountManager_RegStatusByName_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
-	})
-	return _c
-}
-
-func (_c *mockAccountManager_RegStatusByName_Call) Return(_a0 uint16, _a1 error) *mockAccountManager_RegStatusByName_Call {
-	_c.Call.Return(_a0, _a1)
-	return _c
-}
-
-func (_c *mockAccountManager_RegStatusByName_Call) RunAndReturn(run func(state.IdentScreenName) (uint16, error)) *mockAccountManager_RegStatusByName_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// UpdateSuspendedStatus provides a mock function with given fields: suspendedStatus, screenName
-func (_m *mockAccountManager) UpdateSuspendedStatus(suspendedStatus uint16, screenName state.IdentScreenName) error {
-	ret := _m.Called(suspendedStatus, screenName)
-
-	if len(ret) == 0 {
-		panic("no return value specified for UpdateSuspendedStatus")
-	}
-
-	var r0 error
-	if rf, ok := ret.Get(0).(func(uint16, state.IdentScreenName) error); ok {
-		r0 = rf(suspendedStatus, screenName)
-	} else {
-		r0 = ret.Error(0)
-	}
-
-	return r0
-}
-
-// mockAccountManager_UpdateSuspendedStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateSuspendedStatus'
-type mockAccountManager_UpdateSuspendedStatus_Call struct {
-	*mock.Call
-}
-
-// UpdateSuspendedStatus is a helper method to define mock.On call
-//   - suspendedStatus uint16
-//   - screenName state.IdentScreenName
-func (_e *mockAccountManager_Expecter) UpdateSuspendedStatus(suspendedStatus interface{}, screenName interface{}) *mockAccountManager_UpdateSuspendedStatus_Call {
-	return &mockAccountManager_UpdateSuspendedStatus_Call{Call: _e.mock.On("UpdateSuspendedStatus", suspendedStatus, screenName)}
-}
-
-func (_c *mockAccountManager_UpdateSuspendedStatus_Call) Run(run func(suspendedStatus uint16, screenName state.IdentScreenName)) *mockAccountManager_UpdateSuspendedStatus_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(uint16), args[1].(state.IdentScreenName))
-	})
-	return _c
-}
-
-func (_c *mockAccountManager_UpdateSuspendedStatus_Call) Return(_a0 error) *mockAccountManager_UpdateSuspendedStatus_Call {
-	_c.Call.Return(_a0)
-	return _c
-}
-
-func (_c *mockAccountManager_UpdateSuspendedStatus_Call) RunAndReturn(run func(uint16, state.IdentScreenName) error) *mockAccountManager_UpdateSuspendedStatus_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// newMockAccountManager creates a new instance of mockAccountManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func newMockAccountManager(t interface {
-	mock.TestingT
-	Cleanup(func())
-}) *mockAccountManager {
-	mock := &mockAccountManager{}
-	mock.Mock.Test(t)
-
-	t.Cleanup(func() { mock.AssertExpectations(t) })
-
-	return mock
-}

+ 260 - 0
server/http/mock_account_manager_test.go

@@ -0,0 +1,260 @@
+// Code generated by mockery v2.52.1. DO NOT EDIT.
+
+package http
+
+import (
+	context "context"
+	mail "net/mail"
+
+	mock "github.com/stretchr/testify/mock"
+
+	state "github.com/mk6i/retro-aim-server/state"
+)
+
+// mockAccountManager is an autogenerated mock type for the AccountManager type
+type mockAccountManager struct {
+	mock.Mock
+}
+
+type mockAccountManager_Expecter struct {
+	mock *mock.Mock
+}
+
+func (_m *mockAccountManager) EXPECT() *mockAccountManager_Expecter {
+	return &mockAccountManager_Expecter{mock: &_m.Mock}
+}
+
+// ConfirmStatus provides a mock function with given fields: ctx, screenName
+func (_m *mockAccountManager) ConfirmStatus(ctx context.Context, screenName state.IdentScreenName) (bool, error) {
+	ret := _m.Called(ctx, screenName)
+
+	if len(ret) == 0 {
+		panic("no return value specified for ConfirmStatus")
+	}
+
+	var r0 bool
+	var r1 error
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) (bool, error)); ok {
+		return rf(ctx, screenName)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) bool); ok {
+		r0 = rf(ctx, screenName)
+	} else {
+		r0 = ret.Get(0).(bool)
+	}
+
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// mockAccountManager_ConfirmStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConfirmStatus'
+type mockAccountManager_ConfirmStatus_Call struct {
+	*mock.Call
+}
+
+// ConfirmStatus is a helper method to define mock.On call
+//   - ctx context.Context
+//   - screenName state.IdentScreenName
+func (_e *mockAccountManager_Expecter) ConfirmStatus(ctx interface{}, screenName interface{}) *mockAccountManager_ConfirmStatus_Call {
+	return &mockAccountManager_ConfirmStatus_Call{Call: _e.mock.On("ConfirmStatus", ctx, screenName)}
+}
+
+func (_c *mockAccountManager_ConfirmStatus_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockAccountManager_ConfirmStatus_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
+	})
+	return _c
+}
+
+func (_c *mockAccountManager_ConfirmStatus_Call) Return(_a0 bool, _a1 error) *mockAccountManager_ConfirmStatus_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *mockAccountManager_ConfirmStatus_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) (bool, error)) *mockAccountManager_ConfirmStatus_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// EmailAddress provides a mock function with given fields: ctx, screenName
+func (_m *mockAccountManager) EmailAddress(ctx context.Context, screenName state.IdentScreenName) (*mail.Address, error) {
+	ret := _m.Called(ctx, screenName)
+
+	if len(ret) == 0 {
+		panic("no return value specified for EmailAddress")
+	}
+
+	var r0 *mail.Address
+	var r1 error
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) (*mail.Address, error)); ok {
+		return rf(ctx, screenName)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) *mail.Address); ok {
+		r0 = rf(ctx, screenName)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(*mail.Address)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// mockAccountManager_EmailAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EmailAddress'
+type mockAccountManager_EmailAddress_Call struct {
+	*mock.Call
+}
+
+// EmailAddress is a helper method to define mock.On call
+//   - ctx context.Context
+//   - screenName state.IdentScreenName
+func (_e *mockAccountManager_Expecter) EmailAddress(ctx interface{}, screenName interface{}) *mockAccountManager_EmailAddress_Call {
+	return &mockAccountManager_EmailAddress_Call{Call: _e.mock.On("EmailAddress", ctx, screenName)}
+}
+
+func (_c *mockAccountManager_EmailAddress_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockAccountManager_EmailAddress_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
+	})
+	return _c
+}
+
+func (_c *mockAccountManager_EmailAddress_Call) Return(_a0 *mail.Address, _a1 error) *mockAccountManager_EmailAddress_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *mockAccountManager_EmailAddress_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) (*mail.Address, error)) *mockAccountManager_EmailAddress_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// RegStatus provides a mock function with given fields: ctx, screenName
+func (_m *mockAccountManager) RegStatus(ctx context.Context, screenName state.IdentScreenName) (uint16, error) {
+	ret := _m.Called(ctx, screenName)
+
+	if len(ret) == 0 {
+		panic("no return value specified for RegStatus")
+	}
+
+	var r0 uint16
+	var r1 error
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) (uint16, error)); ok {
+		return rf(ctx, screenName)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) uint16); ok {
+		r0 = rf(ctx, screenName)
+	} else {
+		r0 = ret.Get(0).(uint16)
+	}
+
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// mockAccountManager_RegStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RegStatus'
+type mockAccountManager_RegStatus_Call struct {
+	*mock.Call
+}
+
+// RegStatus is a helper method to define mock.On call
+//   - ctx context.Context
+//   - screenName state.IdentScreenName
+func (_e *mockAccountManager_Expecter) RegStatus(ctx interface{}, screenName interface{}) *mockAccountManager_RegStatus_Call {
+	return &mockAccountManager_RegStatus_Call{Call: _e.mock.On("RegStatus", ctx, screenName)}
+}
+
+func (_c *mockAccountManager_RegStatus_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockAccountManager_RegStatus_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
+	})
+	return _c
+}
+
+func (_c *mockAccountManager_RegStatus_Call) Return(_a0 uint16, _a1 error) *mockAccountManager_RegStatus_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *mockAccountManager_RegStatus_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) (uint16, error)) *mockAccountManager_RegStatus_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// UpdateSuspendedStatus provides a mock function with given fields: ctx, suspendedStatus, screenName
+func (_m *mockAccountManager) UpdateSuspendedStatus(ctx context.Context, suspendedStatus uint16, screenName state.IdentScreenName) error {
+	ret := _m.Called(ctx, suspendedStatus, screenName)
+
+	if len(ret) == 0 {
+		panic("no return value specified for UpdateSuspendedStatus")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(context.Context, uint16, state.IdentScreenName) error); ok {
+		r0 = rf(ctx, suspendedStatus, screenName)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// mockAccountManager_UpdateSuspendedStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateSuspendedStatus'
+type mockAccountManager_UpdateSuspendedStatus_Call struct {
+	*mock.Call
+}
+
+// UpdateSuspendedStatus is a helper method to define mock.On call
+//   - ctx context.Context
+//   - suspendedStatus uint16
+//   - screenName state.IdentScreenName
+func (_e *mockAccountManager_Expecter) UpdateSuspendedStatus(ctx interface{}, suspendedStatus interface{}, screenName interface{}) *mockAccountManager_UpdateSuspendedStatus_Call {
+	return &mockAccountManager_UpdateSuspendedStatus_Call{Call: _e.mock.On("UpdateSuspendedStatus", ctx, suspendedStatus, screenName)}
+}
+
+func (_c *mockAccountManager_UpdateSuspendedStatus_Call) Run(run func(ctx context.Context, suspendedStatus uint16, screenName state.IdentScreenName)) *mockAccountManager_UpdateSuspendedStatus_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(uint16), args[2].(state.IdentScreenName))
+	})
+	return _c
+}
+
+func (_c *mockAccountManager_UpdateSuspendedStatus_Call) Return(_a0 error) *mockAccountManager_UpdateSuspendedStatus_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *mockAccountManager_UpdateSuspendedStatus_Call) RunAndReturn(run func(context.Context, uint16, state.IdentScreenName) error) *mockAccountManager_UpdateSuspendedStatus_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// newMockAccountManager creates a new instance of mockAccountManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func newMockAccountManager(t interface {
+	mock.TestingT
+	Cleanup(func())
+}) *mockAccountManager {
+	mock := &mockAccountManager{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}

+ 0 - 90
server/http/mock_bart_retriever_test.go

@@ -1,90 +0,0 @@
-// Code generated by mockery v2.52.1. DO NOT EDIT.
-
-package http
-
-import mock "github.com/stretchr/testify/mock"
-
-// mockBARTRetriever is an autogenerated mock type for the BARTRetriever type
-type mockBARTRetriever struct {
-	mock.Mock
-}
-
-type mockBARTRetriever_Expecter struct {
-	mock *mock.Mock
-}
-
-func (_m *mockBARTRetriever) EXPECT() *mockBARTRetriever_Expecter {
-	return &mockBARTRetriever_Expecter{mock: &_m.Mock}
-}
-
-// BARTRetrieve provides a mock function with given fields: itemHash
-func (_m *mockBARTRetriever) BARTRetrieve(itemHash []byte) ([]byte, error) {
-	ret := _m.Called(itemHash)
-
-	if len(ret) == 0 {
-		panic("no return value specified for BARTRetrieve")
-	}
-
-	var r0 []byte
-	var r1 error
-	if rf, ok := ret.Get(0).(func([]byte) ([]byte, error)); ok {
-		return rf(itemHash)
-	}
-	if rf, ok := ret.Get(0).(func([]byte) []byte); ok {
-		r0 = rf(itemHash)
-	} else {
-		if ret.Get(0) != nil {
-			r0 = ret.Get(0).([]byte)
-		}
-	}
-
-	if rf, ok := ret.Get(1).(func([]byte) error); ok {
-		r1 = rf(itemHash)
-	} else {
-		r1 = ret.Error(1)
-	}
-
-	return r0, r1
-}
-
-// mockBARTRetriever_BARTRetrieve_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BARTRetrieve'
-type mockBARTRetriever_BARTRetrieve_Call struct {
-	*mock.Call
-}
-
-// BARTRetrieve is a helper method to define mock.On call
-//   - itemHash []byte
-func (_e *mockBARTRetriever_Expecter) BARTRetrieve(itemHash interface{}) *mockBARTRetriever_BARTRetrieve_Call {
-	return &mockBARTRetriever_BARTRetrieve_Call{Call: _e.mock.On("BARTRetrieve", itemHash)}
-}
-
-func (_c *mockBARTRetriever_BARTRetrieve_Call) Run(run func(itemHash []byte)) *mockBARTRetriever_BARTRetrieve_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].([]byte))
-	})
-	return _c
-}
-
-func (_c *mockBARTRetriever_BARTRetrieve_Call) Return(_a0 []byte, _a1 error) *mockBARTRetriever_BARTRetrieve_Call {
-	_c.Call.Return(_a0, _a1)
-	return _c
-}
-
-func (_c *mockBARTRetriever_BARTRetrieve_Call) RunAndReturn(run func([]byte) ([]byte, error)) *mockBARTRetriever_BARTRetrieve_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// newMockBARTRetriever creates a new instance of mockBARTRetriever. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func newMockBARTRetriever(t interface {
-	mock.TestingT
-	Cleanup(func())
-}) *mockBARTRetriever {
-	mock := &mockBARTRetriever{}
-	mock.Mock.Test(t)
-
-	t.Cleanup(func() { mock.AssertExpectations(t) })
-
-	return mock
-}

+ 95 - 0
server/http/mock_buddy_icon_retriever_test.go

@@ -0,0 +1,95 @@
+// Code generated by mockery v2.52.1. DO NOT EDIT.
+
+package http
+
+import (
+	context "context"
+
+	mock "github.com/stretchr/testify/mock"
+)
+
+// mockBuddyIconRetriever is an autogenerated mock type for the BuddyIconRetriever type
+type mockBuddyIconRetriever struct {
+	mock.Mock
+}
+
+type mockBuddyIconRetriever_Expecter struct {
+	mock *mock.Mock
+}
+
+func (_m *mockBuddyIconRetriever) EXPECT() *mockBuddyIconRetriever_Expecter {
+	return &mockBuddyIconRetriever_Expecter{mock: &_m.Mock}
+}
+
+// BuddyIcon provides a mock function with given fields: ctx, itemHash
+func (_m *mockBuddyIconRetriever) BuddyIcon(ctx context.Context, itemHash []byte) ([]byte, error) {
+	ret := _m.Called(ctx, itemHash)
+
+	if len(ret) == 0 {
+		panic("no return value specified for BuddyIcon")
+	}
+
+	var r0 []byte
+	var r1 error
+	if rf, ok := ret.Get(0).(func(context.Context, []byte) ([]byte, error)); ok {
+		return rf(ctx, itemHash)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, []byte) []byte); ok {
+		r0 = rf(ctx, itemHash)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).([]byte)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func(context.Context, []byte) error); ok {
+		r1 = rf(ctx, itemHash)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// mockBuddyIconRetriever_BuddyIcon_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BuddyIcon'
+type mockBuddyIconRetriever_BuddyIcon_Call struct {
+	*mock.Call
+}
+
+// BuddyIcon is a helper method to define mock.On call
+//   - ctx context.Context
+//   - itemHash []byte
+func (_e *mockBuddyIconRetriever_Expecter) BuddyIcon(ctx interface{}, itemHash interface{}) *mockBuddyIconRetriever_BuddyIcon_Call {
+	return &mockBuddyIconRetriever_BuddyIcon_Call{Call: _e.mock.On("BuddyIcon", ctx, itemHash)}
+}
+
+func (_c *mockBuddyIconRetriever_BuddyIcon_Call) Run(run func(ctx context.Context, itemHash []byte)) *mockBuddyIconRetriever_BuddyIcon_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].([]byte))
+	})
+	return _c
+}
+
+func (_c *mockBuddyIconRetriever_BuddyIcon_Call) Return(_a0 []byte, _a1 error) *mockBuddyIconRetriever_BuddyIcon_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *mockBuddyIconRetriever_BuddyIcon_Call) RunAndReturn(run func(context.Context, []byte) ([]byte, error)) *mockBuddyIconRetriever_BuddyIcon_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
+// newMockBuddyIconRetriever creates a new instance of mockBuddyIconRetriever. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func newMockBuddyIconRetriever(t interface {
+	mock.TestingT
+	Cleanup(func())
+}) *mockBuddyIconRetriever {
+	mock := &mockBuddyIconRetriever{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}

+ 0 - 207
server/http/mock_chat_account_retriever_test.go

@@ -1,207 +0,0 @@
-// Code generated by mockery v2.52.1. DO NOT EDIT.
-
-package http
-
-import (
-	mail "net/mail"
-
-	state "github.com/mk6i/retro-aim-server/state"
-	mock "github.com/stretchr/testify/mock"
-)
-
-// mockAccountRetriever is an autogenerated mock type for the AccountRetriever type
-type mockAccountRetriever struct {
-	mock.Mock
-}
-
-type mockAccountRetriever_Expecter struct {
-	mock *mock.Mock
-}
-
-func (_m *mockAccountRetriever) EXPECT() *mockAccountRetriever_Expecter {
-	return &mockAccountRetriever_Expecter{mock: &_m.Mock}
-}
-
-// ConfirmStatusByName provides a mock function with given fields: screnName
-func (_m *mockAccountRetriever) ConfirmStatusByName(screnName state.IdentScreenName) (bool, error) {
-	ret := _m.Called(screnName)
-
-	if len(ret) == 0 {
-		panic("no return value specified for ConfirmStatusByName")
-	}
-
-	var r0 bool
-	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (bool, error)); ok {
-		return rf(screnName)
-	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) bool); ok {
-		r0 = rf(screnName)
-	} else {
-		r0 = ret.Get(0).(bool)
-	}
-
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screnName)
-	} else {
-		r1 = ret.Error(1)
-	}
-
-	return r0, r1
-}
-
-// mockAccountRetriever_ConfirmStatusByName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConfirmStatusByName'
-type mockAccountRetriever_ConfirmStatusByName_Call struct {
-	*mock.Call
-}
-
-// ConfirmStatusByName is a helper method to define mock.On call
-//   - screnName state.IdentScreenName
-func (_e *mockAccountRetriever_Expecter) ConfirmStatusByName(screnName interface{}) *mockAccountRetriever_ConfirmStatusByName_Call {
-	return &mockAccountRetriever_ConfirmStatusByName_Call{Call: _e.mock.On("ConfirmStatusByName", screnName)}
-}
-
-func (_c *mockAccountRetriever_ConfirmStatusByName_Call) Run(run func(screnName state.IdentScreenName)) *mockAccountRetriever_ConfirmStatusByName_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
-	})
-	return _c
-}
-
-func (_c *mockAccountRetriever_ConfirmStatusByName_Call) Return(_a0 bool, _a1 error) *mockAccountRetriever_ConfirmStatusByName_Call {
-	_c.Call.Return(_a0, _a1)
-	return _c
-}
-
-func (_c *mockAccountRetriever_ConfirmStatusByName_Call) RunAndReturn(run func(state.IdentScreenName) (bool, error)) *mockAccountRetriever_ConfirmStatusByName_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// EmailAddressByName provides a mock function with given fields: screenName
-func (_m *mockAccountRetriever) EmailAddressByName(screenName state.IdentScreenName) (*mail.Address, error) {
-	ret := _m.Called(screenName)
-
-	if len(ret) == 0 {
-		panic("no return value specified for EmailAddressByName")
-	}
-
-	var r0 *mail.Address
-	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (*mail.Address, error)); ok {
-		return rf(screenName)
-	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) *mail.Address); ok {
-		r0 = rf(screenName)
-	} else {
-		if ret.Get(0) != nil {
-			r0 = ret.Get(0).(*mail.Address)
-		}
-	}
-
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
-	} else {
-		r1 = ret.Error(1)
-	}
-
-	return r0, r1
-}
-
-// mockAccountRetriever_EmailAddressByName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EmailAddressByName'
-type mockAccountRetriever_EmailAddressByName_Call struct {
-	*mock.Call
-}
-
-// EmailAddressByName is a helper method to define mock.On call
-//   - screenName state.IdentScreenName
-func (_e *mockAccountRetriever_Expecter) EmailAddressByName(screenName interface{}) *mockAccountRetriever_EmailAddressByName_Call {
-	return &mockAccountRetriever_EmailAddressByName_Call{Call: _e.mock.On("EmailAddressByName", screenName)}
-}
-
-func (_c *mockAccountRetriever_EmailAddressByName_Call) Run(run func(screenName state.IdentScreenName)) *mockAccountRetriever_EmailAddressByName_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
-	})
-	return _c
-}
-
-func (_c *mockAccountRetriever_EmailAddressByName_Call) Return(_a0 *mail.Address, _a1 error) *mockAccountRetriever_EmailAddressByName_Call {
-	_c.Call.Return(_a0, _a1)
-	return _c
-}
-
-func (_c *mockAccountRetriever_EmailAddressByName_Call) RunAndReturn(run func(state.IdentScreenName) (*mail.Address, error)) *mockAccountRetriever_EmailAddressByName_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// RegStatusByName provides a mock function with given fields: screenName
-func (_m *mockAccountRetriever) RegStatusByName(screenName state.IdentScreenName) (uint16, error) {
-	ret := _m.Called(screenName)
-
-	if len(ret) == 0 {
-		panic("no return value specified for RegStatusByName")
-	}
-
-	var r0 uint16
-	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (uint16, error)); ok {
-		return rf(screenName)
-	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) uint16); ok {
-		r0 = rf(screenName)
-	} else {
-		r0 = ret.Get(0).(uint16)
-	}
-
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
-	} else {
-		r1 = ret.Error(1)
-	}
-
-	return r0, r1
-}
-
-// mockAccountRetriever_RegStatusByName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RegStatusByName'
-type mockAccountRetriever_RegStatusByName_Call struct {
-	*mock.Call
-}
-
-// RegStatusByName is a helper method to define mock.On call
-//   - screenName state.IdentScreenName
-func (_e *mockAccountRetriever_Expecter) RegStatusByName(screenName interface{}) *mockAccountRetriever_RegStatusByName_Call {
-	return &mockAccountRetriever_RegStatusByName_Call{Call: _e.mock.On("RegStatusByName", screenName)}
-}
-
-func (_c *mockAccountRetriever_RegStatusByName_Call) Run(run func(screenName state.IdentScreenName)) *mockAccountRetriever_RegStatusByName_Call {
-	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
-	})
-	return _c
-}
-
-func (_c *mockAccountRetriever_RegStatusByName_Call) Return(_a0 uint16, _a1 error) *mockAccountRetriever_RegStatusByName_Call {
-	_c.Call.Return(_a0, _a1)
-	return _c
-}
-
-func (_c *mockAccountRetriever_RegStatusByName_Call) RunAndReturn(run func(state.IdentScreenName) (uint16, error)) *mockAccountRetriever_RegStatusByName_Call {
-	_c.Call.Return(run)
-	return _c
-}
-
-// newMockAccountRetriever creates a new instance of mockAccountRetriever. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func newMockAccountRetriever(t interface {
-	mock.TestingT
-	Cleanup(func())
-}) *mockAccountRetriever {
-	mock := &mockAccountRetriever{}
-	mock.Mock.Test(t)
-
-	t.Cleanup(func() { mock.AssertExpectations(t) })
-
-	return mock
-}

+ 13 - 10
server/http/mock_chat_room_creator_test.go

@@ -3,6 +3,8 @@
 package http
 
 import (
+	context "context"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 )
@@ -20,17 +22,17 @@ func (_m *mockChatRoomCreator) EXPECT() *mockChatRoomCreator_Expecter {
 	return &mockChatRoomCreator_Expecter{mock: &_m.Mock}
 }
 
-// CreateChatRoom provides a mock function with given fields: chatRoom
-func (_m *mockChatRoomCreator) CreateChatRoom(chatRoom *state.ChatRoom) error {
-	ret := _m.Called(chatRoom)
+// CreateChatRoom provides a mock function with given fields: ctx, chatRoom
+func (_m *mockChatRoomCreator) CreateChatRoom(ctx context.Context, chatRoom *state.ChatRoom) error {
+	ret := _m.Called(ctx, chatRoom)
 
 	if len(ret) == 0 {
 		panic("no return value specified for CreateChatRoom")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(*state.ChatRoom) error); ok {
-		r0 = rf(chatRoom)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.ChatRoom) error); ok {
+		r0 = rf(ctx, chatRoom)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -44,14 +46,15 @@ type mockChatRoomCreator_CreateChatRoom_Call struct {
 }
 
 // CreateChatRoom is a helper method to define mock.On call
+//   - ctx context.Context
 //   - chatRoom *state.ChatRoom
-func (_e *mockChatRoomCreator_Expecter) CreateChatRoom(chatRoom interface{}) *mockChatRoomCreator_CreateChatRoom_Call {
-	return &mockChatRoomCreator_CreateChatRoom_Call{Call: _e.mock.On("CreateChatRoom", chatRoom)}
+func (_e *mockChatRoomCreator_Expecter) CreateChatRoom(ctx interface{}, chatRoom interface{}) *mockChatRoomCreator_CreateChatRoom_Call {
+	return &mockChatRoomCreator_CreateChatRoom_Call{Call: _e.mock.On("CreateChatRoom", ctx, chatRoom)}
 }
 
-func (_c *mockChatRoomCreator_CreateChatRoom_Call) Run(run func(chatRoom *state.ChatRoom)) *mockChatRoomCreator_CreateChatRoom_Call {
+func (_c *mockChatRoomCreator_CreateChatRoom_Call) Run(run func(ctx context.Context, chatRoom *state.ChatRoom)) *mockChatRoomCreator_CreateChatRoom_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(*state.ChatRoom))
+		run(args[0].(context.Context), args[1].(*state.ChatRoom))
 	})
 	return _c
 }
@@ -61,7 +64,7 @@ func (_c *mockChatRoomCreator_CreateChatRoom_Call) Return(_a0 error) *mockChatRo
 	return _c
 }
 
-func (_c *mockChatRoomCreator_CreateChatRoom_Call) RunAndReturn(run func(*state.ChatRoom) error) *mockChatRoomCreator_CreateChatRoom_Call {
+func (_c *mockChatRoomCreator_CreateChatRoom_Call) RunAndReturn(run func(context.Context, *state.ChatRoom) error) *mockChatRoomCreator_CreateChatRoom_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 17 - 14
server/http/mock_chat_room_retriever_test.go

@@ -3,6 +3,8 @@
 package http
 
 import (
+	context "context"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 )
@@ -20,9 +22,9 @@ func (_m *mockChatRoomRetriever) EXPECT() *mockChatRoomRetriever_Expecter {
 	return &mockChatRoomRetriever_Expecter{mock: &_m.Mock}
 }
 
-// AllChatRooms provides a mock function with given fields: exchange
-func (_m *mockChatRoomRetriever) AllChatRooms(exchange uint16) ([]state.ChatRoom, error) {
-	ret := _m.Called(exchange)
+// AllChatRooms provides a mock function with given fields: ctx, exchange
+func (_m *mockChatRoomRetriever) AllChatRooms(ctx context.Context, exchange uint16) ([]state.ChatRoom, error) {
+	ret := _m.Called(ctx, exchange)
 
 	if len(ret) == 0 {
 		panic("no return value specified for AllChatRooms")
@@ -30,19 +32,19 @@ func (_m *mockChatRoomRetriever) AllChatRooms(exchange uint16) ([]state.ChatRoom
 
 	var r0 []state.ChatRoom
 	var r1 error
-	if rf, ok := ret.Get(0).(func(uint16) ([]state.ChatRoom, error)); ok {
-		return rf(exchange)
+	if rf, ok := ret.Get(0).(func(context.Context, uint16) ([]state.ChatRoom, error)); ok {
+		return rf(ctx, exchange)
 	}
-	if rf, ok := ret.Get(0).(func(uint16) []state.ChatRoom); ok {
-		r0 = rf(exchange)
+	if rf, ok := ret.Get(0).(func(context.Context, uint16) []state.ChatRoom); ok {
+		r0 = rf(ctx, exchange)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).([]state.ChatRoom)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(uint16) error); ok {
-		r1 = rf(exchange)
+	if rf, ok := ret.Get(1).(func(context.Context, uint16) error); ok {
+		r1 = rf(ctx, exchange)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -56,14 +58,15 @@ type mockChatRoomRetriever_AllChatRooms_Call struct {
 }
 
 // AllChatRooms is a helper method to define mock.On call
+//   - ctx context.Context
 //   - exchange uint16
-func (_e *mockChatRoomRetriever_Expecter) AllChatRooms(exchange interface{}) *mockChatRoomRetriever_AllChatRooms_Call {
-	return &mockChatRoomRetriever_AllChatRooms_Call{Call: _e.mock.On("AllChatRooms", exchange)}
+func (_e *mockChatRoomRetriever_Expecter) AllChatRooms(ctx interface{}, exchange interface{}) *mockChatRoomRetriever_AllChatRooms_Call {
+	return &mockChatRoomRetriever_AllChatRooms_Call{Call: _e.mock.On("AllChatRooms", ctx, exchange)}
 }
 
-func (_c *mockChatRoomRetriever_AllChatRooms_Call) Run(run func(exchange uint16)) *mockChatRoomRetriever_AllChatRooms_Call {
+func (_c *mockChatRoomRetriever_AllChatRooms_Call) Run(run func(ctx context.Context, exchange uint16)) *mockChatRoomRetriever_AllChatRooms_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(uint16))
+		run(args[0].(context.Context), args[1].(uint16))
 	})
 	return _c
 }
@@ -73,7 +76,7 @@ func (_c *mockChatRoomRetriever_AllChatRooms_Call) Return(_a0 []state.ChatRoom,
 	return _c
 }
 
-func (_c *mockChatRoomRetriever_AllChatRooms_Call) RunAndReturn(run func(uint16) ([]state.ChatRoom, error)) *mockChatRoomRetriever_AllChatRooms_Call {
+func (_c *mockChatRoomRetriever_AllChatRooms_Call) RunAndReturn(run func(context.Context, uint16) ([]state.ChatRoom, error)) *mockChatRoomRetriever_AllChatRooms_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 84 - 76
server/http/mock_directory_manager_test.go

@@ -3,6 +3,8 @@
 package http
 
 import (
+	context "context"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 )
@@ -20,9 +22,9 @@ func (_m *mockDirectoryManager) EXPECT() *mockDirectoryManager_Expecter {
 	return &mockDirectoryManager_Expecter{mock: &_m.Mock}
 }
 
-// Categories provides a mock function with no fields
-func (_m *mockDirectoryManager) Categories() ([]state.Category, error) {
-	ret := _m.Called()
+// Categories provides a mock function with given fields: ctx
+func (_m *mockDirectoryManager) Categories(ctx context.Context) ([]state.Category, error) {
+	ret := _m.Called(ctx)
 
 	if len(ret) == 0 {
 		panic("no return value specified for Categories")
@@ -30,19 +32,19 @@ func (_m *mockDirectoryManager) Categories() ([]state.Category, error) {
 
 	var r0 []state.Category
 	var r1 error
-	if rf, ok := ret.Get(0).(func() ([]state.Category, error)); ok {
-		return rf()
+	if rf, ok := ret.Get(0).(func(context.Context) ([]state.Category, error)); ok {
+		return rf(ctx)
 	}
-	if rf, ok := ret.Get(0).(func() []state.Category); ok {
-		r0 = rf()
+	if rf, ok := ret.Get(0).(func(context.Context) []state.Category); ok {
+		r0 = rf(ctx)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).([]state.Category)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func() error); ok {
-		r1 = rf()
+	if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+		r1 = rf(ctx)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -56,13 +58,14 @@ type mockDirectoryManager_Categories_Call struct {
 }
 
 // Categories is a helper method to define mock.On call
-func (_e *mockDirectoryManager_Expecter) Categories() *mockDirectoryManager_Categories_Call {
-	return &mockDirectoryManager_Categories_Call{Call: _e.mock.On("Categories")}
+//   - ctx context.Context
+func (_e *mockDirectoryManager_Expecter) Categories(ctx interface{}) *mockDirectoryManager_Categories_Call {
+	return &mockDirectoryManager_Categories_Call{Call: _e.mock.On("Categories", ctx)}
 }
 
-func (_c *mockDirectoryManager_Categories_Call) Run(run func()) *mockDirectoryManager_Categories_Call {
+func (_c *mockDirectoryManager_Categories_Call) Run(run func(ctx context.Context)) *mockDirectoryManager_Categories_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run()
+		run(args[0].(context.Context))
 	})
 	return _c
 }
@@ -72,14 +75,14 @@ func (_c *mockDirectoryManager_Categories_Call) Return(_a0 []state.Category, _a1
 	return _c
 }
 
-func (_c *mockDirectoryManager_Categories_Call) RunAndReturn(run func() ([]state.Category, error)) *mockDirectoryManager_Categories_Call {
+func (_c *mockDirectoryManager_Categories_Call) RunAndReturn(run func(context.Context) ([]state.Category, error)) *mockDirectoryManager_Categories_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// CreateCategory provides a mock function with given fields: name
-func (_m *mockDirectoryManager) CreateCategory(name string) (state.Category, error) {
-	ret := _m.Called(name)
+// CreateCategory provides a mock function with given fields: ctx, name
+func (_m *mockDirectoryManager) CreateCategory(ctx context.Context, name string) (state.Category, error) {
+	ret := _m.Called(ctx, name)
 
 	if len(ret) == 0 {
 		panic("no return value specified for CreateCategory")
@@ -87,17 +90,17 @@ func (_m *mockDirectoryManager) CreateCategory(name string) (state.Category, err
 
 	var r0 state.Category
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string) (state.Category, error)); ok {
-		return rf(name)
+	if rf, ok := ret.Get(0).(func(context.Context, string) (state.Category, error)); ok {
+		return rf(ctx, name)
 	}
-	if rf, ok := ret.Get(0).(func(string) state.Category); ok {
-		r0 = rf(name)
+	if rf, ok := ret.Get(0).(func(context.Context, string) state.Category); ok {
+		r0 = rf(ctx, name)
 	} else {
 		r0 = ret.Get(0).(state.Category)
 	}
 
-	if rf, ok := ret.Get(1).(func(string) error); ok {
-		r1 = rf(name)
+	if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
+		r1 = rf(ctx, name)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -111,14 +114,15 @@ type mockDirectoryManager_CreateCategory_Call struct {
 }
 
 // CreateCategory is a helper method to define mock.On call
+//   - ctx context.Context
 //   - name string
-func (_e *mockDirectoryManager_Expecter) CreateCategory(name interface{}) *mockDirectoryManager_CreateCategory_Call {
-	return &mockDirectoryManager_CreateCategory_Call{Call: _e.mock.On("CreateCategory", name)}
+func (_e *mockDirectoryManager_Expecter) CreateCategory(ctx interface{}, name interface{}) *mockDirectoryManager_CreateCategory_Call {
+	return &mockDirectoryManager_CreateCategory_Call{Call: _e.mock.On("CreateCategory", ctx, name)}
 }
 
-func (_c *mockDirectoryManager_CreateCategory_Call) Run(run func(name string)) *mockDirectoryManager_CreateCategory_Call {
+func (_c *mockDirectoryManager_CreateCategory_Call) Run(run func(ctx context.Context, name string)) *mockDirectoryManager_CreateCategory_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string))
+		run(args[0].(context.Context), args[1].(string))
 	})
 	return _c
 }
@@ -128,14 +132,14 @@ func (_c *mockDirectoryManager_CreateCategory_Call) Return(_a0 state.Category, _
 	return _c
 }
 
-func (_c *mockDirectoryManager_CreateCategory_Call) RunAndReturn(run func(string) (state.Category, error)) *mockDirectoryManager_CreateCategory_Call {
+func (_c *mockDirectoryManager_CreateCategory_Call) RunAndReturn(run func(context.Context, string) (state.Category, error)) *mockDirectoryManager_CreateCategory_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// CreateKeyword provides a mock function with given fields: name, categoryID
-func (_m *mockDirectoryManager) CreateKeyword(name string, categoryID uint8) (state.Keyword, error) {
-	ret := _m.Called(name, categoryID)
+// CreateKeyword provides a mock function with given fields: ctx, name, categoryID
+func (_m *mockDirectoryManager) CreateKeyword(ctx context.Context, name string, categoryID uint8) (state.Keyword, error) {
+	ret := _m.Called(ctx, name, categoryID)
 
 	if len(ret) == 0 {
 		panic("no return value specified for CreateKeyword")
@@ -143,17 +147,17 @@ func (_m *mockDirectoryManager) CreateKeyword(name string, categoryID uint8) (st
 
 	var r0 state.Keyword
 	var r1 error
-	if rf, ok := ret.Get(0).(func(string, uint8) (state.Keyword, error)); ok {
-		return rf(name, categoryID)
+	if rf, ok := ret.Get(0).(func(context.Context, string, uint8) (state.Keyword, error)); ok {
+		return rf(ctx, name, categoryID)
 	}
-	if rf, ok := ret.Get(0).(func(string, uint8) state.Keyword); ok {
-		r0 = rf(name, categoryID)
+	if rf, ok := ret.Get(0).(func(context.Context, string, uint8) state.Keyword); ok {
+		r0 = rf(ctx, name, categoryID)
 	} else {
 		r0 = ret.Get(0).(state.Keyword)
 	}
 
-	if rf, ok := ret.Get(1).(func(string, uint8) error); ok {
-		r1 = rf(name, categoryID)
+	if rf, ok := ret.Get(1).(func(context.Context, string, uint8) error); ok {
+		r1 = rf(ctx, name, categoryID)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -167,15 +171,16 @@ type mockDirectoryManager_CreateKeyword_Call struct {
 }
 
 // CreateKeyword is a helper method to define mock.On call
+//   - ctx context.Context
 //   - name string
 //   - categoryID uint8
-func (_e *mockDirectoryManager_Expecter) CreateKeyword(name interface{}, categoryID interface{}) *mockDirectoryManager_CreateKeyword_Call {
-	return &mockDirectoryManager_CreateKeyword_Call{Call: _e.mock.On("CreateKeyword", name, categoryID)}
+func (_e *mockDirectoryManager_Expecter) CreateKeyword(ctx interface{}, name interface{}, categoryID interface{}) *mockDirectoryManager_CreateKeyword_Call {
+	return &mockDirectoryManager_CreateKeyword_Call{Call: _e.mock.On("CreateKeyword", ctx, name, categoryID)}
 }
 
-func (_c *mockDirectoryManager_CreateKeyword_Call) Run(run func(name string, categoryID uint8)) *mockDirectoryManager_CreateKeyword_Call {
+func (_c *mockDirectoryManager_CreateKeyword_Call) Run(run func(ctx context.Context, name string, categoryID uint8)) *mockDirectoryManager_CreateKeyword_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(string), args[1].(uint8))
+		run(args[0].(context.Context), args[1].(string), args[2].(uint8))
 	})
 	return _c
 }
@@ -185,22 +190,22 @@ func (_c *mockDirectoryManager_CreateKeyword_Call) Return(_a0 state.Keyword, _a1
 	return _c
 }
 
-func (_c *mockDirectoryManager_CreateKeyword_Call) RunAndReturn(run func(string, uint8) (state.Keyword, error)) *mockDirectoryManager_CreateKeyword_Call {
+func (_c *mockDirectoryManager_CreateKeyword_Call) RunAndReturn(run func(context.Context, string, uint8) (state.Keyword, error)) *mockDirectoryManager_CreateKeyword_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// DeleteCategory provides a mock function with given fields: categoryID
-func (_m *mockDirectoryManager) DeleteCategory(categoryID uint8) error {
-	ret := _m.Called(categoryID)
+// DeleteCategory provides a mock function with given fields: ctx, categoryID
+func (_m *mockDirectoryManager) DeleteCategory(ctx context.Context, categoryID uint8) error {
+	ret := _m.Called(ctx, categoryID)
 
 	if len(ret) == 0 {
 		panic("no return value specified for DeleteCategory")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(uint8) error); ok {
-		r0 = rf(categoryID)
+	if rf, ok := ret.Get(0).(func(context.Context, uint8) error); ok {
+		r0 = rf(ctx, categoryID)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -214,14 +219,15 @@ type mockDirectoryManager_DeleteCategory_Call struct {
 }
 
 // DeleteCategory is a helper method to define mock.On call
+//   - ctx context.Context
 //   - categoryID uint8
-func (_e *mockDirectoryManager_Expecter) DeleteCategory(categoryID interface{}) *mockDirectoryManager_DeleteCategory_Call {
-	return &mockDirectoryManager_DeleteCategory_Call{Call: _e.mock.On("DeleteCategory", categoryID)}
+func (_e *mockDirectoryManager_Expecter) DeleteCategory(ctx interface{}, categoryID interface{}) *mockDirectoryManager_DeleteCategory_Call {
+	return &mockDirectoryManager_DeleteCategory_Call{Call: _e.mock.On("DeleteCategory", ctx, categoryID)}
 }
 
-func (_c *mockDirectoryManager_DeleteCategory_Call) Run(run func(categoryID uint8)) *mockDirectoryManager_DeleteCategory_Call {
+func (_c *mockDirectoryManager_DeleteCategory_Call) Run(run func(ctx context.Context, categoryID uint8)) *mockDirectoryManager_DeleteCategory_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(uint8))
+		run(args[0].(context.Context), args[1].(uint8))
 	})
 	return _c
 }
@@ -231,22 +237,22 @@ func (_c *mockDirectoryManager_DeleteCategory_Call) Return(_a0 error) *mockDirec
 	return _c
 }
 
-func (_c *mockDirectoryManager_DeleteCategory_Call) RunAndReturn(run func(uint8) error) *mockDirectoryManager_DeleteCategory_Call {
+func (_c *mockDirectoryManager_DeleteCategory_Call) RunAndReturn(run func(context.Context, uint8) error) *mockDirectoryManager_DeleteCategory_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// DeleteKeyword provides a mock function with given fields: id
-func (_m *mockDirectoryManager) DeleteKeyword(id uint8) error {
-	ret := _m.Called(id)
+// DeleteKeyword provides a mock function with given fields: ctx, id
+func (_m *mockDirectoryManager) DeleteKeyword(ctx context.Context, id uint8) error {
+	ret := _m.Called(ctx, id)
 
 	if len(ret) == 0 {
 		panic("no return value specified for DeleteKeyword")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(uint8) error); ok {
-		r0 = rf(id)
+	if rf, ok := ret.Get(0).(func(context.Context, uint8) error); ok {
+		r0 = rf(ctx, id)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -260,14 +266,15 @@ type mockDirectoryManager_DeleteKeyword_Call struct {
 }
 
 // DeleteKeyword is a helper method to define mock.On call
+//   - ctx context.Context
 //   - id uint8
-func (_e *mockDirectoryManager_Expecter) DeleteKeyword(id interface{}) *mockDirectoryManager_DeleteKeyword_Call {
-	return &mockDirectoryManager_DeleteKeyword_Call{Call: _e.mock.On("DeleteKeyword", id)}
+func (_e *mockDirectoryManager_Expecter) DeleteKeyword(ctx interface{}, id interface{}) *mockDirectoryManager_DeleteKeyword_Call {
+	return &mockDirectoryManager_DeleteKeyword_Call{Call: _e.mock.On("DeleteKeyword", ctx, id)}
 }
 
-func (_c *mockDirectoryManager_DeleteKeyword_Call) Run(run func(id uint8)) *mockDirectoryManager_DeleteKeyword_Call {
+func (_c *mockDirectoryManager_DeleteKeyword_Call) Run(run func(ctx context.Context, id uint8)) *mockDirectoryManager_DeleteKeyword_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(uint8))
+		run(args[0].(context.Context), args[1].(uint8))
 	})
 	return _c
 }
@@ -277,14 +284,14 @@ func (_c *mockDirectoryManager_DeleteKeyword_Call) Return(_a0 error) *mockDirect
 	return _c
 }
 
-func (_c *mockDirectoryManager_DeleteKeyword_Call) RunAndReturn(run func(uint8) error) *mockDirectoryManager_DeleteKeyword_Call {
+func (_c *mockDirectoryManager_DeleteKeyword_Call) RunAndReturn(run func(context.Context, uint8) error) *mockDirectoryManager_DeleteKeyword_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// KeywordsByCategory provides a mock function with given fields: categoryID
-func (_m *mockDirectoryManager) KeywordsByCategory(categoryID uint8) ([]state.Keyword, error) {
-	ret := _m.Called(categoryID)
+// KeywordsByCategory provides a mock function with given fields: ctx, categoryID
+func (_m *mockDirectoryManager) KeywordsByCategory(ctx context.Context, categoryID uint8) ([]state.Keyword, error) {
+	ret := _m.Called(ctx, categoryID)
 
 	if len(ret) == 0 {
 		panic("no return value specified for KeywordsByCategory")
@@ -292,19 +299,19 @@ func (_m *mockDirectoryManager) KeywordsByCategory(categoryID uint8) ([]state.Ke
 
 	var r0 []state.Keyword
 	var r1 error
-	if rf, ok := ret.Get(0).(func(uint8) ([]state.Keyword, error)); ok {
-		return rf(categoryID)
+	if rf, ok := ret.Get(0).(func(context.Context, uint8) ([]state.Keyword, error)); ok {
+		return rf(ctx, categoryID)
 	}
-	if rf, ok := ret.Get(0).(func(uint8) []state.Keyword); ok {
-		r0 = rf(categoryID)
+	if rf, ok := ret.Get(0).(func(context.Context, uint8) []state.Keyword); ok {
+		r0 = rf(ctx, categoryID)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).([]state.Keyword)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(uint8) error); ok {
-		r1 = rf(categoryID)
+	if rf, ok := ret.Get(1).(func(context.Context, uint8) error); ok {
+		r1 = rf(ctx, categoryID)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -318,14 +325,15 @@ type mockDirectoryManager_KeywordsByCategory_Call struct {
 }
 
 // KeywordsByCategory is a helper method to define mock.On call
+//   - ctx context.Context
 //   - categoryID uint8
-func (_e *mockDirectoryManager_Expecter) KeywordsByCategory(categoryID interface{}) *mockDirectoryManager_KeywordsByCategory_Call {
-	return &mockDirectoryManager_KeywordsByCategory_Call{Call: _e.mock.On("KeywordsByCategory", categoryID)}
+func (_e *mockDirectoryManager_Expecter) KeywordsByCategory(ctx interface{}, categoryID interface{}) *mockDirectoryManager_KeywordsByCategory_Call {
+	return &mockDirectoryManager_KeywordsByCategory_Call{Call: _e.mock.On("KeywordsByCategory", ctx, categoryID)}
 }
 
-func (_c *mockDirectoryManager_KeywordsByCategory_Call) Run(run func(categoryID uint8)) *mockDirectoryManager_KeywordsByCategory_Call {
+func (_c *mockDirectoryManager_KeywordsByCategory_Call) Run(run func(ctx context.Context, categoryID uint8)) *mockDirectoryManager_KeywordsByCategory_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(uint8))
+		run(args[0].(context.Context), args[1].(uint8))
 	})
 	return _c
 }
@@ -335,7 +343,7 @@ func (_c *mockDirectoryManager_KeywordsByCategory_Call) Return(_a0 []state.Keywo
 	return _c
 }
 
-func (_c *mockDirectoryManager_KeywordsByCategory_Call) RunAndReturn(run func(uint8) ([]state.Keyword, error)) *mockDirectoryManager_KeywordsByCategory_Call {
+func (_c *mockDirectoryManager_KeywordsByCategory_Call) RunAndReturn(run func(context.Context, uint8) ([]state.Keyword, error)) *mockDirectoryManager_KeywordsByCategory_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 22 - 19
server/http/mock_feedbag_retriever_test.go

@@ -3,6 +3,8 @@
 package http
 
 import (
+	context "context"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 
@@ -22,29 +24,29 @@ func (_m *mockFeedBagRetriever) EXPECT() *mockFeedBagRetriever_Expecter {
 	return &mockFeedBagRetriever_Expecter{mock: &_m.Mock}
 }
 
-// BuddyIconRefByName provides a mock function with given fields: screenName
-func (_m *mockFeedBagRetriever) BuddyIconRefByName(screenName state.IdentScreenName) (*wire.BARTID, error) {
-	ret := _m.Called(screenName)
+// BuddyIconMetadata provides a mock function with given fields: ctx, screenName
+func (_m *mockFeedBagRetriever) BuddyIconMetadata(ctx context.Context, screenName state.IdentScreenName) (*wire.BARTID, error) {
+	ret := _m.Called(ctx, screenName)
 
 	if len(ret) == 0 {
-		panic("no return value specified for BuddyIconRefByName")
+		panic("no return value specified for BuddyIconMetadata")
 	}
 
 	var r0 *wire.BARTID
 	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (*wire.BARTID, error)); ok {
-		return rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) (*wire.BARTID, error)); ok {
+		return rf(ctx, screenName)
 	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) *wire.BARTID); ok {
-		r0 = rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) *wire.BARTID); ok {
+		r0 = rf(ctx, screenName)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*wire.BARTID)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -52,30 +54,31 @@ func (_m *mockFeedBagRetriever) BuddyIconRefByName(screenName state.IdentScreenN
 	return r0, r1
 }
 
-// mockFeedBagRetriever_BuddyIconRefByName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BuddyIconRefByName'
-type mockFeedBagRetriever_BuddyIconRefByName_Call struct {
+// mockFeedBagRetriever_BuddyIconMetadata_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BuddyIconMetadata'
+type mockFeedBagRetriever_BuddyIconMetadata_Call struct {
 	*mock.Call
 }
 
-// BuddyIconRefByName is a helper method to define mock.On call
+// BuddyIconMetadata is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockFeedBagRetriever_Expecter) BuddyIconRefByName(screenName interface{}) *mockFeedBagRetriever_BuddyIconRefByName_Call {
-	return &mockFeedBagRetriever_BuddyIconRefByName_Call{Call: _e.mock.On("BuddyIconRefByName", screenName)}
+func (_e *mockFeedBagRetriever_Expecter) BuddyIconMetadata(ctx interface{}, screenName interface{}) *mockFeedBagRetriever_BuddyIconMetadata_Call {
+	return &mockFeedBagRetriever_BuddyIconMetadata_Call{Call: _e.mock.On("BuddyIconMetadata", ctx, screenName)}
 }
 
-func (_c *mockFeedBagRetriever_BuddyIconRefByName_Call) Run(run func(screenName state.IdentScreenName)) *mockFeedBagRetriever_BuddyIconRefByName_Call {
+func (_c *mockFeedBagRetriever_BuddyIconMetadata_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockFeedBagRetriever_BuddyIconMetadata_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
 
-func (_c *mockFeedBagRetriever_BuddyIconRefByName_Call) Return(_a0 *wire.BARTID, _a1 error) *mockFeedBagRetriever_BuddyIconRefByName_Call {
+func (_c *mockFeedBagRetriever_BuddyIconMetadata_Call) Return(_a0 *wire.BARTID, _a1 error) *mockFeedBagRetriever_BuddyIconMetadata_Call {
 	_c.Call.Return(_a0, _a1)
 	return _c
 }
 
-func (_c *mockFeedBagRetriever_BuddyIconRefByName_Call) RunAndReturn(run func(state.IdentScreenName) (*wire.BARTID, error)) *mockFeedBagRetriever_BuddyIconRefByName_Call {
+func (_c *mockFeedBagRetriever_BuddyIconMetadata_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) (*wire.BARTID, error)) *mockFeedBagRetriever_BuddyIconMetadata_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 17 - 14
server/http/mock_profile_retriever_test.go

@@ -3,6 +3,8 @@
 package http
 
 import (
+	context "context"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 )
@@ -20,9 +22,9 @@ func (_m *mockProfileRetriever) EXPECT() *mockProfileRetriever_Expecter {
 	return &mockProfileRetriever_Expecter{mock: &_m.Mock}
 }
 
-// Profile provides a mock function with given fields: screenName
-func (_m *mockProfileRetriever) Profile(screenName state.IdentScreenName) (string, error) {
-	ret := _m.Called(screenName)
+// Profile provides a mock function with given fields: ctx, screenName
+func (_m *mockProfileRetriever) Profile(ctx context.Context, screenName state.IdentScreenName) (string, error) {
+	ret := _m.Called(ctx, screenName)
 
 	if len(ret) == 0 {
 		panic("no return value specified for Profile")
@@ -30,17 +32,17 @@ func (_m *mockProfileRetriever) Profile(screenName state.IdentScreenName) (strin
 
 	var r0 string
 	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (string, error)); ok {
-		return rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) (string, error)); ok {
+		return rf(ctx, screenName)
 	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) string); ok {
-		r0 = rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) string); ok {
+		r0 = rf(ctx, screenName)
 	} else {
 		r0 = ret.Get(0).(string)
 	}
 
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -54,14 +56,15 @@ type mockProfileRetriever_Profile_Call struct {
 }
 
 // Profile is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockProfileRetriever_Expecter) Profile(screenName interface{}) *mockProfileRetriever_Profile_Call {
-	return &mockProfileRetriever_Profile_Call{Call: _e.mock.On("Profile", screenName)}
+func (_e *mockProfileRetriever_Expecter) Profile(ctx interface{}, screenName interface{}) *mockProfileRetriever_Profile_Call {
+	return &mockProfileRetriever_Profile_Call{Call: _e.mock.On("Profile", ctx, screenName)}
 }
 
-func (_c *mockProfileRetriever_Profile_Call) Run(run func(screenName state.IdentScreenName)) *mockProfileRetriever_Profile_Call {
+func (_c *mockProfileRetriever_Profile_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockProfileRetriever_Profile_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
@@ -71,7 +74,7 @@ func (_c *mockProfileRetriever_Profile_Call) Return(_a0 string, _a1 error) *mock
 	return _c
 }
 
-func (_c *mockProfileRetriever_Profile_Call) RunAndReturn(run func(state.IdentScreenName) (string, error)) *mockProfileRetriever_Profile_Call {
+func (_c *mockProfileRetriever_Profile_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) (string, error)) *mockProfileRetriever_Profile_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 65 - 58
server/http/mock_user_manager_test.go

@@ -3,6 +3,8 @@
 package http
 
 import (
+	context "context"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 )
@@ -20,9 +22,9 @@ func (_m *mockUserManager) EXPECT() *mockUserManager_Expecter {
 	return &mockUserManager_Expecter{mock: &_m.Mock}
 }
 
-// AllUsers provides a mock function with no fields
-func (_m *mockUserManager) AllUsers() ([]state.User, error) {
-	ret := _m.Called()
+// AllUsers provides a mock function with given fields: ctx
+func (_m *mockUserManager) AllUsers(ctx context.Context) ([]state.User, error) {
+	ret := _m.Called(ctx)
 
 	if len(ret) == 0 {
 		panic("no return value specified for AllUsers")
@@ -30,19 +32,19 @@ func (_m *mockUserManager) AllUsers() ([]state.User, error) {
 
 	var r0 []state.User
 	var r1 error
-	if rf, ok := ret.Get(0).(func() ([]state.User, error)); ok {
-		return rf()
+	if rf, ok := ret.Get(0).(func(context.Context) ([]state.User, error)); ok {
+		return rf(ctx)
 	}
-	if rf, ok := ret.Get(0).(func() []state.User); ok {
-		r0 = rf()
+	if rf, ok := ret.Get(0).(func(context.Context) []state.User); ok {
+		r0 = rf(ctx)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).([]state.User)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func() error); ok {
-		r1 = rf()
+	if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+		r1 = rf(ctx)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -56,13 +58,14 @@ type mockUserManager_AllUsers_Call struct {
 }
 
 // AllUsers is a helper method to define mock.On call
-func (_e *mockUserManager_Expecter) AllUsers() *mockUserManager_AllUsers_Call {
-	return &mockUserManager_AllUsers_Call{Call: _e.mock.On("AllUsers")}
+//   - ctx context.Context
+func (_e *mockUserManager_Expecter) AllUsers(ctx interface{}) *mockUserManager_AllUsers_Call {
+	return &mockUserManager_AllUsers_Call{Call: _e.mock.On("AllUsers", ctx)}
 }
 
-func (_c *mockUserManager_AllUsers_Call) Run(run func()) *mockUserManager_AllUsers_Call {
+func (_c *mockUserManager_AllUsers_Call) Run(run func(ctx context.Context)) *mockUserManager_AllUsers_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run()
+		run(args[0].(context.Context))
 	})
 	return _c
 }
@@ -72,22 +75,22 @@ func (_c *mockUserManager_AllUsers_Call) Return(_a0 []state.User, _a1 error) *mo
 	return _c
 }
 
-func (_c *mockUserManager_AllUsers_Call) RunAndReturn(run func() ([]state.User, error)) *mockUserManager_AllUsers_Call {
+func (_c *mockUserManager_AllUsers_Call) RunAndReturn(run func(context.Context) ([]state.User, error)) *mockUserManager_AllUsers_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// DeleteUser provides a mock function with given fields: screenName
-func (_m *mockUserManager) DeleteUser(screenName state.IdentScreenName) error {
-	ret := _m.Called(screenName)
+// DeleteUser provides a mock function with given fields: ctx, screenName
+func (_m *mockUserManager) DeleteUser(ctx context.Context, screenName state.IdentScreenName) error {
+	ret := _m.Called(ctx, screenName)
 
 	if len(ret) == 0 {
 		panic("no return value specified for DeleteUser")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) error); ok {
-		r0 = rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) error); ok {
+		r0 = rf(ctx, screenName)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -101,14 +104,15 @@ type mockUserManager_DeleteUser_Call struct {
 }
 
 // DeleteUser is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockUserManager_Expecter) DeleteUser(screenName interface{}) *mockUserManager_DeleteUser_Call {
-	return &mockUserManager_DeleteUser_Call{Call: _e.mock.On("DeleteUser", screenName)}
+func (_e *mockUserManager_Expecter) DeleteUser(ctx interface{}, screenName interface{}) *mockUserManager_DeleteUser_Call {
+	return &mockUserManager_DeleteUser_Call{Call: _e.mock.On("DeleteUser", ctx, screenName)}
 }
 
-func (_c *mockUserManager_DeleteUser_Call) Run(run func(screenName state.IdentScreenName)) *mockUserManager_DeleteUser_Call {
+func (_c *mockUserManager_DeleteUser_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockUserManager_DeleteUser_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
@@ -118,22 +122,22 @@ func (_c *mockUserManager_DeleteUser_Call) Return(_a0 error) *mockUserManager_De
 	return _c
 }
 
-func (_c *mockUserManager_DeleteUser_Call) RunAndReturn(run func(state.IdentScreenName) error) *mockUserManager_DeleteUser_Call {
+func (_c *mockUserManager_DeleteUser_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) error) *mockUserManager_DeleteUser_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// InsertUser provides a mock function with given fields: u
-func (_m *mockUserManager) InsertUser(u state.User) error {
-	ret := _m.Called(u)
+// InsertUser provides a mock function with given fields: ctx, u
+func (_m *mockUserManager) InsertUser(ctx context.Context, u state.User) error {
+	ret := _m.Called(ctx, u)
 
 	if len(ret) == 0 {
 		panic("no return value specified for InsertUser")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.User) error); ok {
-		r0 = rf(u)
+	if rf, ok := ret.Get(0).(func(context.Context, state.User) error); ok {
+		r0 = rf(ctx, u)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -147,14 +151,15 @@ type mockUserManager_InsertUser_Call struct {
 }
 
 // InsertUser is a helper method to define mock.On call
+//   - ctx context.Context
 //   - u state.User
-func (_e *mockUserManager_Expecter) InsertUser(u interface{}) *mockUserManager_InsertUser_Call {
-	return &mockUserManager_InsertUser_Call{Call: _e.mock.On("InsertUser", u)}
+func (_e *mockUserManager_Expecter) InsertUser(ctx interface{}, u interface{}) *mockUserManager_InsertUser_Call {
+	return &mockUserManager_InsertUser_Call{Call: _e.mock.On("InsertUser", ctx, u)}
 }
 
-func (_c *mockUserManager_InsertUser_Call) Run(run func(u state.User)) *mockUserManager_InsertUser_Call {
+func (_c *mockUserManager_InsertUser_Call) Run(run func(ctx context.Context, u state.User)) *mockUserManager_InsertUser_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.User))
+		run(args[0].(context.Context), args[1].(state.User))
 	})
 	return _c
 }
@@ -164,22 +169,22 @@ func (_c *mockUserManager_InsertUser_Call) Return(_a0 error) *mockUserManager_In
 	return _c
 }
 
-func (_c *mockUserManager_InsertUser_Call) RunAndReturn(run func(state.User) error) *mockUserManager_InsertUser_Call {
+func (_c *mockUserManager_InsertUser_Call) RunAndReturn(run func(context.Context, state.User) error) *mockUserManager_InsertUser_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// SetUserPassword provides a mock function with given fields: screenName, newPassword
-func (_m *mockUserManager) SetUserPassword(screenName state.IdentScreenName, newPassword string) error {
-	ret := _m.Called(screenName, newPassword)
+// SetUserPassword provides a mock function with given fields: ctx, screenName, newPassword
+func (_m *mockUserManager) SetUserPassword(ctx context.Context, screenName state.IdentScreenName, newPassword string) error {
+	ret := _m.Called(ctx, screenName, newPassword)
 
 	if len(ret) == 0 {
 		panic("no return value specified for SetUserPassword")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, string) error); ok {
-		r0 = rf(screenName, newPassword)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, string) error); ok {
+		r0 = rf(ctx, screenName, newPassword)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -193,15 +198,16 @@ type mockUserManager_SetUserPassword_Call struct {
 }
 
 // SetUserPassword is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
 //   - newPassword string
-func (_e *mockUserManager_Expecter) SetUserPassword(screenName interface{}, newPassword interface{}) *mockUserManager_SetUserPassword_Call {
-	return &mockUserManager_SetUserPassword_Call{Call: _e.mock.On("SetUserPassword", screenName, newPassword)}
+func (_e *mockUserManager_Expecter) SetUserPassword(ctx interface{}, screenName interface{}, newPassword interface{}) *mockUserManager_SetUserPassword_Call {
+	return &mockUserManager_SetUserPassword_Call{Call: _e.mock.On("SetUserPassword", ctx, screenName, newPassword)}
 }
 
-func (_c *mockUserManager_SetUserPassword_Call) Run(run func(screenName state.IdentScreenName, newPassword string)) *mockUserManager_SetUserPassword_Call {
+func (_c *mockUserManager_SetUserPassword_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName, newPassword string)) *mockUserManager_SetUserPassword_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(string))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(string))
 	})
 	return _c
 }
@@ -211,14 +217,14 @@ func (_c *mockUserManager_SetUserPassword_Call) Return(_a0 error) *mockUserManag
 	return _c
 }
 
-func (_c *mockUserManager_SetUserPassword_Call) RunAndReturn(run func(state.IdentScreenName, string) error) *mockUserManager_SetUserPassword_Call {
+func (_c *mockUserManager_SetUserPassword_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, string) error) *mockUserManager_SetUserPassword_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// User provides a mock function with given fields: screenName
-func (_m *mockUserManager) User(screenName state.IdentScreenName) (*state.User, error) {
-	ret := _m.Called(screenName)
+// User provides a mock function with given fields: ctx, screenName
+func (_m *mockUserManager) User(ctx context.Context, screenName state.IdentScreenName) (*state.User, error) {
+	ret := _m.Called(ctx, screenName)
 
 	if len(ret) == 0 {
 		panic("no return value specified for User")
@@ -226,19 +232,19 @@ func (_m *mockUserManager) User(screenName state.IdentScreenName) (*state.User,
 
 	var r0 *state.User
 	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (*state.User, error)); ok {
-		return rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) (*state.User, error)); ok {
+		return rf(ctx, screenName)
 	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) *state.User); ok {
-		r0 = rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) *state.User); ok {
+		r0 = rf(ctx, screenName)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*state.User)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -252,14 +258,15 @@ type mockUserManager_User_Call struct {
 }
 
 // User is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockUserManager_Expecter) User(screenName interface{}) *mockUserManager_User_Call {
-	return &mockUserManager_User_Call{Call: _e.mock.On("User", screenName)}
+func (_e *mockUserManager_Expecter) User(ctx interface{}, screenName interface{}) *mockUserManager_User_Call {
+	return &mockUserManager_User_Call{Call: _e.mock.On("User", ctx, screenName)}
 }
 
-func (_c *mockUserManager_User_Call) Run(run func(screenName state.IdentScreenName)) *mockUserManager_User_Call {
+func (_c *mockUserManager_User_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockUserManager_User_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
@@ -269,7 +276,7 @@ func (_c *mockUserManager_User_Call) Return(_a0 *state.User, _a1 error) *mockUse
 	return _c
 }
 
-func (_c *mockUserManager_User_Call) RunAndReturn(run func(state.IdentScreenName) (*state.User, error)) *mockUserManager_User_Call {
+func (_c *mockUserManager_User_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) (*state.User, error)) *mockUserManager_User_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 92 - 32
server/http/types.go

@@ -9,61 +9,121 @@ import (
 	"github.com/mk6i/retro-aim-server/wire"
 )
 
-type ChatRoomRetriever interface {
-	AllChatRooms(exchange uint16) ([]state.ChatRoom, error)
+// AccountManager defines methods for managing user account attributes
+// such as email, confirmation status, registration status, and suspension.
+type AccountManager interface {
+	// ConfirmStatus returns whether a user account has been confirmed.
+	ConfirmStatus(ctx context.Context, screenName state.IdentScreenName) (bool, error)
+
+	// EmailAddress looks up a user's email address by screen name.
+	EmailAddress(ctx context.Context, screenName state.IdentScreenName) (*mail.Address, error)
+
+	// RegStatus looks up a user's registration status by screen name.
+	// It returns one of the following values:
+	//   - wire.AdminInfoRegStatusFullDisclosure
+	//   - wire.AdminInfoRegStatusLimitDisclosure
+	//   - wire.AdminInfoRegStatusNoDisclosure
+	RegStatus(ctx context.Context, screenName state.IdentScreenName) (uint16, error)
+
+	// UpdateSuspendedStatus updates the suspension status of a user account.
+	UpdateSuspendedStatus(ctx context.Context, suspendedStatus uint16, screenName state.IdentScreenName) error
 }
 
+// BuddyIconRetriever defines a method for retrieving a buddy icon image by its hash.
+type BuddyIconRetriever interface {
+	// BuddyIcon retrieves a buddy icon image by its md5 hash.
+	BuddyIcon(ctx context.Context, itemHash []byte) ([]byte, error)
+}
+
+// ChatRoomCreator defines a method for creating a new chat room.
 type ChatRoomCreator interface {
-	CreateChatRoom(chatRoom *state.ChatRoom) error
+	// CreateChatRoom creates a new chat room.
+	CreateChatRoom(ctx context.Context, chatRoom *state.ChatRoom) error
+}
+
+// ChatRoomRetriever defines a method for retrieving all chat rooms
+// under a specific exchange.
+type ChatRoomRetriever interface {
+	// AllChatRooms returns all chat rooms associated with the given exchange ID.
+	AllChatRooms(ctx context.Context, exchange uint16) ([]state.ChatRoom, error)
 }
 
+// ChatSessionRetriever defines a method for retrieving all sessions
+// associated with a specific chat room.
 type ChatSessionRetriever interface {
+	// AllSessions returns all active sessions in the chat room identified by cookie.
 	AllSessions(cookie string) []*state.Session
 }
 
-type SessionRetriever interface {
-	AllSessions() []*state.Session
-	RetrieveSession(screenName state.IdentScreenName) *state.Session
+// DirectoryManager defines methods for managing interest categories and keywords
+// used in user profiles and directory listings.
+type DirectoryManager interface {
+	// Categories returns all existing directory categories.
+	Categories(ctx context.Context) ([]state.Category, error)
+
+	// CreateCategory adds a new directory category.
+	CreateCategory(ctx context.Context, name string) (state.Category, error)
+
+	// CreateKeyword adds a new keyword to the specified category.
+	CreateKeyword(ctx context.Context, name string, categoryID uint8) (state.Keyword, error)
+
+	// DeleteCategory removes a directory category by ID.
+	DeleteCategory(ctx context.Context, categoryID uint8) error
+
+	// DeleteKeyword removes a keyword by ID.
+	DeleteKeyword(ctx context.Context, id uint8) error
+
+	// KeywordsByCategory returns all keywords under the specified category.
+	KeywordsByCategory(ctx context.Context, categoryID uint8) ([]state.Keyword, error)
 }
 
-type UserManager interface {
-	AllUsers() ([]state.User, error)
-	DeleteUser(screenName state.IdentScreenName) error
-	InsertUser(u state.User) error
-	SetUserPassword(screenName state.IdentScreenName, newPassword string) error
-	User(screenName state.IdentScreenName) (*state.User, error)
+// FeedBagRetriever defines methods for retrieving buddy list metadata.
+type FeedBagRetriever interface {
+	// BuddyIconMetadata retrieves a user's buddy icon metadata. It returns nil
+	// if the user does not have a buddy icon.
+	BuddyIconMetadata(ctx context.Context, screenName state.IdentScreenName) (*wire.BARTID, error)
 }
 
+// MessageRelayer defines a method for sending a SNAC message to a specific screen name.
 type MessageRelayer interface {
+	// RelayToScreenName sends the given SNAC message to the specified screen name.
 	RelayToScreenName(ctx context.Context, screenName state.IdentScreenName, msg wire.SNACMessage)
 }
 
-type AccountManager interface {
-	EmailAddressByName(screenName state.IdentScreenName) (*mail.Address, error)
-	RegStatusByName(screenName state.IdentScreenName) (uint16, error)
-	ConfirmStatusByName(screenName state.IdentScreenName) (bool, error)
-	UpdateSuspendedStatus(suspendedStatus uint16, screenName state.IdentScreenName) error
+// ProfileRetriever defines a method for retrieving a user's free-form profile.
+type ProfileRetriever interface {
+	// Profile returns the free-form profile body for the given screen name.
+	Profile(ctx context.Context, screenName state.IdentScreenName) (string, error)
 }
 
-type BARTRetriever interface {
-	BARTRetrieve(itemHash []byte) ([]byte, error)
-}
+// SessionRetriever defines methods for retrieving active sessions,
+// either all of them or by screen name.
+type SessionRetriever interface {
+	// AllSessions returns all active user sessions.
+	AllSessions() []*state.Session
 
-type FeedBagRetriever interface {
-	BuddyIconRefByName(screenName state.IdentScreenName) (*wire.BARTID, error)
+	// RetrieveSession returns the session associated with the given screen name,
+	// or nil if no active session exists.
+	RetrieveSession(screenName state.IdentScreenName) *state.Session
 }
 
-type ProfileRetriever interface {
-	Profile(screenName state.IdentScreenName) (string, error)
-}
+// UserManager defines methods for accessing and inserting AIM user records.
+type UserManager interface {
+	// AllUsers returns all registered users.
+	AllUsers(ctx context.Context) ([]state.User, error)
 
-type DirectoryManager interface {
-	Categories() ([]state.Category, error)
-	CreateCategory(name string) (state.Category, error)
-	CreateKeyword(name string, categoryID uint8) (state.Keyword, error)
-	DeleteCategory(categoryID uint8) error
-	DeleteKeyword(id uint8) error
-	KeywordsByCategory(categoryID uint8) ([]state.Keyword, error)
+	// DeleteUser removes a user from the system by screen name.
+	DeleteUser(ctx context.Context, screenName state.IdentScreenName) error
+
+	// InsertUser inserts a new user into the system. Return state.ErrDupUser
+	// if a user with the same screen name already exists.
+	InsertUser(ctx context.Context, u state.User) error
+
+	// SetUserPassword sets the user's password hashes and auth key.
+	SetUserPassword(ctx context.Context, screenName state.IdentScreenName, newPassword string) error
+
+	// User returns all attributes for a user.
+	User(ctx context.Context, screenName state.IdentScreenName) (*state.User, error)
 }
 
 type userWithPassword struct {

+ 1 - 1
server/oscar/admin.go

@@ -90,7 +90,7 @@ func (rt AdminServer) handleNewConnection(ctx context.Context, rwc io.ReadWriteC
 		return errors.New("unable to get session id from payload")
 	}
 
-	sess, err := rt.RetrieveBOSSession(authCookie)
+	sess, err := rt.RetrieveBOSSession(ctx, authCookie)
 	if err != nil {
 		return err
 	}

+ 13 - 13
server/oscar/auth.go

@@ -18,11 +18,11 @@ import (
 )
 
 type AuthService interface {
-	BUCPChallenge(bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID) (wire.SNACMessage, error)
-	BUCPLogin(bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(screenName state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error)
-	FLAPLogin(frame wire.FLAPSignonFrame, newUserFn func(screenName state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error)
+	BUCPChallenge(ctx context.Context, bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID) (wire.SNACMessage, error)
+	BUCPLogin(ctx context.Context, bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(screenName state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error)
+	FLAPLogin(ctx context.Context, frame wire.FLAPSignonFrame, newUserFn func(screenName state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error)
 	RegisterBOSSession(ctx context.Context, authCookie []byte) (*state.Session, error)
-	RetrieveBOSSession(authCookie []byte) (*state.Session, error)
+	RetrieveBOSSession(ctx context.Context, authCookie []byte) (*state.Session, error)
 	RegisterChatSession(ctx context.Context, authCookie []byte) (*state.Session, error)
 	Signout(ctx context.Context, sess *state.Session)
 	SignoutChat(ctx context.Context, sess *state.Session)
@@ -67,7 +67,7 @@ func (rt AuthServer) Start(ctx context.Context) error {
 			defer wg.Done()
 			connCtx := context.WithValue(ctx, "ip", conn.RemoteAddr().String())
 			rt.Logger.DebugContext(connCtx, "accepted connection")
-			if err := rt.handleNewConnection(conn); err != nil {
+			if err := rt.handleNewConnection(connCtx, conn); err != nil {
 				rt.Logger.Info("user session failed", "err", err.Error())
 			}
 		}()
@@ -82,7 +82,7 @@ func (rt AuthServer) Start(ctx context.Context) error {
 	return nil
 }
 
-func (rt AuthServer) handleNewConnection(rwc io.ReadWriteCloser) error {
+func (rt AuthServer) handleNewConnection(ctx context.Context, rwc io.ReadWriteCloser) error {
 	defer rwc.Close()
 
 	flapc := wire.NewFlapClient(100, rwc, rwc)
@@ -100,21 +100,21 @@ func (rt AuthServer) handleNewConnection(rwc io.ReadWriteCloser) error {
 	// indicator of FLAP-auth because older ICQ clients appear to omit the
 	// roasted password TLV when the password is not stored client-side.
 	if _, hasScreenName := signonFrame.Uint16BE(wire.LoginTLVTagsScreenName); hasScreenName {
-		return rt.processFLAPAuth(signonFrame, flapc)
+		return rt.processFLAPAuth(ctx, signonFrame, flapc)
 	}
 
-	return rt.processBUCPAuth(flapc)
+	return rt.processBUCPAuth(ctx, flapc)
 }
 
-func (rt AuthServer) processFLAPAuth(signonFrame wire.FLAPSignonFrame, flapc *wire.FlapClient) error {
-	tlv, err := rt.AuthService.FLAPLogin(signonFrame, state.NewStubUser)
+func (rt AuthServer) processFLAPAuth(ctx context.Context, signonFrame wire.FLAPSignonFrame, flapc *wire.FlapClient) error {
+	tlv, err := rt.AuthService.FLAPLogin(ctx, signonFrame, state.NewStubUser)
 	if err != nil {
 		return err
 	}
 	return flapc.SendSignoffFrame(tlv)
 }
 
-func (rt AuthServer) processBUCPAuth(flapc *wire.FlapClient) error {
+func (rt AuthServer) processBUCPAuth(ctx context.Context, flapc *wire.FlapClient) error {
 	for {
 		frame, err := flapc.ReceiveFLAP()
 		if err != nil {
@@ -139,7 +139,7 @@ func (rt AuthServer) processBUCPAuth(flapc *wire.FlapClient) error {
 				if err := wire.UnmarshalBE(&challengeRequest, buf); err != nil {
 					return err
 				}
-				outSNAC, err := rt.BUCPChallenge(challengeRequest, uuid.New)
+				outSNAC, err := rt.BUCPChallenge(ctx, challengeRequest, uuid.New)
 				if err != nil {
 					return err
 				}
@@ -157,7 +157,7 @@ func (rt AuthServer) processBUCPAuth(flapc *wire.FlapClient) error {
 				if err := wire.UnmarshalBE(&loginRequest, buf); err != nil {
 					return err
 				}
-				outSNAC, err := rt.BUCPLogin(loginRequest, state.NewStubUser)
+				outSNAC, err := rt.BUCPLogin(ctx, loginRequest, state.NewStubUser)
 				if err != nil {
 					return err
 				}

+ 4 - 3
server/oscar/auth_test.go

@@ -2,6 +2,7 @@ package oscar
 
 import (
 	"bytes"
+	"context"
 	"io"
 	"log/slog"
 	"testing"
@@ -70,7 +71,7 @@ func TestBUCPAuthService_handleNewConnection(t *testing.T) {
 
 	authService := newMockAuthService(t)
 	authService.EXPECT().
-		BUCPChallenge(mock.Anything, mock.Anything).
+		BUCPChallenge(matchContext(), mock.Anything, mock.Anything).
 		Return(wire.SNACMessage{
 			Frame: wire.SNACFrame{
 				FoodGroup: wire.BUCP,
@@ -79,7 +80,7 @@ func TestBUCPAuthService_handleNewConnection(t *testing.T) {
 			Body: wire.SNAC_0x17_0x07_BUCPChallengeResponse{},
 		}, nil)
 	authService.EXPECT().
-		BUCPLogin(mock.Anything, mock.Anything).
+		BUCPLogin(matchContext(), mock.Anything, mock.Anything).
 		Return(wire.SNACMessage{
 			Frame: wire.SNACFrame{
 				FoodGroup: wire.BUCP,
@@ -96,5 +97,5 @@ func TestBUCPAuthService_handleNewConnection(t *testing.T) {
 		PipeReader: clientReader,
 		PipeWriter: clientWriter,
 	}
-	assert.NoError(t, rt.handleNewConnection(rwc))
+	assert.NoError(t, rt.handleNewConnection(context.Background(), rwc))
 }

+ 6 - 6
server/oscar/bos.go

@@ -27,9 +27,9 @@ type OnlineNotifier interface {
 // buddy lists. Once registered, a user becomes visible to other users' buddy
 // lists and vice versa.
 type BuddyListRegistry interface {
-	ClearBuddyListRegistry() error
-	RegisterBuddyList(user state.IdentScreenName) error
-	UnregisterBuddyList(user state.IdentScreenName) error
+	ClearBuddyListRegistry(ctx context.Context) error
+	RegisterBuddyList(ctx context.Context, user state.IdentScreenName) error
+	UnregisterBuddyList(ctx context.Context, user state.IdentScreenName) error
 }
 
 // DepartureNotifier is the interface for sending buddy departure notifications
@@ -75,7 +75,7 @@ func (rt BOSServer) Start(ctx context.Context) error {
 	rt.Logger.Info("starting server", "listen_host", rt.ListenAddr, "oscar_host", rt.Config.OSCARHost)
 
 	if rt.BuddyListRegistry != nil { // nil check is a hack until server refactor
-		if err = rt.BuddyListRegistry.ClearBuddyListRegistry(); err != nil {
+		if err = rt.BuddyListRegistry.ClearBuddyListRegistry(ctx); err != nil {
 			return fmt.Errorf("unable to clear client-side buddy list: %s", err.Error())
 		}
 	}
@@ -161,7 +161,7 @@ func (rt BOSServer) handleNewConnection(ctx context.Context, rwc io.ReadWriteClo
 
 	if rt.BuddyListRegistry != nil { // nil check is a hack until server refactor
 		// todo should this check be below defer()?
-		if err := rt.BuddyListRegistry.RegisterBuddyList(sess.IdentScreenName()); err != nil {
+		if err := rt.BuddyListRegistry.RegisterBuddyList(ctx, sess.IdentScreenName()); err != nil {
 			return fmt.Errorf("unable to init buddy list: %w", err)
 		}
 	}
@@ -177,7 +177,7 @@ func (rt BOSServer) handleNewConnection(ctx context.Context, rwc io.ReadWriteClo
 			// buddy list must be cleared before session is closed, otherwise
 			// there will be a race condition that could cause the buddy list
 			// be prematurely deleted.
-			if err := rt.BuddyListRegistry.UnregisterBuddyList(sess.IdentScreenName()); err != nil {
+			if err := rt.BuddyListRegistry.UnregisterBuddyList(ctx, sess.IdentScreenName()); err != nil {
 				rt.Logger.ErrorContext(ctx, "error removing buddy list entry", "err", err.Error())
 			}
 		}

+ 0 - 0
server/oscar/handler/mock_admin_test.go → server/oscar/handler/mock_admin_service_test.go


+ 0 - 0
server/oscar/handler/mock_bart_test.go → server/oscar/handler/mock_bart_service_test.go


+ 0 - 0
server/oscar/handler/mock_buddy_test.go → server/oscar/handler/mock_buddy_service_test.go


+ 0 - 0
server/oscar/handler/mock_chat_nav_test.go → server/oscar/handler/mock_chat_nav_service_test.go


+ 0 - 0
server/oscar/handler/mock_chat_test.go → server/oscar/handler/mock_chat_service_test.go


+ 0 - 0
server/oscar/handler/mock_feedbag_test.go → server/oscar/handler/mock_feedbag_service_test.go


+ 0 - 0
server/oscar/handler/mock_icbm_test.go → server/oscar/handler/mock_icbm_service_test.go


+ 0 - 0
server/oscar/handler/mock_locate_test.go → server/oscar/handler/mock_locate_service_test.go


+ 0 - 0
server/oscar/handler/mock_oservice_test.go → server/oscar/handler/mock_oservice_service_test.go


+ 0 - 0
server/oscar/handler/mock_permit_deny_test.go → server/oscar/handler/mock_permit_deny_service_test.go


+ 15 - 0
server/oscar/helpers_test.go

@@ -0,0 +1,15 @@
+package oscar
+
+import (
+	"context"
+
+	"github.com/stretchr/testify/mock"
+)
+
+// matchContext matches any instance of Context interface.
+func matchContext() interface{} {
+	return mock.MatchedBy(func(ctx any) bool {
+		_, ok := ctx.(context.Context)
+		return ok
+	})
+}

+ 5 - 3
server/oscar/mock_BuddyListRegistry.go

@@ -3,6 +3,8 @@
 package oscar
 
 import (
+	"context"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 )
@@ -21,7 +23,7 @@ func (_m *mockBuddyListRegistry) EXPECT() *mockBuddyListRegistry_Expecter {
 }
 
 // ClearBuddyListRegistry provides a mock function with no fields
-func (_m *mockBuddyListRegistry) ClearBuddyListRegistry() error {
+func (_m *mockBuddyListRegistry) ClearBuddyListRegistry(context.Context) error {
 	ret := _m.Called()
 
 	if len(ret) == 0 {
@@ -66,7 +68,7 @@ func (_c *mockBuddyListRegistry_ClearBuddyListRegistry_Call) RunAndReturn(run fu
 }
 
 // RegisterBuddyList provides a mock function with given fields: user
-func (_m *mockBuddyListRegistry) RegisterBuddyList(user state.IdentScreenName) error {
+func (_m *mockBuddyListRegistry) RegisterBuddyList(ctx context.Context, user state.IdentScreenName) error {
 	ret := _m.Called(user)
 
 	if len(ret) == 0 {
@@ -112,7 +114,7 @@ func (_c *mockBuddyListRegistry_RegisterBuddyList_Call) RunAndReturn(run func(st
 }
 
 // UnregisterBuddyList provides a mock function with given fields: user
-func (_m *mockBuddyListRegistry) UnregisterBuddyList(user state.IdentScreenName) error {
+func (_m *mockBuddyListRegistry) UnregisterBuddyList(ctx context.Context, user state.IdentScreenName) error {
 	ret := _m.Called(user)
 
 	if len(ret) == 0 {

+ 60 - 56
server/oscar/mock_auth_test.go

@@ -26,9 +26,9 @@ func (_m *mockAuthService) EXPECT() *mockAuthService_Expecter {
 	return &mockAuthService_Expecter{mock: &_m.Mock}
 }
 
-// BUCPChallenge provides a mock function with given fields: bodyIn, newUUID
-func (_m *mockAuthService) BUCPChallenge(bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID) (wire.SNACMessage, error) {
-	ret := _m.Called(bodyIn, newUUID)
+// BUCPChallenge provides a mock function with given fields: ctx, bodyIn, newUUID
+func (_m *mockAuthService) BUCPChallenge(ctx context.Context, bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID) (wire.SNACMessage, error) {
+	ret := _m.Called(ctx, bodyIn, newUUID)
 
 	if len(ret) == 0 {
 		panic("no return value specified for BUCPChallenge")
@@ -36,17 +36,17 @@ func (_m *mockAuthService) BUCPChallenge(bodyIn wire.SNAC_0x17_0x06_BUCPChalleng
 
 	var r0 wire.SNACMessage
 	var r1 error
-	if rf, ok := ret.Get(0).(func(wire.SNAC_0x17_0x06_BUCPChallengeRequest, func() uuid.UUID) (wire.SNACMessage, error)); ok {
-		return rf(bodyIn, newUUID)
+	if rf, ok := ret.Get(0).(func(context.Context, wire.SNAC_0x17_0x06_BUCPChallengeRequest, func() uuid.UUID) (wire.SNACMessage, error)); ok {
+		return rf(ctx, bodyIn, newUUID)
 	}
-	if rf, ok := ret.Get(0).(func(wire.SNAC_0x17_0x06_BUCPChallengeRequest, func() uuid.UUID) wire.SNACMessage); ok {
-		r0 = rf(bodyIn, newUUID)
+	if rf, ok := ret.Get(0).(func(context.Context, wire.SNAC_0x17_0x06_BUCPChallengeRequest, func() uuid.UUID) wire.SNACMessage); ok {
+		r0 = rf(ctx, bodyIn, newUUID)
 	} else {
 		r0 = ret.Get(0).(wire.SNACMessage)
 	}
 
-	if rf, ok := ret.Get(1).(func(wire.SNAC_0x17_0x06_BUCPChallengeRequest, func() uuid.UUID) error); ok {
-		r1 = rf(bodyIn, newUUID)
+	if rf, ok := ret.Get(1).(func(context.Context, wire.SNAC_0x17_0x06_BUCPChallengeRequest, func() uuid.UUID) error); ok {
+		r1 = rf(ctx, bodyIn, newUUID)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -60,15 +60,16 @@ type mockAuthService_BUCPChallenge_Call struct {
 }
 
 // BUCPChallenge is a helper method to define mock.On call
+//   - ctx context.Context
 //   - bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest
 //   - newUUID func() uuid.UUID
-func (_e *mockAuthService_Expecter) BUCPChallenge(bodyIn interface{}, newUUID interface{}) *mockAuthService_BUCPChallenge_Call {
-	return &mockAuthService_BUCPChallenge_Call{Call: _e.mock.On("BUCPChallenge", bodyIn, newUUID)}
+func (_e *mockAuthService_Expecter) BUCPChallenge(ctx interface{}, bodyIn interface{}, newUUID interface{}) *mockAuthService_BUCPChallenge_Call {
+	return &mockAuthService_BUCPChallenge_Call{Call: _e.mock.On("BUCPChallenge", ctx, bodyIn, newUUID)}
 }
 
-func (_c *mockAuthService_BUCPChallenge_Call) Run(run func(bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID)) *mockAuthService_BUCPChallenge_Call {
+func (_c *mockAuthService_BUCPChallenge_Call) Run(run func(ctx context.Context, bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID)) *mockAuthService_BUCPChallenge_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(wire.SNAC_0x17_0x06_BUCPChallengeRequest), args[1].(func() uuid.UUID))
+		run(args[0].(context.Context), args[1].(wire.SNAC_0x17_0x06_BUCPChallengeRequest), args[2].(func() uuid.UUID))
 	})
 	return _c
 }
@@ -78,14 +79,14 @@ func (_c *mockAuthService_BUCPChallenge_Call) Return(_a0 wire.SNACMessage, _a1 e
 	return _c
 }
 
-func (_c *mockAuthService_BUCPChallenge_Call) RunAndReturn(run func(wire.SNAC_0x17_0x06_BUCPChallengeRequest, func() uuid.UUID) (wire.SNACMessage, error)) *mockAuthService_BUCPChallenge_Call {
+func (_c *mockAuthService_BUCPChallenge_Call) RunAndReturn(run func(context.Context, wire.SNAC_0x17_0x06_BUCPChallengeRequest, func() uuid.UUID) (wire.SNACMessage, error)) *mockAuthService_BUCPChallenge_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// BUCPLogin provides a mock function with given fields: bodyIn, newUserFn
-func (_m *mockAuthService) BUCPLogin(bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error) {
-	ret := _m.Called(bodyIn, newUserFn)
+// BUCPLogin provides a mock function with given fields: ctx, bodyIn, newUserFn
+func (_m *mockAuthService) BUCPLogin(ctx context.Context, bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error) {
+	ret := _m.Called(ctx, bodyIn, newUserFn)
 
 	if len(ret) == 0 {
 		panic("no return value specified for BUCPLogin")
@@ -93,17 +94,17 @@ func (_m *mockAuthService) BUCPLogin(bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest
 
 	var r0 wire.SNACMessage
 	var r1 error
-	if rf, ok := ret.Get(0).(func(wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error)); ok {
-		return rf(bodyIn, newUserFn)
+	if rf, ok := ret.Get(0).(func(context.Context, wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error)); ok {
+		return rf(ctx, bodyIn, newUserFn)
 	}
-	if rf, ok := ret.Get(0).(func(wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) wire.SNACMessage); ok {
-		r0 = rf(bodyIn, newUserFn)
+	if rf, ok := ret.Get(0).(func(context.Context, wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) wire.SNACMessage); ok {
+		r0 = rf(ctx, bodyIn, newUserFn)
 	} else {
 		r0 = ret.Get(0).(wire.SNACMessage)
 	}
 
-	if rf, ok := ret.Get(1).(func(wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) error); ok {
-		r1 = rf(bodyIn, newUserFn)
+	if rf, ok := ret.Get(1).(func(context.Context, wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) error); ok {
+		r1 = rf(ctx, bodyIn, newUserFn)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -117,15 +118,16 @@ type mockAuthService_BUCPLogin_Call struct {
 }
 
 // BUCPLogin is a helper method to define mock.On call
+//   - ctx context.Context
 //   - bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest
 //   - newUserFn func(state.DisplayScreenName)(state.User , error)
-func (_e *mockAuthService_Expecter) BUCPLogin(bodyIn interface{}, newUserFn interface{}) *mockAuthService_BUCPLogin_Call {
-	return &mockAuthService_BUCPLogin_Call{Call: _e.mock.On("BUCPLogin", bodyIn, newUserFn)}
+func (_e *mockAuthService_Expecter) BUCPLogin(ctx interface{}, bodyIn interface{}, newUserFn interface{}) *mockAuthService_BUCPLogin_Call {
+	return &mockAuthService_BUCPLogin_Call{Call: _e.mock.On("BUCPLogin", ctx, bodyIn, newUserFn)}
 }
 
-func (_c *mockAuthService_BUCPLogin_Call) Run(run func(bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(state.DisplayScreenName) (state.User, error))) *mockAuthService_BUCPLogin_Call {
+func (_c *mockAuthService_BUCPLogin_Call) Run(run func(ctx context.Context, bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(state.DisplayScreenName) (state.User, error))) *mockAuthService_BUCPLogin_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(wire.SNAC_0x17_0x02_BUCPLoginRequest), args[1].(func(state.DisplayScreenName) (state.User, error)))
+		run(args[0].(context.Context), args[1].(wire.SNAC_0x17_0x02_BUCPLoginRequest), args[2].(func(state.DisplayScreenName) (state.User, error)))
 	})
 	return _c
 }
@@ -135,14 +137,14 @@ func (_c *mockAuthService_BUCPLogin_Call) Return(_a0 wire.SNACMessage, _a1 error
 	return _c
 }
 
-func (_c *mockAuthService_BUCPLogin_Call) RunAndReturn(run func(wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error)) *mockAuthService_BUCPLogin_Call {
+func (_c *mockAuthService_BUCPLogin_Call) RunAndReturn(run func(context.Context, wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error)) *mockAuthService_BUCPLogin_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// FLAPLogin provides a mock function with given fields: frame, newUserFn
-func (_m *mockAuthService) FLAPLogin(frame wire.FLAPSignonFrame, newUserFn func(state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error) {
-	ret := _m.Called(frame, newUserFn)
+// FLAPLogin provides a mock function with given fields: ctx, frame, newUserFn
+func (_m *mockAuthService) FLAPLogin(ctx context.Context, frame wire.FLAPSignonFrame, newUserFn func(state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error) {
+	ret := _m.Called(ctx, frame, newUserFn)
 
 	if len(ret) == 0 {
 		panic("no return value specified for FLAPLogin")
@@ -150,17 +152,17 @@ func (_m *mockAuthService) FLAPLogin(frame wire.FLAPSignonFrame, newUserFn func(
 
 	var r0 wire.TLVRestBlock
 	var r1 error
-	if rf, ok := ret.Get(0).(func(wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error)); ok {
-		return rf(frame, newUserFn)
+	if rf, ok := ret.Get(0).(func(context.Context, wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error)); ok {
+		return rf(ctx, frame, newUserFn)
 	}
-	if rf, ok := ret.Get(0).(func(wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) wire.TLVRestBlock); ok {
-		r0 = rf(frame, newUserFn)
+	if rf, ok := ret.Get(0).(func(context.Context, wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) wire.TLVRestBlock); ok {
+		r0 = rf(ctx, frame, newUserFn)
 	} else {
 		r0 = ret.Get(0).(wire.TLVRestBlock)
 	}
 
-	if rf, ok := ret.Get(1).(func(wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) error); ok {
-		r1 = rf(frame, newUserFn)
+	if rf, ok := ret.Get(1).(func(context.Context, wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) error); ok {
+		r1 = rf(ctx, frame, newUserFn)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -174,15 +176,16 @@ type mockAuthService_FLAPLogin_Call struct {
 }
 
 // FLAPLogin is a helper method to define mock.On call
+//   - ctx context.Context
 //   - frame wire.FLAPSignonFrame
 //   - newUserFn func(state.DisplayScreenName)(state.User , error)
-func (_e *mockAuthService_Expecter) FLAPLogin(frame interface{}, newUserFn interface{}) *mockAuthService_FLAPLogin_Call {
-	return &mockAuthService_FLAPLogin_Call{Call: _e.mock.On("FLAPLogin", frame, newUserFn)}
+func (_e *mockAuthService_Expecter) FLAPLogin(ctx interface{}, frame interface{}, newUserFn interface{}) *mockAuthService_FLAPLogin_Call {
+	return &mockAuthService_FLAPLogin_Call{Call: _e.mock.On("FLAPLogin", ctx, frame, newUserFn)}
 }
 
-func (_c *mockAuthService_FLAPLogin_Call) Run(run func(frame wire.FLAPSignonFrame, newUserFn func(state.DisplayScreenName) (state.User, error))) *mockAuthService_FLAPLogin_Call {
+func (_c *mockAuthService_FLAPLogin_Call) Run(run func(ctx context.Context, frame wire.FLAPSignonFrame, newUserFn func(state.DisplayScreenName) (state.User, error))) *mockAuthService_FLAPLogin_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(wire.FLAPSignonFrame), args[1].(func(state.DisplayScreenName) (state.User, error)))
+		run(args[0].(context.Context), args[1].(wire.FLAPSignonFrame), args[2].(func(state.DisplayScreenName) (state.User, error)))
 	})
 	return _c
 }
@@ -192,7 +195,7 @@ func (_c *mockAuthService_FLAPLogin_Call) Return(_a0 wire.TLVRestBlock, _a1 erro
 	return _c
 }
 
-func (_c *mockAuthService_FLAPLogin_Call) RunAndReturn(run func(wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error)) *mockAuthService_FLAPLogin_Call {
+func (_c *mockAuthService_FLAPLogin_Call) RunAndReturn(run func(context.Context, wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error)) *mockAuthService_FLAPLogin_Call {
 	_c.Call.Return(run)
 	return _c
 }
@@ -315,9 +318,9 @@ func (_c *mockAuthService_RegisterChatSession_Call) RunAndReturn(run func(contex
 	return _c
 }
 
-// RetrieveBOSSession provides a mock function with given fields: authCookie
-func (_m *mockAuthService) RetrieveBOSSession(authCookie []byte) (*state.Session, error) {
-	ret := _m.Called(authCookie)
+// RetrieveBOSSession provides a mock function with given fields: ctx, authCookie
+func (_m *mockAuthService) RetrieveBOSSession(ctx context.Context, authCookie []byte) (*state.Session, error) {
+	ret := _m.Called(ctx, authCookie)
 
 	if len(ret) == 0 {
 		panic("no return value specified for RetrieveBOSSession")
@@ -325,19 +328,19 @@ func (_m *mockAuthService) RetrieveBOSSession(authCookie []byte) (*state.Session
 
 	var r0 *state.Session
 	var r1 error
-	if rf, ok := ret.Get(0).(func([]byte) (*state.Session, error)); ok {
-		return rf(authCookie)
+	if rf, ok := ret.Get(0).(func(context.Context, []byte) (*state.Session, error)); ok {
+		return rf(ctx, authCookie)
 	}
-	if rf, ok := ret.Get(0).(func([]byte) *state.Session); ok {
-		r0 = rf(authCookie)
+	if rf, ok := ret.Get(0).(func(context.Context, []byte) *state.Session); ok {
+		r0 = rf(ctx, authCookie)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*state.Session)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func([]byte) error); ok {
-		r1 = rf(authCookie)
+	if rf, ok := ret.Get(1).(func(context.Context, []byte) error); ok {
+		r1 = rf(ctx, authCookie)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -351,14 +354,15 @@ type mockAuthService_RetrieveBOSSession_Call struct {
 }
 
 // RetrieveBOSSession is a helper method to define mock.On call
+//   - ctx context.Context
 //   - authCookie []byte
-func (_e *mockAuthService_Expecter) RetrieveBOSSession(authCookie interface{}) *mockAuthService_RetrieveBOSSession_Call {
-	return &mockAuthService_RetrieveBOSSession_Call{Call: _e.mock.On("RetrieveBOSSession", authCookie)}
+func (_e *mockAuthService_Expecter) RetrieveBOSSession(ctx interface{}, authCookie interface{}) *mockAuthService_RetrieveBOSSession_Call {
+	return &mockAuthService_RetrieveBOSSession_Call{Call: _e.mock.On("RetrieveBOSSession", ctx, authCookie)}
 }
 
-func (_c *mockAuthService_RetrieveBOSSession_Call) Run(run func(authCookie []byte)) *mockAuthService_RetrieveBOSSession_Call {
+func (_c *mockAuthService_RetrieveBOSSession_Call) Run(run func(ctx context.Context, authCookie []byte)) *mockAuthService_RetrieveBOSSession_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].([]byte))
+		run(args[0].(context.Context), args[1].([]byte))
 	})
 	return _c
 }
@@ -368,7 +372,7 @@ func (_c *mockAuthService_RetrieveBOSSession_Call) Return(_a0 *state.Session, _a
 	return _c
 }
 
-func (_c *mockAuthService_RetrieveBOSSession_Call) RunAndReturn(run func([]byte) (*state.Session, error)) *mockAuthService_RetrieveBOSSession_Call {
+func (_c *mockAuthService_RetrieveBOSSession_Call) RunAndReturn(run func(context.Context, []byte) (*state.Session, error)) *mockAuthService_RetrieveBOSSession_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 5 - 5
server/toc/cmd_client.go

@@ -1385,7 +1385,7 @@ func (s OSCARProxy) SetConfig(ctx context.Context, me *state.Session, args []byt
 		return s.runtimeErr(ctx, fmt.Errorf("empty config"))
 	}
 
-	if err := s.TOCConfigStore.SetTOCConfig(me.IdentScreenName(), config); err != nil {
+	if err := s.TOCConfigStore.SetTOCConfig(ctx, me.IdentScreenName(), config); err != nil {
 		return s.runtimeErr(ctx, fmt.Errorf("TOCConfigStore.SaveTOCConfig: %w", err))
 	}
 
@@ -1545,7 +1545,7 @@ func (s OSCARProxy) Signon(ctx context.Context, args []byte) (*state.Session, []
 	signonFrame.Append(wire.NewTLVBE(wire.LoginTLVTagsScreenName, userName))
 	signonFrame.Append(wire.NewTLVBE(wire.LoginTLVTagsRoastedTOCPassword, passwordHash))
 
-	block, err := s.AuthService.FLAPLogin(signonFrame, state.NewStubUser)
+	block, err := s.AuthService.FLAPLogin(ctx, signonFrame, state.NewStubUser)
 	if err != nil {
 		return nil, []string{s.runtimeErr(ctx, fmt.Errorf("AuthService.FLAPLogin: %w", err))}
 	}
@@ -1568,11 +1568,11 @@ func (s OSCARProxy) Signon(ctx context.Context, args []byte) (*state.Session, []
 	// set chat capability so that... tk
 	sess.SetCaps([][16]byte{wire.CapChat})
 
-	if err := s.BuddyListRegistry.RegisterBuddyList(sess.IdentScreenName()); err != nil {
+	if err := s.BuddyListRegistry.RegisterBuddyList(ctx, sess.IdentScreenName()); err != nil {
 		return nil, []string{s.runtimeErr(ctx, fmt.Errorf("BuddyListRegistry.RegisterBuddyList: %w", err))}
 	}
 
-	u, err := s.TOCConfigStore.User(sess.IdentScreenName())
+	u, err := s.TOCConfigStore.User(ctx, sess.IdentScreenName())
 	if err != nil {
 		return nil, []string{s.runtimeErr(ctx, fmt.Errorf("TOCConfigStore.User: %w", err))}
 	}
@@ -1589,7 +1589,7 @@ func (s OSCARProxy) Signout(ctx context.Context, me *state.Session, chatRegistry
 	if err := s.BuddyService.BroadcastBuddyDeparted(ctx, me); err != nil {
 		s.Logger.ErrorContext(ctx, "error sending departure notifications", "err", err.Error())
 	}
-	if err := s.BuddyListRegistry.UnregisterBuddyList(me.IdentScreenName()); err != nil {
+	if err := s.BuddyListRegistry.UnregisterBuddyList(ctx, me.IdentScreenName()); err != nil {
 		s.Logger.ErrorContext(ctx, "error removing buddy list entry", "err", err.Error())
 	}
 	s.AuthService.Signout(ctx, me)

+ 6 - 6
server/toc/cmd_client_test.go

@@ -3320,7 +3320,7 @@ func TestOSCARProxy_RecvClientCmd_SetConfig(t *testing.T) {
 			tocConfigSvc := newMockTOCConfigStore(t)
 			for _, params := range tc.mockParams.setTOCConfigParams {
 				tocConfigSvc.EXPECT().
-					SetTOCConfig(params.user, params.config).
+					SetTOCConfig(matchContext(), params.user, params.config).
 					Return(params.err)
 			}
 
@@ -3970,24 +3970,24 @@ func TestOSCARProxy_Signon(t *testing.T) {
 			authSvc := newMockAuthService(t)
 			for _, params := range tc.mockParams.flapLoginParams {
 				authSvc.EXPECT().
-					FLAPLogin(params.frame, mock.Anything).
+					FLAPLogin(matchContext(), params.frame, mock.Anything).
 					Return(params.tlv, params.err)
 			}
 			for _, params := range tc.mockParams.registerBOSSessionParams {
 				authSvc.EXPECT().
-					RegisterBOSSession(ctx, params.authCookie).
+					RegisterBOSSession(matchContext(), params.authCookie).
 					Return(params.sess, params.err)
 			}
 			buddyRegistry := newMockBuddyListRegistry(t)
 			for _, params := range tc.mockParams.registerBuddyListParams {
 				buddyRegistry.EXPECT().
-					RegisterBuddyList(params.user).
+					RegisterBuddyList(matchContext(), params.user).
 					Return(params.err)
 			}
 			tocCfg := newMockTOCConfigStore(t)
 			for _, params := range tc.mockParams.userParams {
 				tocCfg.EXPECT().
-					User(params.screenName).
+					User(matchContext(), params.screenName).
 					Return(params.returnedUser, params.err)
 			}
 
@@ -4148,7 +4148,7 @@ func TestOSCARProxy_Signout(t *testing.T) {
 			buddyListSvc := newMockBuddyListRegistry(t)
 			for _, params := range tc.mockParams.unregisterBuddyListParams {
 				buddyListSvc.EXPECT().
-					UnregisterBuddyList(params.user).
+					UnregisterBuddyList(matchContext(), params.user).
 					Return(params.err)
 			}
 

+ 10 - 0
server/toc/helpers_test.go

@@ -1,6 +1,8 @@
 package toc
 
 import (
+	"context"
+
 	"github.com/stretchr/testify/mock"
 
 	"github.com/mk6i/retro-aim-server/state"
@@ -289,3 +291,11 @@ func newTestSession(screenName state.DisplayScreenName, options ...func(session
 	}
 	return s
 }
+
+// matchContext matches any instance of Context interface.
+func matchContext() interface{} {
+	return mock.MatchedBy(func(ctx any) bool {
+		_, ok := ctx.(context.Context)
+		return ok
+	})
+}

+ 60 - 56
server/toc/mock_auth_service_test.go

@@ -26,9 +26,9 @@ func (_m *mockAuthService) EXPECT() *mockAuthService_Expecter {
 	return &mockAuthService_Expecter{mock: &_m.Mock}
 }
 
-// BUCPChallenge provides a mock function with given fields: bodyIn, newUUID
-func (_m *mockAuthService) BUCPChallenge(bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID) (wire.SNACMessage, error) {
-	ret := _m.Called(bodyIn, newUUID)
+// BUCPChallenge provides a mock function with given fields: ctx, bodyIn, newUUID
+func (_m *mockAuthService) BUCPChallenge(ctx context.Context, bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID) (wire.SNACMessage, error) {
+	ret := _m.Called(ctx, bodyIn, newUUID)
 
 	if len(ret) == 0 {
 		panic("no return value specified for BUCPChallenge")
@@ -36,17 +36,17 @@ func (_m *mockAuthService) BUCPChallenge(bodyIn wire.SNAC_0x17_0x06_BUCPChalleng
 
 	var r0 wire.SNACMessage
 	var r1 error
-	if rf, ok := ret.Get(0).(func(wire.SNAC_0x17_0x06_BUCPChallengeRequest, func() uuid.UUID) (wire.SNACMessage, error)); ok {
-		return rf(bodyIn, newUUID)
+	if rf, ok := ret.Get(0).(func(context.Context, wire.SNAC_0x17_0x06_BUCPChallengeRequest, func() uuid.UUID) (wire.SNACMessage, error)); ok {
+		return rf(ctx, bodyIn, newUUID)
 	}
-	if rf, ok := ret.Get(0).(func(wire.SNAC_0x17_0x06_BUCPChallengeRequest, func() uuid.UUID) wire.SNACMessage); ok {
-		r0 = rf(bodyIn, newUUID)
+	if rf, ok := ret.Get(0).(func(context.Context, wire.SNAC_0x17_0x06_BUCPChallengeRequest, func() uuid.UUID) wire.SNACMessage); ok {
+		r0 = rf(ctx, bodyIn, newUUID)
 	} else {
 		r0 = ret.Get(0).(wire.SNACMessage)
 	}
 
-	if rf, ok := ret.Get(1).(func(wire.SNAC_0x17_0x06_BUCPChallengeRequest, func() uuid.UUID) error); ok {
-		r1 = rf(bodyIn, newUUID)
+	if rf, ok := ret.Get(1).(func(context.Context, wire.SNAC_0x17_0x06_BUCPChallengeRequest, func() uuid.UUID) error); ok {
+		r1 = rf(ctx, bodyIn, newUUID)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -60,15 +60,16 @@ type mockAuthService_BUCPChallenge_Call struct {
 }
 
 // BUCPChallenge is a helper method to define mock.On call
+//   - ctx context.Context
 //   - bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest
 //   - newUUID func() uuid.UUID
-func (_e *mockAuthService_Expecter) BUCPChallenge(bodyIn interface{}, newUUID interface{}) *mockAuthService_BUCPChallenge_Call {
-	return &mockAuthService_BUCPChallenge_Call{Call: _e.mock.On("BUCPChallenge", bodyIn, newUUID)}
+func (_e *mockAuthService_Expecter) BUCPChallenge(ctx interface{}, bodyIn interface{}, newUUID interface{}) *mockAuthService_BUCPChallenge_Call {
+	return &mockAuthService_BUCPChallenge_Call{Call: _e.mock.On("BUCPChallenge", ctx, bodyIn, newUUID)}
 }
 
-func (_c *mockAuthService_BUCPChallenge_Call) Run(run func(bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID)) *mockAuthService_BUCPChallenge_Call {
+func (_c *mockAuthService_BUCPChallenge_Call) Run(run func(ctx context.Context, bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID)) *mockAuthService_BUCPChallenge_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(wire.SNAC_0x17_0x06_BUCPChallengeRequest), args[1].(func() uuid.UUID))
+		run(args[0].(context.Context), args[1].(wire.SNAC_0x17_0x06_BUCPChallengeRequest), args[2].(func() uuid.UUID))
 	})
 	return _c
 }
@@ -78,14 +79,14 @@ func (_c *mockAuthService_BUCPChallenge_Call) Return(_a0 wire.SNACMessage, _a1 e
 	return _c
 }
 
-func (_c *mockAuthService_BUCPChallenge_Call) RunAndReturn(run func(wire.SNAC_0x17_0x06_BUCPChallengeRequest, func() uuid.UUID) (wire.SNACMessage, error)) *mockAuthService_BUCPChallenge_Call {
+func (_c *mockAuthService_BUCPChallenge_Call) RunAndReturn(run func(context.Context, wire.SNAC_0x17_0x06_BUCPChallengeRequest, func() uuid.UUID) (wire.SNACMessage, error)) *mockAuthService_BUCPChallenge_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// BUCPLogin provides a mock function with given fields: bodyIn, newUserFn
-func (_m *mockAuthService) BUCPLogin(bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error) {
-	ret := _m.Called(bodyIn, newUserFn)
+// BUCPLogin provides a mock function with given fields: ctx, bodyIn, newUserFn
+func (_m *mockAuthService) BUCPLogin(ctx context.Context, bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error) {
+	ret := _m.Called(ctx, bodyIn, newUserFn)
 
 	if len(ret) == 0 {
 		panic("no return value specified for BUCPLogin")
@@ -93,17 +94,17 @@ func (_m *mockAuthService) BUCPLogin(bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest
 
 	var r0 wire.SNACMessage
 	var r1 error
-	if rf, ok := ret.Get(0).(func(wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error)); ok {
-		return rf(bodyIn, newUserFn)
+	if rf, ok := ret.Get(0).(func(context.Context, wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error)); ok {
+		return rf(ctx, bodyIn, newUserFn)
 	}
-	if rf, ok := ret.Get(0).(func(wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) wire.SNACMessage); ok {
-		r0 = rf(bodyIn, newUserFn)
+	if rf, ok := ret.Get(0).(func(context.Context, wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) wire.SNACMessage); ok {
+		r0 = rf(ctx, bodyIn, newUserFn)
 	} else {
 		r0 = ret.Get(0).(wire.SNACMessage)
 	}
 
-	if rf, ok := ret.Get(1).(func(wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) error); ok {
-		r1 = rf(bodyIn, newUserFn)
+	if rf, ok := ret.Get(1).(func(context.Context, wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) error); ok {
+		r1 = rf(ctx, bodyIn, newUserFn)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -117,15 +118,16 @@ type mockAuthService_BUCPLogin_Call struct {
 }
 
 // BUCPLogin is a helper method to define mock.On call
+//   - ctx context.Context
 //   - bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest
 //   - newUserFn func(state.DisplayScreenName)(state.User , error)
-func (_e *mockAuthService_Expecter) BUCPLogin(bodyIn interface{}, newUserFn interface{}) *mockAuthService_BUCPLogin_Call {
-	return &mockAuthService_BUCPLogin_Call{Call: _e.mock.On("BUCPLogin", bodyIn, newUserFn)}
+func (_e *mockAuthService_Expecter) BUCPLogin(ctx interface{}, bodyIn interface{}, newUserFn interface{}) *mockAuthService_BUCPLogin_Call {
+	return &mockAuthService_BUCPLogin_Call{Call: _e.mock.On("BUCPLogin", ctx, bodyIn, newUserFn)}
 }
 
-func (_c *mockAuthService_BUCPLogin_Call) Run(run func(bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(state.DisplayScreenName) (state.User, error))) *mockAuthService_BUCPLogin_Call {
+func (_c *mockAuthService_BUCPLogin_Call) Run(run func(ctx context.Context, bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(state.DisplayScreenName) (state.User, error))) *mockAuthService_BUCPLogin_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(wire.SNAC_0x17_0x02_BUCPLoginRequest), args[1].(func(state.DisplayScreenName) (state.User, error)))
+		run(args[0].(context.Context), args[1].(wire.SNAC_0x17_0x02_BUCPLoginRequest), args[2].(func(state.DisplayScreenName) (state.User, error)))
 	})
 	return _c
 }
@@ -135,14 +137,14 @@ func (_c *mockAuthService_BUCPLogin_Call) Return(_a0 wire.SNACMessage, _a1 error
 	return _c
 }
 
-func (_c *mockAuthService_BUCPLogin_Call) RunAndReturn(run func(wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error)) *mockAuthService_BUCPLogin_Call {
+func (_c *mockAuthService_BUCPLogin_Call) RunAndReturn(run func(context.Context, wire.SNAC_0x17_0x02_BUCPLoginRequest, func(state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error)) *mockAuthService_BUCPLogin_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// FLAPLogin provides a mock function with given fields: frame, newUserFn
-func (_m *mockAuthService) FLAPLogin(frame wire.FLAPSignonFrame, newUserFn func(state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error) {
-	ret := _m.Called(frame, newUserFn)
+// FLAPLogin provides a mock function with given fields: ctx, frame, newUserFn
+func (_m *mockAuthService) FLAPLogin(ctx context.Context, frame wire.FLAPSignonFrame, newUserFn func(state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error) {
+	ret := _m.Called(ctx, frame, newUserFn)
 
 	if len(ret) == 0 {
 		panic("no return value specified for FLAPLogin")
@@ -150,17 +152,17 @@ func (_m *mockAuthService) FLAPLogin(frame wire.FLAPSignonFrame, newUserFn func(
 
 	var r0 wire.TLVRestBlock
 	var r1 error
-	if rf, ok := ret.Get(0).(func(wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error)); ok {
-		return rf(frame, newUserFn)
+	if rf, ok := ret.Get(0).(func(context.Context, wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error)); ok {
+		return rf(ctx, frame, newUserFn)
 	}
-	if rf, ok := ret.Get(0).(func(wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) wire.TLVRestBlock); ok {
-		r0 = rf(frame, newUserFn)
+	if rf, ok := ret.Get(0).(func(context.Context, wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) wire.TLVRestBlock); ok {
+		r0 = rf(ctx, frame, newUserFn)
 	} else {
 		r0 = ret.Get(0).(wire.TLVRestBlock)
 	}
 
-	if rf, ok := ret.Get(1).(func(wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) error); ok {
-		r1 = rf(frame, newUserFn)
+	if rf, ok := ret.Get(1).(func(context.Context, wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) error); ok {
+		r1 = rf(ctx, frame, newUserFn)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -174,15 +176,16 @@ type mockAuthService_FLAPLogin_Call struct {
 }
 
 // FLAPLogin is a helper method to define mock.On call
+//   - ctx context.Context
 //   - frame wire.FLAPSignonFrame
 //   - newUserFn func(state.DisplayScreenName)(state.User , error)
-func (_e *mockAuthService_Expecter) FLAPLogin(frame interface{}, newUserFn interface{}) *mockAuthService_FLAPLogin_Call {
-	return &mockAuthService_FLAPLogin_Call{Call: _e.mock.On("FLAPLogin", frame, newUserFn)}
+func (_e *mockAuthService_Expecter) FLAPLogin(ctx interface{}, frame interface{}, newUserFn interface{}) *mockAuthService_FLAPLogin_Call {
+	return &mockAuthService_FLAPLogin_Call{Call: _e.mock.On("FLAPLogin", ctx, frame, newUserFn)}
 }
 
-func (_c *mockAuthService_FLAPLogin_Call) Run(run func(frame wire.FLAPSignonFrame, newUserFn func(state.DisplayScreenName) (state.User, error))) *mockAuthService_FLAPLogin_Call {
+func (_c *mockAuthService_FLAPLogin_Call) Run(run func(ctx context.Context, frame wire.FLAPSignonFrame, newUserFn func(state.DisplayScreenName) (state.User, error))) *mockAuthService_FLAPLogin_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(wire.FLAPSignonFrame), args[1].(func(state.DisplayScreenName) (state.User, error)))
+		run(args[0].(context.Context), args[1].(wire.FLAPSignonFrame), args[2].(func(state.DisplayScreenName) (state.User, error)))
 	})
 	return _c
 }
@@ -192,7 +195,7 @@ func (_c *mockAuthService_FLAPLogin_Call) Return(_a0 wire.TLVRestBlock, _a1 erro
 	return _c
 }
 
-func (_c *mockAuthService_FLAPLogin_Call) RunAndReturn(run func(wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error)) *mockAuthService_FLAPLogin_Call {
+func (_c *mockAuthService_FLAPLogin_Call) RunAndReturn(run func(context.Context, wire.FLAPSignonFrame, func(state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error)) *mockAuthService_FLAPLogin_Call {
 	_c.Call.Return(run)
 	return _c
 }
@@ -315,9 +318,9 @@ func (_c *mockAuthService_RegisterChatSession_Call) RunAndReturn(run func(contex
 	return _c
 }
 
-// RetrieveBOSSession provides a mock function with given fields: authCookie
-func (_m *mockAuthService) RetrieveBOSSession(authCookie []byte) (*state.Session, error) {
-	ret := _m.Called(authCookie)
+// RetrieveBOSSession provides a mock function with given fields: ctx, authCookie
+func (_m *mockAuthService) RetrieveBOSSession(ctx context.Context, authCookie []byte) (*state.Session, error) {
+	ret := _m.Called(ctx, authCookie)
 
 	if len(ret) == 0 {
 		panic("no return value specified for RetrieveBOSSession")
@@ -325,19 +328,19 @@ func (_m *mockAuthService) RetrieveBOSSession(authCookie []byte) (*state.Session
 
 	var r0 *state.Session
 	var r1 error
-	if rf, ok := ret.Get(0).(func([]byte) (*state.Session, error)); ok {
-		return rf(authCookie)
+	if rf, ok := ret.Get(0).(func(context.Context, []byte) (*state.Session, error)); ok {
+		return rf(ctx, authCookie)
 	}
-	if rf, ok := ret.Get(0).(func([]byte) *state.Session); ok {
-		r0 = rf(authCookie)
+	if rf, ok := ret.Get(0).(func(context.Context, []byte) *state.Session); ok {
+		r0 = rf(ctx, authCookie)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*state.Session)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func([]byte) error); ok {
-		r1 = rf(authCookie)
+	if rf, ok := ret.Get(1).(func(context.Context, []byte) error); ok {
+		r1 = rf(ctx, authCookie)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -351,14 +354,15 @@ type mockAuthService_RetrieveBOSSession_Call struct {
 }
 
 // RetrieveBOSSession is a helper method to define mock.On call
+//   - ctx context.Context
 //   - authCookie []byte
-func (_e *mockAuthService_Expecter) RetrieveBOSSession(authCookie interface{}) *mockAuthService_RetrieveBOSSession_Call {
-	return &mockAuthService_RetrieveBOSSession_Call{Call: _e.mock.On("RetrieveBOSSession", authCookie)}
+func (_e *mockAuthService_Expecter) RetrieveBOSSession(ctx interface{}, authCookie interface{}) *mockAuthService_RetrieveBOSSession_Call {
+	return &mockAuthService_RetrieveBOSSession_Call{Call: _e.mock.On("RetrieveBOSSession", ctx, authCookie)}
 }
 
-func (_c *mockAuthService_RetrieveBOSSession_Call) Run(run func(authCookie []byte)) *mockAuthService_RetrieveBOSSession_Call {
+func (_c *mockAuthService_RetrieveBOSSession_Call) Run(run func(ctx context.Context, authCookie []byte)) *mockAuthService_RetrieveBOSSession_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].([]byte))
+		run(args[0].(context.Context), args[1].([]byte))
 	})
 	return _c
 }
@@ -368,7 +372,7 @@ func (_c *mockAuthService_RetrieveBOSSession_Call) Return(_a0 *state.Session, _a
 	return _c
 }
 
-func (_c *mockAuthService_RetrieveBOSSession_Call) RunAndReturn(run func([]byte) (*state.Session, error)) *mockAuthService_RetrieveBOSSession_Call {
+func (_c *mockAuthService_RetrieveBOSSession_Call) RunAndReturn(run func(context.Context, []byte) (*state.Session, error)) *mockAuthService_RetrieveBOSSession_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 24 - 20
server/toc/mock_buddy_list_registry_test.go

@@ -3,6 +3,8 @@
 package toc
 
 import (
+	context "context"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 )
@@ -20,17 +22,17 @@ func (_m *mockBuddyListRegistry) EXPECT() *mockBuddyListRegistry_Expecter {
 	return &mockBuddyListRegistry_Expecter{mock: &_m.Mock}
 }
 
-// RegisterBuddyList provides a mock function with given fields: user
-func (_m *mockBuddyListRegistry) RegisterBuddyList(user state.IdentScreenName) error {
-	ret := _m.Called(user)
+// RegisterBuddyList provides a mock function with given fields: ctx, user
+func (_m *mockBuddyListRegistry) RegisterBuddyList(ctx context.Context, user state.IdentScreenName) error {
+	ret := _m.Called(ctx, user)
 
 	if len(ret) == 0 {
 		panic("no return value specified for RegisterBuddyList")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) error); ok {
-		r0 = rf(user)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) error); ok {
+		r0 = rf(ctx, user)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -44,14 +46,15 @@ type mockBuddyListRegistry_RegisterBuddyList_Call struct {
 }
 
 // RegisterBuddyList is a helper method to define mock.On call
+//   - ctx context.Context
 //   - user state.IdentScreenName
-func (_e *mockBuddyListRegistry_Expecter) RegisterBuddyList(user interface{}) *mockBuddyListRegistry_RegisterBuddyList_Call {
-	return &mockBuddyListRegistry_RegisterBuddyList_Call{Call: _e.mock.On("RegisterBuddyList", user)}
+func (_e *mockBuddyListRegistry_Expecter) RegisterBuddyList(ctx interface{}, user interface{}) *mockBuddyListRegistry_RegisterBuddyList_Call {
+	return &mockBuddyListRegistry_RegisterBuddyList_Call{Call: _e.mock.On("RegisterBuddyList", ctx, user)}
 }
 
-func (_c *mockBuddyListRegistry_RegisterBuddyList_Call) Run(run func(user state.IdentScreenName)) *mockBuddyListRegistry_RegisterBuddyList_Call {
+func (_c *mockBuddyListRegistry_RegisterBuddyList_Call) Run(run func(ctx context.Context, user state.IdentScreenName)) *mockBuddyListRegistry_RegisterBuddyList_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
@@ -61,22 +64,22 @@ func (_c *mockBuddyListRegistry_RegisterBuddyList_Call) Return(_a0 error) *mockB
 	return _c
 }
 
-func (_c *mockBuddyListRegistry_RegisterBuddyList_Call) RunAndReturn(run func(state.IdentScreenName) error) *mockBuddyListRegistry_RegisterBuddyList_Call {
+func (_c *mockBuddyListRegistry_RegisterBuddyList_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) error) *mockBuddyListRegistry_RegisterBuddyList_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// UnregisterBuddyList provides a mock function with given fields: user
-func (_m *mockBuddyListRegistry) UnregisterBuddyList(user state.IdentScreenName) error {
-	ret := _m.Called(user)
+// UnregisterBuddyList provides a mock function with given fields: ctx, user
+func (_m *mockBuddyListRegistry) UnregisterBuddyList(ctx context.Context, user state.IdentScreenName) error {
+	ret := _m.Called(ctx, user)
 
 	if len(ret) == 0 {
 		panic("no return value specified for UnregisterBuddyList")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) error); ok {
-		r0 = rf(user)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) error); ok {
+		r0 = rf(ctx, user)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -90,14 +93,15 @@ type mockBuddyListRegistry_UnregisterBuddyList_Call struct {
 }
 
 // UnregisterBuddyList is a helper method to define mock.On call
+//   - ctx context.Context
 //   - user state.IdentScreenName
-func (_e *mockBuddyListRegistry_Expecter) UnregisterBuddyList(user interface{}) *mockBuddyListRegistry_UnregisterBuddyList_Call {
-	return &mockBuddyListRegistry_UnregisterBuddyList_Call{Call: _e.mock.On("UnregisterBuddyList", user)}
+func (_e *mockBuddyListRegistry_Expecter) UnregisterBuddyList(ctx interface{}, user interface{}) *mockBuddyListRegistry_UnregisterBuddyList_Call {
+	return &mockBuddyListRegistry_UnregisterBuddyList_Call{Call: _e.mock.On("UnregisterBuddyList", ctx, user)}
 }
 
-func (_c *mockBuddyListRegistry_UnregisterBuddyList_Call) Run(run func(user state.IdentScreenName)) *mockBuddyListRegistry_UnregisterBuddyList_Call {
+func (_c *mockBuddyListRegistry_UnregisterBuddyList_Call) Run(run func(ctx context.Context, user state.IdentScreenName)) *mockBuddyListRegistry_UnregisterBuddyList_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
@@ -107,7 +111,7 @@ func (_c *mockBuddyListRegistry_UnregisterBuddyList_Call) Return(_a0 error) *moc
 	return _c
 }
 
-func (_c *mockBuddyListRegistry_UnregisterBuddyList_Call) RunAndReturn(run func(state.IdentScreenName) error) *mockBuddyListRegistry_UnregisterBuddyList_Call {
+func (_c *mockBuddyListRegistry_UnregisterBuddyList_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) error) *mockBuddyListRegistry_UnregisterBuddyList_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 8 - 8
server/toc/mock_buddy_service_test.go

@@ -119,9 +119,9 @@ func (_c *mockBuddyService_BroadcastBuddyDeparted_Call) RunAndReturn(run func(co
 	return _c
 }
 
-// DelBuddies provides a mock function with given fields: _a0, sess, inBody
-func (_m *mockBuddyService) DelBuddies(_a0 context.Context, sess *state.Session, inBody wire.SNAC_0x03_0x05_BuddyDelBuddies) error {
-	ret := _m.Called(_a0, sess, inBody)
+// DelBuddies provides a mock function with given fields: ctx, sess, inBody
+func (_m *mockBuddyService) DelBuddies(ctx context.Context, sess *state.Session, inBody wire.SNAC_0x03_0x05_BuddyDelBuddies) error {
+	ret := _m.Called(ctx, sess, inBody)
 
 	if len(ret) == 0 {
 		panic("no return value specified for DelBuddies")
@@ -129,7 +129,7 @@ func (_m *mockBuddyService) DelBuddies(_a0 context.Context, sess *state.Session,
 
 	var r0 error
 	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, wire.SNAC_0x03_0x05_BuddyDelBuddies) error); ok {
-		r0 = rf(_a0, sess, inBody)
+		r0 = rf(ctx, sess, inBody)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -143,14 +143,14 @@ type mockBuddyService_DelBuddies_Call struct {
 }
 
 // DelBuddies is a helper method to define mock.On call
-//   - _a0 context.Context
+//   - ctx context.Context
 //   - sess *state.Session
 //   - inBody wire.SNAC_0x03_0x05_BuddyDelBuddies
-func (_e *mockBuddyService_Expecter) DelBuddies(_a0 interface{}, sess interface{}, inBody interface{}) *mockBuddyService_DelBuddies_Call {
-	return &mockBuddyService_DelBuddies_Call{Call: _e.mock.On("DelBuddies", _a0, sess, inBody)}
+func (_e *mockBuddyService_Expecter) DelBuddies(ctx interface{}, sess interface{}, inBody interface{}) *mockBuddyService_DelBuddies_Call {
+	return &mockBuddyService_DelBuddies_Call{Call: _e.mock.On("DelBuddies", ctx, sess, inBody)}
 }
 
-func (_c *mockBuddyService_DelBuddies_Call) Run(run func(_a0 context.Context, sess *state.Session, inBody wire.SNAC_0x03_0x05_BuddyDelBuddies)) *mockBuddyService_DelBuddies_Call {
+func (_c *mockBuddyService_DelBuddies_Call) Run(run func(ctx context.Context, sess *state.Session, inBody wire.SNAC_0x03_0x05_BuddyDelBuddies)) *mockBuddyService_DelBuddies_Call {
 	_c.Call.Run(func(args mock.Arguments) {
 		run(args[0].(context.Context), args[1].(*state.Session), args[2].(wire.SNAC_0x03_0x05_BuddyDelBuddies))
 	})

+ 28 - 24
server/toc/mock_toc_config_store_test.go

@@ -3,6 +3,8 @@
 package toc
 
 import (
+	context "context"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 )
@@ -20,17 +22,17 @@ func (_m *mockTOCConfigStore) EXPECT() *mockTOCConfigStore_Expecter {
 	return &mockTOCConfigStore_Expecter{mock: &_m.Mock}
 }
 
-// SetTOCConfig provides a mock function with given fields: user, config
-func (_m *mockTOCConfigStore) SetTOCConfig(user state.IdentScreenName, config string) error {
-	ret := _m.Called(user, config)
+// SetTOCConfig provides a mock function with given fields: ctx, user, config
+func (_m *mockTOCConfigStore) SetTOCConfig(ctx context.Context, user state.IdentScreenName, config string) error {
+	ret := _m.Called(ctx, user, config)
 
 	if len(ret) == 0 {
 		panic("no return value specified for SetTOCConfig")
 	}
 
 	var r0 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName, string) error); ok {
-		r0 = rf(user, config)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName, string) error); ok {
+		r0 = rf(ctx, user, config)
 	} else {
 		r0 = ret.Error(0)
 	}
@@ -44,15 +46,16 @@ type mockTOCConfigStore_SetTOCConfig_Call struct {
 }
 
 // SetTOCConfig is a helper method to define mock.On call
+//   - ctx context.Context
 //   - user state.IdentScreenName
 //   - config string
-func (_e *mockTOCConfigStore_Expecter) SetTOCConfig(user interface{}, config interface{}) *mockTOCConfigStore_SetTOCConfig_Call {
-	return &mockTOCConfigStore_SetTOCConfig_Call{Call: _e.mock.On("SetTOCConfig", user, config)}
+func (_e *mockTOCConfigStore_Expecter) SetTOCConfig(ctx interface{}, user interface{}, config interface{}) *mockTOCConfigStore_SetTOCConfig_Call {
+	return &mockTOCConfigStore_SetTOCConfig_Call{Call: _e.mock.On("SetTOCConfig", ctx, user, config)}
 }
 
-func (_c *mockTOCConfigStore_SetTOCConfig_Call) Run(run func(user state.IdentScreenName, config string)) *mockTOCConfigStore_SetTOCConfig_Call {
+func (_c *mockTOCConfigStore_SetTOCConfig_Call) Run(run func(ctx context.Context, user state.IdentScreenName, config string)) *mockTOCConfigStore_SetTOCConfig_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName), args[1].(string))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName), args[2].(string))
 	})
 	return _c
 }
@@ -62,14 +65,14 @@ func (_c *mockTOCConfigStore_SetTOCConfig_Call) Return(_a0 error) *mockTOCConfig
 	return _c
 }
 
-func (_c *mockTOCConfigStore_SetTOCConfig_Call) RunAndReturn(run func(state.IdentScreenName, string) error) *mockTOCConfigStore_SetTOCConfig_Call {
+func (_c *mockTOCConfigStore_SetTOCConfig_Call) RunAndReturn(run func(context.Context, state.IdentScreenName, string) error) *mockTOCConfigStore_SetTOCConfig_Call {
 	_c.Call.Return(run)
 	return _c
 }
 
-// User provides a mock function with given fields: screenName
-func (_m *mockTOCConfigStore) User(screenName state.IdentScreenName) (*state.User, error) {
-	ret := _m.Called(screenName)
+// User provides a mock function with given fields: ctx, screenName
+func (_m *mockTOCConfigStore) User(ctx context.Context, screenName state.IdentScreenName) (*state.User, error) {
+	ret := _m.Called(ctx, screenName)
 
 	if len(ret) == 0 {
 		panic("no return value specified for User")
@@ -77,19 +80,19 @@ func (_m *mockTOCConfigStore) User(screenName state.IdentScreenName) (*state.Use
 
 	var r0 *state.User
 	var r1 error
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) (*state.User, error)); ok {
-		return rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) (*state.User, error)); ok {
+		return rf(ctx, screenName)
 	}
-	if rf, ok := ret.Get(0).(func(state.IdentScreenName) *state.User); ok {
-		r0 = rf(screenName)
+	if rf, ok := ret.Get(0).(func(context.Context, state.IdentScreenName) *state.User); ok {
+		r0 = rf(ctx, screenName)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*state.User)
 		}
 	}
 
-	if rf, ok := ret.Get(1).(func(state.IdentScreenName) error); ok {
-		r1 = rf(screenName)
+	if rf, ok := ret.Get(1).(func(context.Context, state.IdentScreenName) error); ok {
+		r1 = rf(ctx, screenName)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -103,14 +106,15 @@ type mockTOCConfigStore_User_Call struct {
 }
 
 // User is a helper method to define mock.On call
+//   - ctx context.Context
 //   - screenName state.IdentScreenName
-func (_e *mockTOCConfigStore_Expecter) User(screenName interface{}) *mockTOCConfigStore_User_Call {
-	return &mockTOCConfigStore_User_Call{Call: _e.mock.On("User", screenName)}
+func (_e *mockTOCConfigStore_Expecter) User(ctx interface{}, screenName interface{}) *mockTOCConfigStore_User_Call {
+	return &mockTOCConfigStore_User_Call{Call: _e.mock.On("User", ctx, screenName)}
 }
 
-func (_c *mockTOCConfigStore_User_Call) Run(run func(screenName state.IdentScreenName)) *mockTOCConfigStore_User_Call {
+func (_c *mockTOCConfigStore_User_Call) Run(run func(ctx context.Context, screenName state.IdentScreenName)) *mockTOCConfigStore_User_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(state.IdentScreenName))
+		run(args[0].(context.Context), args[1].(state.IdentScreenName))
 	})
 	return _c
 }
@@ -120,7 +124,7 @@ func (_c *mockTOCConfigStore_User_Call) Return(_a0 *state.User, _a1 error) *mock
 	return _c
 }
 
-func (_c *mockTOCConfigStore_User_Call) RunAndReturn(run func(state.IdentScreenName) (*state.User, error)) *mockTOCConfigStore_User_Call {
+func (_c *mockTOCConfigStore_User_Call) RunAndReturn(run func(context.Context, state.IdentScreenName) (*state.User, error)) *mockTOCConfigStore_User_Call {
 	_c.Call.Return(run)
 	return _c
 }

+ 19 - 9
server/toc/types.go

@@ -12,7 +12,7 @@ import (
 type BuddyService interface {
 	AddBuddies(ctx context.Context, sess *state.Session, inBody wire.SNAC_0x03_0x04_BuddyAddBuddies) error
 	BroadcastBuddyDeparted(ctx context.Context, sess *state.Session) error
-	DelBuddies(_ context.Context, sess *state.Session, inBody wire.SNAC_0x03_0x05_BuddyDelBuddies) error
+	DelBuddies(ctx context.Context, sess *state.Session, inBody wire.SNAC_0x03_0x05_BuddyDelBuddies) error
 	RightsQuery(ctx context.Context, inFrame wire.SNACFrame) wire.SNACMessage
 }
 
@@ -42,11 +42,11 @@ type OServiceService interface {
 }
 
 type AuthService interface {
-	BUCPChallenge(bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID) (wire.SNACMessage, error)
-	BUCPLogin(bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(screenName state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error)
-	FLAPLogin(frame wire.FLAPSignonFrame, newUserFn func(screenName state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error)
+	BUCPChallenge(ctx context.Context, bodyIn wire.SNAC_0x17_0x06_BUCPChallengeRequest, newUUID func() uuid.UUID) (wire.SNACMessage, error)
+	BUCPLogin(ctx context.Context, bodyIn wire.SNAC_0x17_0x02_BUCPLoginRequest, newUserFn func(screenName state.DisplayScreenName) (state.User, error)) (wire.SNACMessage, error)
+	FLAPLogin(ctx context.Context, frame wire.FLAPSignonFrame, newUserFn func(screenName state.DisplayScreenName) (state.User, error)) (wire.TLVRestBlock, error)
 	RegisterBOSSession(ctx context.Context, authCookie []byte) (*state.Session, error)
-	RetrieveBOSSession(authCookie []byte) (*state.Session, error)
+	RetrieveBOSSession(ctx context.Context, authCookie []byte) (*state.Session, error)
 	RegisterChatSession(ctx context.Context, authCookie []byte) (*state.Session, error)
 	Signout(ctx context.Context, sess *state.Session)
 	SignoutChat(ctx context.Context, sess *state.Session)
@@ -75,17 +75,27 @@ type PermitDenyService interface {
 // buddy lists. Once registered, a user becomes visible to other users' buddy
 // lists and vice versa.
 type BuddyListRegistry interface {
-	RegisterBuddyList(user state.IdentScreenName) error
-	UnregisterBuddyList(user state.IdentScreenName) error
+	RegisterBuddyList(ctx context.Context, user state.IdentScreenName) error
+	UnregisterBuddyList(ctx context.Context, user state.IdentScreenName) error
 }
 
 type TOCConfigStore interface {
-	SetTOCConfig(user state.IdentScreenName, config string) error
-	User(screenName state.IdentScreenName) (*state.User, error)
+	// SetTOCConfig sets the user's TOC config. The TOC config is the server-side
+	// buddy list functionality for TOC. This configuration is not available to
+	// OSCAR clients.
+	SetTOCConfig(ctx context.Context, user state.IdentScreenName, config string) error
+	User(ctx context.Context, screenName state.IdentScreenName) (*state.User, error)
 }
 
+// CookieBaker defines methods for issuing and verifying AIM authentication tokens ("cookies").
+// These tokens are used for authenticating client sessions with AIM services.
 type CookieBaker interface {
+	// Crack verifies and decodes a previously issued authentication token.
+	// Returns the original payload if the token is valid.
 	Crack(data []byte) ([]byte, error)
+
+	// Issue creates a new authentication token from the given payload.
+	// The resulting token can later be verified using Crack.
 	Issue(data []byte) ([]byte, error)
 }
 

+ 5 - 4
state/relationship.go

@@ -2,6 +2,7 @@ package state
 
 import (
 	"bytes"
+	"context"
 	"fmt"
 	"strings"
 	"text/template"
@@ -160,8 +161,8 @@ type Relationship struct {
 // This method always returns a usable [Relationship] value. If the user
 // specified by `them` does not exist, the returned [Relationship] will have
 // default boolean values.
-func (f SQLiteUserStore) Relationship(me IdentScreenName, them IdentScreenName) (Relationship, error) {
-	rels, err := f.AllRelationships(me, []IdentScreenName{them})
+func (f SQLiteUserStore) Relationship(ctx context.Context, me IdentScreenName, them IdentScreenName) (Relationship, error) {
+	rels, err := f.AllRelationships(ctx, me, []IdentScreenName{them})
 	if err != nil {
 		return Relationship{}, fmt.Errorf("error getting relationships: %w", err)
 	}
@@ -185,7 +186,7 @@ func (f SQLiteUserStore) Relationship(me IdentScreenName, them IdentScreenName)
 // a call to [SQLiteUserStore.RegisterBuddyList]. The results can be optionally
 // filtered to include only specific users by providing their identifiers in
 // the `filter` parameter.
-func (f SQLiteUserStore) AllRelationships(me IdentScreenName, filter []IdentScreenName) ([]Relationship, error) {
+func (f SQLiteUserStore) AllRelationships(ctx context.Context, me IdentScreenName, filter []IdentScreenName) ([]Relationship, error) {
 	tpl := queryWithoutFiltering
 	args := make([]any, 1, len(filter)+1)
 	args[0] = me.String()
@@ -200,7 +201,7 @@ func (f SQLiteUserStore) AllRelationships(me IdentScreenName, filter []IdentScre
 		}
 	}
 
-	rows, err := f.db.Query(tpl, args...)
+	rows, err := f.db.QueryContext(ctx, tpl, args...)
 	if err != nil {
 		return nil, fmt.Errorf("error querying relationships: %w", err)
 	}

+ 9 - 8
state/relationship_test.go

@@ -1,6 +1,7 @@
 package state
 
 import (
+	"context"
 	"os"
 	"testing"
 
@@ -2999,27 +3000,27 @@ func TestSQLiteUserStore_AllRelationships(t *testing.T) {
 			assert.NoError(t, err)
 
 			for sn, list := range tt.clientSideLists {
-				assert.NoError(t, feedbagStore.SetPDMode(sn, list.privacyMode))
+				assert.NoError(t, feedbagStore.SetPDMode(context.Background(), sn, list.privacyMode))
 				for _, buddy := range list.buddyList {
-					assert.NoError(t, feedbagStore.AddBuddy(sn, buddy))
+					assert.NoError(t, feedbagStore.AddBuddy(context.Background(), sn, buddy))
 				}
 				for _, buddy := range list.permitList {
-					assert.NoError(t, feedbagStore.PermitBuddy(sn, buddy))
+					assert.NoError(t, feedbagStore.PermitBuddy(context.Background(), sn, buddy))
 				}
 				for _, buddy := range list.denyList {
-					assert.NoError(t, feedbagStore.DenyBuddy(sn, buddy))
+					assert.NoError(t, feedbagStore.DenyBuddy(context.Background(), sn, buddy))
 				}
 			}
 
 			for sn, list := range tt.serverSideLists {
-				assert.NoError(t, feedbagStore.UseFeedbag(sn))
+				assert.NoError(t, feedbagStore.UseFeedbag(context.Background(), sn))
 				itemID := uint16(1)
 				items := []wire.FeedbagItem{
 					pdInfoItem(itemID, list.privacyMode),
 				}
 				itemID++
 				for _, buddy := range list.buddyList {
-					assert.NoError(t, feedbagStore.AddBuddy(sn, buddy))
+					assert.NoError(t, feedbagStore.AddBuddy(context.Background(), sn, buddy))
 					items = append(items, newFeedbagItem(wire.FeedbagClassIdBuddy, itemID, buddy.String()))
 					itemID++
 				}
@@ -3031,10 +3032,10 @@ func TestSQLiteUserStore_AllRelationships(t *testing.T) {
 					items = append(items, newFeedbagItem(wire.FeedbagClassIDDeny, itemID, buddy.String()))
 					itemID++
 				}
-				assert.NoError(t, feedbagStore.FeedbagUpsert(sn, items))
+				assert.NoError(t, feedbagStore.FeedbagUpsert(context.Background(), sn, items))
 			}
 
-			have, err := feedbagStore.AllRelationships(tt.me, tt.filter)
+			have, err := feedbagStore.AllRelationships(context.Background(), tt.me, tt.filter)
 			assert.NoError(t, err)
 			assert.ElementsMatch(t, tt.expect, have)
 		})

+ 0 - 6
state/session_manager.go

@@ -71,12 +71,6 @@ func (s *InMemorySessionManager) maybeRelayMessage(ctx context.Context, msg wire
 	}
 }
 
-// AddSession adds a new session to the pool, ensuring only one session exists
-// for a given screen name. If a session with the same screen name is already
-// active, the call blocks until the active session is terminated by
-// [InMemorySessionManager.RemoveSession] or the context is canceled. When
-// concurrent calls are made for the same screen name, only one call succeeds
-// and the others return an error.
 func (s *InMemorySessionManager) AddSession(ctx context.Context, screenName DisplayScreenName) (*Session, error) {
 	s.mapMutex.Lock()
 

Разница между файлами не показана из-за своего большого размера
+ 137 - 196
state/user_store.go


Разница между файлами не показана из-за своего большого размера
+ 137 - 136
state/user_store_test.go


Некоторые файлы не были показаны из-за большого количества измененных файлов