Sfoglia il codice sorgente

Update unit tests for additional admin changes

Josh Knight 2 anni fa
parent
commit
acc373ae84

+ 571 - 13
foodgroup/admin_test.go

@@ -1,6 +1,7 @@
 package foodgroup
 
 import (
+	"net/mail"
 	"testing"
 
 	"github.com/mk6i/retro-aim-server/config"
@@ -21,17 +22,21 @@ func TestAdminService_ConfirmRequest(t *testing.T) {
 		// mockParams is the list of params sent to mocks that satisfy this
 		// method's dependencies
 		mockParams mockParams
+		// userSession is the session of the user
+		userSession *state.Session
 		// expectOutput is the SNAC sent from the server to client
 		expectOutput wire.SNACMessage
 		// expectErr is the expected error returned
 		expectErr error
 	}{
 		{
-			name: "user confirms their account",
+			name:        "unconfirmed account sends confirmation request",
+			userSession: newTestSession("chattingchuck"),
 			inputSNAC: wire.SNACMessage{
 				Frame: wire.SNACFrame{
 					FoodGroup: wire.Admin,
 					SubGroup:  wire.AdminAcctConfirmRequest,
+					RequestID: 1234,
 				},
 				Body: wire.SNAC_0x07_0x06_AdminConfirmRequest{},
 			},
@@ -39,11 +44,124 @@ func TestAdminService_ConfirmRequest(t *testing.T) {
 				Frame: wire.SNACFrame{
 					FoodGroup: wire.Admin,
 					SubGroup:  wire.AdminAcctConfirmReply,
+					RequestID: 1234,
 				},
 				Body: wire.SNAC_0x07_0x07_AdminConfirmReply{
 					Status: wire.AdminAcctConfirmStatusEmailSent,
 				},
 			},
+			mockParams: mockParams{
+				accountManagerParams: accountManagerParams{
+					accountManagerEmailAddressByNameParams: accountManagerEmailAddressByNameParams{
+						{
+
+							screenName: state.NewIdentScreenName("chattingchuck"),
+							emailAddress: &mail.Address{
+								Address: "chuck@aol.com",
+							},
+							err: nil,
+						},
+					},
+					accountManagerConfirmStatusByNameParams: accountManagerConfirmStatusByNameParams{
+						{
+							screenName:    state.NewIdentScreenName("chattingchuck"),
+							confirmStatus: false,
+							err:           nil,
+						},
+					},
+					accountManagerUpdateConfirmStatusParams: accountManagerUpdateConfirmStatusParams{
+						{
+							confirmStatus: true,
+							screenName:    state.NewIdentScreenName("chattingchuck"),
+							err:           nil,
+						},
+					},
+				},
+				buddyBroadcasterParams: buddyBroadcasterParams{
+					broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
+						{
+							screenName: state.NewIdentScreenName("Chatting Chuck"),
+						},
+					},
+				},
+			},
+		},
+		{
+			name:        "already confirmed account sends confirmation request",
+			userSession: newTestSession("chattingchuck"),
+			inputSNAC: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminAcctConfirmRequest,
+					RequestID: 1234,
+				},
+				Body: wire.SNAC_0x07_0x06_AdminConfirmRequest{},
+			},
+			expectOutput: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminAcctConfirmReply,
+					RequestID: 1234,
+				},
+				Body: wire.SNAC_0x07_0x07_AdminConfirmReply{
+					Status: wire.AdminAcctConfirmStatusAlreadyConfirmed,
+				},
+			},
+			mockParams: mockParams{
+				accountManagerParams: accountManagerParams{
+					accountManagerEmailAddressByNameParams: accountManagerEmailAddressByNameParams{
+						{
+
+							screenName: state.NewIdentScreenName("chattingchuck"),
+							emailAddress: &mail.Address{
+								Address: "chuck@aol.com",
+							},
+							err: nil,
+						},
+					},
+					accountManagerConfirmStatusByNameParams: accountManagerConfirmStatusByNameParams{
+						{
+							screenName:    state.NewIdentScreenName("chattingchuck"),
+							confirmStatus: true,
+							err:           nil,
+						},
+					},
+				},
+			},
+		},
+		{
+			name:        "acccount with no email address sends confirmation request",
+			userSession: newTestSession("chattingchuck"),
+			inputSNAC: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminAcctConfirmRequest,
+					RequestID: 1234,
+				},
+				Body: wire.SNAC_0x07_0x06_AdminConfirmRequest{},
+			},
+			expectOutput: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminAcctConfirmReply,
+					RequestID: 1234,
+				},
+				Body: wire.SNAC_0x07_0x07_AdminConfirmReply{
+					Status: wire.AdminAcctConfirmStatusServerError,
+				},
+			},
+			mockParams: mockParams{
+				accountManagerParams: accountManagerParams{
+					accountManagerEmailAddressByNameParams: accountManagerEmailAddressByNameParams{
+						{
+
+							screenName:   state.NewIdentScreenName("chattingchuck"),
+							emailAddress: nil,
+							err:          state.ErrNoEmailAddress,
+						},
+					},
+				},
+			},
 		},
 	}
 
@@ -52,12 +170,33 @@ func TestAdminService_ConfirmRequest(t *testing.T) {
 			sessionManager := newMockSessionManager(t)
 			accountManager := newMockAccountManager(t)
 			buddyBroadcaster := newMockbuddyBroadcaster(t)
+
+			for _, params := range tc.mockParams.accountManagerParams.accountManagerEmailAddressByNameParams {
+				accountManager.EXPECT().
+					EmailAddressByName(params.screenName).
+					Return(params.emailAddress, params.err)
+			}
+			for _, params := range tc.mockParams.accountManagerParams.accountManagerConfirmStatusByNameParams {
+				accountManager.EXPECT().
+					ConfirmStatusByName(params.screenName).
+					Return(params.confirmStatus, params.err)
+			}
+			for _, params := range tc.mockParams.accountManagerParams.accountManagerUpdateConfirmStatusParams {
+				accountManager.EXPECT().
+					UpdateConfirmStatus(params.confirmStatus, params.screenName).
+					Return(params.err)
+			}
+			for _, params := range tc.mockParams.broadcastBuddyArrivedParams {
+				buddyBroadcaster.EXPECT().
+					BroadcastBuddyArrived(mock.Anything, tc.userSession).
+					Return(params.err)
+			}
 			svc := AdminService{
 				sessionManager:         sessionManager,
 				accountManager:         accountManager,
 				buddyUpdateBroadcaster: buddyBroadcaster,
 			}
-			outputSNAC, err := svc.ConfirmRequest(nil, tc.inputSNAC.Frame)
+			outputSNAC, err := svc.ConfirmRequest(nil, tc.userSession, tc.inputSNAC.Frame)
 			assert.ErrorIs(t, err, tc.expectErr)
 			if tc.expectErr != nil {
 				return
@@ -111,7 +250,18 @@ func TestAdminService_InfoQuery(t *testing.T) {
 					Permissions: wire.AdminInfoPermissionsReadWrite,
 					TLVBlock: wire.TLVBlock{
 						TLVList: wire.TLVList{
-							wire.NewTLV(wire.AdminTLVRegistrationStatus, wire.AdminInfoRegStatusFullDisclosure),
+							wire.NewTLV(wire.AdminTLVRegistrationStatus, wire.AdminInfoRegStatusLimitDisclosure),
+						},
+					},
+				},
+			},
+			mockParams: mockParams{
+				accountManagerParams: accountManagerParams{
+					accountManagerRegStatusByNameParams: accountManagerRegStatusByNameParams{
+						{
+							screenName: state.NewIdentScreenName("chattingchuck"),
+							regStatus:  wire.AdminInfoRegStatusLimitDisclosure,
+							err:        nil,
 						},
 					},
 				},
@@ -143,7 +293,63 @@ func TestAdminService_InfoQuery(t *testing.T) {
 					Permissions: wire.AdminInfoPermissionsReadWrite,
 					TLVBlock: wire.TLVBlock{
 						TLVList: wire.TLVList{
-							wire.NewTLV(wire.AdminTLVEmailAddress, "chattingchuck@aol.com"), // todo: get from session
+							wire.NewTLV(wire.AdminTLVEmailAddress, "chattingchuck@aol.com"),
+						},
+					},
+				},
+			},
+			mockParams: mockParams{
+				accountManagerParams: accountManagerParams{
+					accountManagerEmailAddressByNameParams: accountManagerEmailAddressByNameParams{
+						{
+							screenName: state.NewIdentScreenName("chattingchuck"),
+							emailAddress: &mail.Address{
+								Address: "chattingchuck@aol.com",
+							},
+							err: nil,
+						},
+					},
+				},
+			},
+		},
+		{
+			name:        "user requests account email address but not set",
+			userSession: newTestSession("chattingchuck"),
+			inputSNAC: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminInfoQuery,
+					RequestID: 1337,
+				},
+				Body: wire.SNAC_0x07_0x02_AdminInfoQuery{
+					TLVRestBlock: wire.TLVRestBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLV(wire.AdminTLVEmailAddress, uint16(0x00))},
+					},
+				},
+			},
+			expectOutput: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminInfoReply,
+					RequestID: 1337,
+				},
+				Body: wire.SNAC_0x07_0x03_AdminInfoReply{
+					Permissions: wire.AdminInfoPermissionsReadWrite,
+					TLVBlock: wire.TLVBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLV(wire.AdminTLVEmailAddress, ""),
+						},
+					},
+				},
+			},
+			mockParams: mockParams{
+				accountManagerParams: accountManagerParams{
+					accountManagerEmailAddressByNameParams: accountManagerEmailAddressByNameParams{
+						{
+							screenName:   state.NewIdentScreenName("chattingchuck"),
+							emailAddress: nil,
+							err:          state.ErrNoEmailAddress,
 						},
 					},
 				},
@@ -215,6 +421,19 @@ func TestAdminService_InfoQuery(t *testing.T) {
 			sessionManager := newMockSessionManager(t)
 			accountManager := newMockAccountManager(t)
 			buddyBroadcaster := newMockbuddyBroadcaster(t)
+
+			for _, params := range tc.mockParams.accountManagerParams.accountManagerRegStatusByNameParams {
+				accountManager.EXPECT().
+					RegStatusByName(params.screenName).
+					Return(params.regStatus, params.err)
+			}
+
+			for _, params := range tc.mockParams.accountManagerParams.accountManagerEmailAddressByNameParams {
+				accountManager.EXPECT().
+					EmailAddressByName(params.screenName).
+					Return(params.emailAddress, params.err)
+			}
+
 			svc := AdminService{
 				sessionManager:         sessionManager,
 				accountManager:         accountManager,
@@ -230,7 +449,7 @@ func TestAdminService_InfoQuery(t *testing.T) {
 	}
 }
 
-func TestAdminService_InfoChangeRequest(t *testing.T) {
+func TestAdminService_InfoChangeRequest_ScreenName(t *testing.T) {
 	cases := []struct {
 		// name is the unit test name
 		name string
@@ -332,16 +551,22 @@ func TestAdminService_InfoChangeRequest(t *testing.T) {
 			expectOutput: wire.SNACMessage{
 				Frame: wire.SNACFrame{
 					FoodGroup: wire.Admin,
-					SubGroup:  wire.AdminErr,
+					SubGroup:  wire.AdminInfoChangeReply,
 					RequestID: 1337,
 				},
-				Body: wire.SNACError{
-					Code: wire.AdminInfoErrorInvalidNickNameLength,
+				Body: wire.SNAC_0x07_0x05_AdminChangeReply{
+					Permissions: wire.AdminInfoPermissionsReadWrite,
+					TLVBlock: wire.TLVBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLV(wire.AdminTLVErrorCode, wire.AdminInfoErrorInvalidNickNameLength),
+							wire.NewTLV(wire.AdminTLVUrl, ""),
+						},
+					},
 				},
 			},
 		},
 		{
-			name:        "proposed screen name does not match session's screen name (malicous client)",
+			name:        "proposed screen name does not match session screen name",
 			userSession: newTestSession("chattingchuck"),
 			inputSNAC: wire.SNACMessage{
 				Frame: wire.SNACFrame{
@@ -359,11 +584,50 @@ func TestAdminService_InfoChangeRequest(t *testing.T) {
 			expectOutput: wire.SNACMessage{
 				Frame: wire.SNACFrame{
 					FoodGroup: wire.Admin,
-					SubGroup:  wire.AdminErr,
+					SubGroup:  wire.AdminInfoChangeReply,
 					RequestID: 1337,
 				},
-				Body: wire.SNACError{
-					Code: wire.AdminInfoErrorInvalidNickName,
+				Body: wire.SNAC_0x07_0x05_AdminChangeReply{
+					Permissions: wire.AdminInfoPermissionsReadWrite,
+					TLVBlock: wire.TLVBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLV(wire.AdminTLVErrorCode, wire.AdminInfoErrorValidateNickName),
+							wire.NewTLV(wire.AdminTLVUrl, ""),
+						},
+					},
+				},
+			},
+		},
+		{
+			name:        "proposed screen name ends in a space",
+			userSession: newTestSession("chattingchuck"),
+			inputSNAC: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminInfoChangeRequest,
+					RequestID: 1337,
+				},
+				Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
+					TLVRestBlock: wire.TLVRestBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLV(wire.AdminTLVScreenNameFormatted, "ChattingChuck ")},
+					},
+				},
+			},
+			expectOutput: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminInfoChangeReply,
+					RequestID: 1337,
+				},
+				Body: wire.SNAC_0x07_0x05_AdminChangeReply{
+					Permissions: wire.AdminInfoPermissionsReadWrite,
+					TLVBlock: wire.TLVBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLV(wire.AdminTLVErrorCode, wire.AdminInfoErrorInvalidNickName),
+							wire.NewTLV(wire.AdminTLVUrl, ""),
+						},
+					},
 				},
 			},
 		},
@@ -388,7 +652,7 @@ func TestAdminService_InfoChangeRequest(t *testing.T) {
 					BroadcastBuddyArrived(mock.Anything, mock.MatchedBy(func(s *state.Session) bool {
 						return s.IdentScreenName() == p.screenName
 					})).
-					Return(nil)
+					Return(p.err)
 			}
 
 			for _, params := range tc.mockParams.messageRelayerParams.relayToScreenNameParams {
@@ -412,3 +676,297 @@ func TestAdminService_InfoChangeRequest(t *testing.T) {
 		})
 	}
 }
+
+func TestAdminService_InfoChangeRequest_EmailAddress(t *testing.T) {
+	// One case needs a 320 character long email address
+	longEmailAddress := "longemailaddress@"
+	for i := 0; i < 50; i++ {
+		longEmailAddress += "domain"
+	}
+	longEmailAddress += ".com"
+	cases := []struct {
+		// name is the unit test name
+		name string
+		// cfg is the app configuration
+		cfg config.Config
+		// inputSNAC is the SNAC sent from the client to the server
+		inputSNAC wire.SNACMessage
+		// mockParams is the list of params sent to mocks that satisfy this
+		// method's dependencies
+		mockParams mockParams
+		// userSession is the session of the user
+		userSession *state.Session
+		// expectOutput is the SNAC sent from the server to client
+		expectOutput wire.SNACMessage
+		// expectErr is the expected error returned
+		expectErr error
+	}{
+		{
+			name:        "user changes email address successfully",
+			userSession: newTestSession("chattingchuck"),
+			mockParams: mockParams{
+				accountManagerParams: accountManagerParams{
+					accountManagerUpdateEmailAddressParams: accountManagerUpdateEmailAddressParams{
+						{
+							screenName: state.NewIdentScreenName("chattingchuck"),
+							emailAddress: &mail.Address{
+								Address: "chattingchuck@aol.com",
+							},
+						},
+					},
+				},
+			},
+			inputSNAC: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminInfoChangeRequest,
+					RequestID: 1337,
+				},
+				Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
+					TLVRestBlock: wire.TLVRestBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLV(wire.AdminTLVEmailAddress, "chattingchuck@aol.com"),
+						},
+					},
+				},
+			},
+			expectOutput: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminInfoChangeReply,
+					RequestID: 1337,
+				},
+				Body: wire.SNAC_0x07_0x05_AdminChangeReply{
+					Permissions: wire.AdminInfoPermissionsReadWrite,
+					TLVBlock: wire.TLVBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLV(wire.AdminTLVEmailAddress, "chattingchuck@aol.com"),
+						},
+					},
+				},
+			},
+		},
+		{
+			name:        "proposed email address invalid rfc 5322 format",
+			userSession: newTestSession("chattingchuck"),
+			inputSNAC: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminInfoChangeRequest,
+					RequestID: 1337,
+				},
+				Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
+					TLVRestBlock: wire.TLVRestBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLV(wire.AdminTLVEmailAddress, "chattingchuck@@@@@@@aol.com"),
+						},
+					},
+				},
+			},
+			expectOutput: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminInfoChangeReply,
+					RequestID: 1337,
+				},
+				Body: wire.SNAC_0x07_0x05_AdminChangeReply{
+					Permissions: wire.AdminInfoPermissionsReadWrite,
+					TLVBlock: wire.TLVBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLV(wire.AdminTLVErrorCode, wire.AdminInfoErrorInvalidEmail),
+							wire.NewTLV(wire.AdminTLVUrl, ""),
+						},
+					},
+				},
+			},
+		},
+		{
+			name:        "proposed email address too long",
+			userSession: newTestSession("chattingchuck"),
+			inputSNAC: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminInfoChangeRequest,
+					RequestID: 1337,
+				},
+				Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
+					TLVRestBlock: wire.TLVRestBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLV(wire.AdminTLVEmailAddress, longEmailAddress),
+						},
+					},
+				},
+			},
+			expectOutput: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminInfoChangeReply,
+					RequestID: 1337,
+				},
+				Body: wire.SNAC_0x07_0x05_AdminChangeReply{
+					Permissions: wire.AdminInfoPermissionsReadWrite,
+					TLVBlock: wire.TLVBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLV(wire.AdminTLVErrorCode, wire.AdminInfoErrorInvalidEmailLength),
+							wire.NewTLV(wire.AdminTLVUrl, ""),
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for _, tc := range cases {
+		t.Run(tc.name, func(t *testing.T) {
+			sessionManager := newMockSessionManager(t)
+			accountManager := newMockAccountManager(t)
+			buddyBroadcaster := newMockbuddyBroadcaster(t)
+			messageRelayer := newMockMessageRelayer(t)
+
+			for _, params := range tc.mockParams.accountManagerParams.accountManagerUpdateEmailAddressParams {
+				accountManager.EXPECT().
+					UpdateEmailAddress(params.emailAddress, params.screenName).
+					Return(params.err)
+			}
+
+			svc := AdminService{
+				sessionManager:         sessionManager,
+				accountManager:         accountManager,
+				buddyUpdateBroadcaster: buddyBroadcaster,
+				messageRelayer:         messageRelayer,
+			}
+			outputSNAC, err := svc.InfoChangeRequest(nil, tc.userSession, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x04_AdminInfoChangeRequest))
+			assert.ErrorIs(t, err, tc.expectErr)
+			if tc.expectErr != nil {
+				return
+			}
+			assert.Equal(t, tc.expectOutput, outputSNAC)
+		})
+	}
+}
+
+func TestAdminService_InfoChangeRequest_RegStatus(t *testing.T) {
+	cases := []struct {
+		// name is the unit test name
+		name string
+		// cfg is the app configuration
+		cfg config.Config
+		// inputSNAC is the SNAC sent from the client to the server
+		inputSNAC wire.SNACMessage
+		// mockParams is the list of params sent to mocks that satisfy this
+		// method's dependencies
+		mockParams mockParams
+		// userSession is the session of the user
+		userSession *state.Session
+		// expectOutput is the SNAC sent from the server to client
+		expectOutput wire.SNACMessage
+		// expectErr is the expected error returned
+		expectErr error
+	}{
+		{
+			name:        "user changes reg preference successfully",
+			userSession: newTestSession("chattingchuck"),
+			mockParams: mockParams{
+				accountManagerParams: accountManagerParams{
+					accountManagerUpdateRegStatusParams: accountManagerUpdateRegStatusParams{
+						{
+							screenName: state.NewIdentScreenName("chattingchuck"),
+							regStatus:  wire.AdminInfoRegStatusNoDisclosure,
+						},
+					},
+				},
+			},
+			inputSNAC: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminInfoChangeRequest,
+					RequestID: 1337,
+				},
+				Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
+					TLVRestBlock: wire.TLVRestBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLV(wire.AdminTLVRegistrationStatus, wire.AdminInfoRegStatusNoDisclosure),
+						},
+					},
+				},
+			},
+			expectOutput: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminInfoChangeReply,
+					RequestID: 1337,
+				},
+				Body: wire.SNAC_0x07_0x05_AdminChangeReply{
+					Permissions: wire.AdminInfoPermissionsReadWrite,
+					TLVBlock: wire.TLVBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLV(wire.AdminTLVRegistrationStatus, wire.AdminInfoRegStatusNoDisclosure),
+						},
+					},
+				},
+			},
+		},
+		{
+			name:        "proposed reg preference invalid",
+			userSession: newTestSession("chattingchuck"),
+			inputSNAC: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminInfoChangeRequest,
+					RequestID: 1337,
+				},
+				Body: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
+					TLVRestBlock: wire.TLVRestBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLV(wire.AdminTLVRegistrationStatus, uint16(0x1337)),
+						},
+					},
+				},
+			},
+			expectOutput: wire.SNACMessage{
+				Frame: wire.SNACFrame{
+					FoodGroup: wire.Admin,
+					SubGroup:  wire.AdminInfoChangeReply,
+					RequestID: 1337,
+				},
+				Body: wire.SNAC_0x07_0x05_AdminChangeReply{
+					Permissions: wire.AdminInfoPermissionsReadWrite,
+					TLVBlock: wire.TLVBlock{
+						TLVList: wire.TLVList{
+							wire.NewTLV(wire.AdminTLVErrorCode, wire.AdminInfoErrorInvalidRegistrationPreference),
+							wire.NewTLV(wire.AdminTLVUrl, ""),
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for _, tc := range cases {
+		t.Run(tc.name, func(t *testing.T) {
+			sessionManager := newMockSessionManager(t)
+			accountManager := newMockAccountManager(t)
+			buddyBroadcaster := newMockbuddyBroadcaster(t)
+			messageRelayer := newMockMessageRelayer(t)
+
+			for _, params := range tc.mockParams.accountManagerParams.accountManagerUpdateRegStatusParams {
+				accountManager.EXPECT().
+					UpdateRegStatus(params.regStatus, params.screenName).
+					Return(params.err)
+			}
+
+			svc := AdminService{
+				sessionManager:         sessionManager,
+				accountManager:         accountManager,
+				buddyUpdateBroadcaster: buddyBroadcaster,
+				messageRelayer:         messageRelayer,
+			}
+			outputSNAC, err := svc.InfoChangeRequest(nil, tc.userSession, tc.inputSNAC.Frame, tc.inputSNAC.Body.(wire.SNAC_0x07_0x04_AdminInfoChangeRequest))
+			assert.ErrorIs(t, err, tc.expectErr)
+			if tc.expectErr != nil {
+				return
+			}
+			assert.Equal(t, tc.expectOutput, outputSNAC)
+		})
+	}
+}

+ 11 - 6
foodgroup/auth_test.go

@@ -957,7 +957,7 @@ func TestAuthService_RegisterChatSession_HappyPath(t *testing.T) {
 		Crack(authCookie).
 		Return(chatCookieBuf.Bytes(), nil)
 
-	svc := NewAuthService(config.Config{}, nil, chatSessionRegistry, nil, nil, cookieBaker, nil, nil, nil)
+	svc := NewAuthService(config.Config{}, nil, chatSessionRegistry, nil, nil, cookieBaker, nil, nil, nil, nil)
 
 	have, err := svc.RegisterChatSession(authCookie)
 	assert.NoError(t, err)
@@ -984,7 +984,12 @@ func TestAuthService_RegisterBOSSession_HappyPath(t *testing.T) {
 		User(sess.IdentScreenName()).
 		Return(&state.User{DisplayScreenName: sess.DisplayScreenName()}, nil)
 
-	svc := NewAuthService(config.Config{}, sessionManager, nil, userManager, nil, cookieBaker, nil, nil, nil)
+	accountManager := newMockAccountManager(t)
+	accountManager.EXPECT().
+		ConfirmStatusByName(sess.IdentScreenName()).
+		Return(true, nil)
+
+	svc := NewAuthService(config.Config{}, sessionManager, nil, userManager, nil, cookieBaker, nil, nil, nil, accountManager)
 
 	have, err := svc.RegisterBOSSession(authCookie)
 	assert.NoError(t, err)
@@ -1011,7 +1016,7 @@ func TestAuthService_RetrieveBOSSession_HappyPath(t *testing.T) {
 		User(sess.IdentScreenName()).
 		Return(&state.User{IdentScreenName: sess.IdentScreenName()}, nil)
 
-	svc := NewAuthService(config.Config{}, sessionManager, nil, userManager, nil, cookieBaker, nil, nil, nil)
+	svc := NewAuthService(config.Config{}, sessionManager, nil, userManager, nil, cookieBaker, nil, nil, nil, nil)
 
 	have, err := svc.RetrieveBOSSession(authCookie)
 	assert.NoError(t, err)
@@ -1038,7 +1043,7 @@ func TestAuthService_RetrieveBOSSession_SessionNotFound(t *testing.T) {
 		User(sess.IdentScreenName()).
 		Return(&state.User{IdentScreenName: sess.IdentScreenName()}, nil)
 
-	svc := NewAuthService(config.Config{}, sessionManager, nil, userManager, nil, cookieBaker, nil, nil, nil)
+	svc := NewAuthService(config.Config{}, sessionManager, nil, userManager, nil, cookieBaker, nil, nil, nil, nil)
 
 	have, err := svc.RetrieveBOSSession(authCookie)
 	assert.NoError(t, err)
@@ -1149,7 +1154,7 @@ func TestAuthService_SignoutChat(t *testing.T) {
 					RemoveSession(matchSession(params.screenName))
 			}
 
-			svc := NewAuthService(config.Config{}, nil, sessionManager, nil, nil, nil, nil, nil, chatMessageRelayer)
+			svc := NewAuthService(config.Config{}, nil, sessionManager, nil, nil, nil, nil, nil, chatMessageRelayer, nil)
 			svc.SignoutChat(nil, tt.userSession)
 		})
 	}
@@ -1214,7 +1219,7 @@ func TestAuthService_Signout(t *testing.T) {
 					})).
 					Return(nil)
 			}
-			svc := NewAuthService(config.Config{}, sessionManager, nil, nil, legacyBuddyListManager, nil, nil, nil, nil)
+			svc := NewAuthService(config.Config{}, sessionManager, nil, nil, legacyBuddyListManager, nil, nil, nil, nil, nil)
 			svc.buddyUpdateBroadcaster = buddyUpdateBroadcaster
 
 			err := svc.Signout(nil, tt.userSession)

+ 313 - 0
foodgroup/mock_account_manager_test.go

@@ -3,6 +3,8 @@
 package foodgroup
 
 import (
+	mail "net/mail"
+
 	state "github.com/mk6i/retro-aim-server/state"
 	mock "github.com/stretchr/testify/mock"
 )
@@ -20,6 +22,223 @@ func (_m *mockAccountManager) EXPECT() *mockAccountManager_Expecter {
 	return &mockAccountManager_Expecter{mock: &_m.Mock}
 }
 
+// ConfirmStatusByName provides a mock function with given fields: screnName
+func (_m *mockAccountManager) 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
+}
+
+// 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
+//   - screnName state.IdentScreenName
+func (_e *mockAccountManager_Expecter) ConfirmStatusByName(screnName interface{}) *mockAccountManager_ConfirmStatusByName_Call {
+	return &mockAccountManager_ConfirmStatusByName_Call{Call: _e.mock.On("ConfirmStatusByName", screnName)}
+}
+
+func (_c *mockAccountManager_ConfirmStatusByName_Call) Run(run func(screnName 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
+}
+
+// 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)
+
+	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)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// mockAccountManager_UpdateConfirmStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateConfirmStatus'
+type mockAccountManager_UpdateConfirmStatus_Call struct {
+	*mock.Call
+}
+
+// UpdateConfirmStatus is a helper method to define mock.On call
+//   - confirmStatus bool
+//   - 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)}
+}
+
+func (_c *mockAccountManager_UpdateConfirmStatus_Call) Run(run func(confirmStatus bool, screenName state.IdentScreenName)) *mockAccountManager_UpdateConfirmStatus_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(bool), args[1].(state.IdentScreenName))
+	})
+	return _c
+}
+
+func (_c *mockAccountManager_UpdateConfirmStatus_Call) Return(_a0 error) *mockAccountManager_UpdateConfirmStatus_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *mockAccountManager_UpdateConfirmStatus_Call) RunAndReturn(run func(bool, state.IdentScreenName) 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)
@@ -66,6 +285,100 @@ func (_c *mockAccountManager_UpdateDisplayScreenName_Call) RunAndReturn(run func
 	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)
+
+	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)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// mockAccountManager_UpdateEmailAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateEmailAddress'
+type mockAccountManager_UpdateEmailAddress_Call struct {
+	*mock.Call
+}
+
+// UpdateEmailAddress is a helper method to define mock.On call
+//   - emailAddress *mail.Address
+//   - 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)}
+}
+
+func (_c *mockAccountManager_UpdateEmailAddress_Call) Run(run func(emailAddress *mail.Address, screenName state.IdentScreenName)) *mockAccountManager_UpdateEmailAddress_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(*mail.Address), args[1].(state.IdentScreenName))
+	})
+	return _c
+}
+
+func (_c *mockAccountManager_UpdateEmailAddress_Call) Return(_a0 error) *mockAccountManager_UpdateEmailAddress_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *mockAccountManager_UpdateEmailAddress_Call) RunAndReturn(run func(*mail.Address, state.IdentScreenName) 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)
+
+	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)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// mockAccountManager_UpdateRegStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateRegStatus'
+type mockAccountManager_UpdateRegStatus_Call struct {
+	*mock.Call
+}
+
+// UpdateRegStatus is a helper method to define mock.On call
+//   - regStatus uint16
+//   - 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)}
+}
+
+func (_c *mockAccountManager_UpdateRegStatus_Call) Run(run func(regStatus uint16, screenName state.IdentScreenName)) *mockAccountManager_UpdateRegStatus_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(uint16), args[1].(state.IdentScreenName))
+	})
+	return _c
+}
+
+func (_c *mockAccountManager_UpdateRegStatus_Call) Return(_a0 error) *mockAccountManager_UpdateRegStatus_Call {
+	_c.Call.Return(_a0)
+	return _c
+}
+
+func (_c *mockAccountManager_UpdateRegStatus_Call) RunAndReturn(run func(uint16, state.IdentScreenName) error) *mockAccountManager_UpdateRegStatus_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 {

+ 55 - 0
foodgroup/test_helpers.go

@@ -1,6 +1,7 @@
 package foodgroup
 
 import (
+	"net/mail"
 	"time"
 
 	"github.com/stretchr/testify/mock"
@@ -302,6 +303,12 @@ type cookieIssuerParams []struct {
 // accountManager methods
 type accountManagerParams struct {
 	accountManagerUpdateDisplayScreenNameParams
+	accountManagerUpdateEmailAddressParams
+	accountManagerEmailAddressByNameParams
+	accountManagerUpdateRegStatusParams
+	accountManagerRegStatusByNameParams
+	accountManagerUpdateConfirmStatusParams
+	accountManagerConfirmStatusByNameParams
 }
 
 // accountManagerUpdateDisplayScreenNameParams is the list of parameters passed at the mock
@@ -311,6 +318,54 @@ type accountManagerUpdateDisplayScreenNameParams []struct {
 	err               error
 }
 
+// accountManagerUpdateEmailAddressParams is the list of parameters passed at the mock
+// accountManager.UpdateEmailAddress call site
+type accountManagerUpdateEmailAddressParams []struct {
+	emailAddress *mail.Address
+	screenName   state.IdentScreenName
+	err          error
+}
+
+// accountManagerEmailAddressByNameParams is the list of parameters passed at the mock
+// accountManager.EmailAddressByName call site
+type accountManagerEmailAddressByNameParams []struct {
+	screenName   state.IdentScreenName
+	emailAddress *mail.Address
+	err          error
+}
+
+// accountManagerUpdateRegStatusParams is the list of parameters passed at the mock
+// accountManager.UpdateRegStatus call site
+type accountManagerUpdateRegStatusParams []struct {
+	regStatus  uint16
+	screenName state.IdentScreenName
+	err        error
+}
+
+// accountManagerRegStatusByNameParams is the list of parameters passed at the mock
+// accountManager.RegStatusByName call site
+type accountManagerRegStatusByNameParams []struct {
+	screenName state.IdentScreenName
+	regStatus  uint16
+	err        error
+}
+
+// accountManagerUpdateConfirmStatusParams is the list of parameters passed at the mock
+// accountManager.UpdateConfirmStatus call site
+type accountManagerUpdateConfirmStatusParams []struct {
+	confirmStatus bool
+	screenName    state.IdentScreenName
+	err           error
+}
+
+// accountManagerConfirmStatusByNameParams is the list of parameters passed at the mock
+// accountManager.ConfirmStatusByName call site
+type accountManagerConfirmStatusByNameParams []struct {
+	screenName    state.IdentScreenName
+	confirmStatus bool
+	err           error
+}
+
 // buddyBroadcasterParams is a helper struct that contains mock parameters for
 // buddyBroadcaster methods
 type buddyBroadcasterParams struct {

+ 2 - 2
server/oscar/handler/admin_test.go

@@ -31,7 +31,7 @@ func TestAdminHandler_ConfirmRequest(t *testing.T) {
 
 	svc := newMockAdminService(t)
 	svc.EXPECT().
-		ConfirmRequest(mock.Anything, input.Frame).
+		ConfirmRequest(nil, mock.Anything, input.Frame).
 		Return(output, nil)
 
 	h := NewAdminHandler(slog.Default(), svc)
@@ -77,7 +77,7 @@ func TestAdminHandler_InfoQuery_RegistrationStatus(t *testing.T) {
 
 	svc := newMockAdminService(t)
 	svc.EXPECT().
-		ConfirmRequest(mock.Anything, input.Frame).
+		ConfirmRequest(mock.Anything, mock.Anything, input.Frame).
 		Return(output, nil)
 
 	h := NewAdminHandler(slog.Default(), svc)

+ 16 - 15
server/oscar/handler/mock_admin_test.go

@@ -24,9 +24,9 @@ func (_m *mockAdminService) EXPECT() *mockAdminService_Expecter {
 	return &mockAdminService_Expecter{mock: &_m.Mock}
 }
 
-// ConfirmRequest provides a mock function with given fields: _a0, frame
-func (_m *mockAdminService) ConfirmRequest(_a0 context.Context, frame wire.SNACFrame) (wire.SNACMessage, error) {
-	ret := _m.Called(_a0, frame)
+// ConfirmRequest provides a mock function with given fields: ctx, sess, frame
+func (_m *mockAdminService) ConfirmRequest(ctx context.Context, sess *state.Session, frame wire.SNACFrame) (wire.SNACMessage, error) {
+	ret := _m.Called(ctx, sess, frame)
 
 	if len(ret) == 0 {
 		panic("no return value specified for ConfirmRequest")
@@ -34,17 +34,17 @@ func (_m *mockAdminService) ConfirmRequest(_a0 context.Context, frame wire.SNACF
 
 	var r0 wire.SNACMessage
 	var r1 error
-	if rf, ok := ret.Get(0).(func(context.Context, wire.SNACFrame) (wire.SNACMessage, error)); ok {
-		return rf(_a0, frame)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, wire.SNACFrame) (wire.SNACMessage, error)); ok {
+		return rf(ctx, sess, frame)
 	}
-	if rf, ok := ret.Get(0).(func(context.Context, wire.SNACFrame) wire.SNACMessage); ok {
-		r0 = rf(_a0, frame)
+	if rf, ok := ret.Get(0).(func(context.Context, *state.Session, wire.SNACFrame) wire.SNACMessage); ok {
+		r0 = rf(ctx, sess, frame)
 	} else {
 		r0 = ret.Get(0).(wire.SNACMessage)
 	}
 
-	if rf, ok := ret.Get(1).(func(context.Context, wire.SNACFrame) error); ok {
-		r1 = rf(_a0, frame)
+	if rf, ok := ret.Get(1).(func(context.Context, *state.Session, wire.SNACFrame) error); ok {
+		r1 = rf(ctx, sess, frame)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -58,15 +58,16 @@ type mockAdminService_ConfirmRequest_Call struct {
 }
 
 // ConfirmRequest is a helper method to define mock.On call
-//   - _a0 context.Context
+//   - ctx context.Context
+//   - sess *state.Session
 //   - frame wire.SNACFrame
-func (_e *mockAdminService_Expecter) ConfirmRequest(_a0 interface{}, frame interface{}) *mockAdminService_ConfirmRequest_Call {
-	return &mockAdminService_ConfirmRequest_Call{Call: _e.mock.On("ConfirmRequest", _a0, frame)}
+func (_e *mockAdminService_Expecter) ConfirmRequest(ctx interface{}, sess interface{}, frame interface{}) *mockAdminService_ConfirmRequest_Call {
+	return &mockAdminService_ConfirmRequest_Call{Call: _e.mock.On("ConfirmRequest", ctx, sess, frame)}
 }
 
-func (_c *mockAdminService_ConfirmRequest_Call) Run(run func(_a0 context.Context, frame wire.SNACFrame)) *mockAdminService_ConfirmRequest_Call {
+func (_c *mockAdminService_ConfirmRequest_Call) Run(run func(ctx context.Context, sess *state.Session, frame wire.SNACFrame)) *mockAdminService_ConfirmRequest_Call {
 	_c.Call.Run(func(args mock.Arguments) {
-		run(args[0].(context.Context), args[1].(wire.SNACFrame))
+		run(args[0].(context.Context), args[1].(*state.Session), args[2].(wire.SNACFrame))
 	})
 	return _c
 }
@@ -76,7 +77,7 @@ func (_c *mockAdminService_ConfirmRequest_Call) Return(_a0 wire.SNACMessage, _a1
 	return _c
 }
 
-func (_c *mockAdminService_ConfirmRequest_Call) RunAndReturn(run func(context.Context, wire.SNACFrame) (wire.SNACMessage, error)) *mockAdminService_ConfirmRequest_Call {
+func (_c *mockAdminService_ConfirmRequest_Call) RunAndReturn(run func(context.Context, *state.Session, wire.SNACFrame) (wire.SNACMessage, error)) *mockAdminService_ConfirmRequest_Call {
 	_c.Call.Return(run)
 	return _c
 }