diff --git a/pkg/middleware/chat/process/add_to_room_test.go b/pkg/middleware/chat/process/add_to_room_test.go new file mode 100644 index 0000000..f73ba34 --- /dev/null +++ b/pkg/middleware/chat/process/add_to_room_test.go @@ -0,0 +1,137 @@ +package process + +import ( + "context" + "errors" + "testing" + + chaterrors "github.com/harshabose/socket-comm/pkg/middleware/chat/errors" + "github.com/harshabose/socket-comm/pkg/middleware/chat/interfaces" + "github.com/harshabose/socket-comm/pkg/middleware/chat/state" + "github.com/harshabose/socket-comm/pkg/middleware/chat/types" +) + +// MockProcessor is a mock implementation of the Processor interface +type MockProcessor struct { + addFunc func(types.RoomID, *state.State) error +} + +// Add is a mock implementation of the CanAdd interface +func (m *MockProcessor) Add(roomID types.RoomID, s *state.State) error { + if m.addFunc != nil { + return m.addFunc(roomID, s) + } + return nil +} + +// Process implements the CanProcess interface +func (m *MockProcessor) Process(ctx context.Context, p interfaces.CanBeProcessed, s *state.State) error { + // This method should not be called in our tests + return errors.New("Process method should not be called in tests") +} + +// ProcessBackground implements the CanProcessBackground interface +func (m *MockProcessor) ProcessBackground(ctx context.Context, p interfaces.CanBeProcessedBackground, s *state.State) interfaces.CanBeProcessedBackground { + // This method should not be called in our tests + return nil +} + +// MockProcessorWithoutAdd is a mock implementation of the Processor interface without CanAdd +type MockProcessorWithoutAdd struct{} + +// Process implements the CanProcess interface +func (m *MockProcessorWithoutAdd) Process(ctx context.Context, p interfaces.CanBeProcessed, s *state.State) error { + // This method should not be called in our tests + return errors.New("Process method should not be called in tests") +} + +// ProcessBackground implements the CanProcessBackground interface +func (m *MockProcessorWithoutAdd) ProcessBackground(ctx context.Context, p interfaces.CanBeProcessedBackground, s *state.State) interfaces.CanBeProcessedBackground { + // This method should not be called in our tests + return nil +} + +func TestAddToRoom_Process(t *testing.T) { + tests := []struct { + name string + roomID types.RoomID + mockAddFunc func(types.RoomID, *state.State) error + contextTimeout bool + wantErr bool + expectedErr error + }{ + { + name: "successful add to room", + roomID: "test-room", + mockAddFunc: func(roomID types.RoomID, s *state.State) error { + return nil + }, + wantErr: false, + }, + { + name: "error adding to room", + roomID: "test-room", + mockAddFunc: func(roomID types.RoomID, s *state.State) error { + return errors.New("failed to add to room") + }, + wantErr: true, + expectedErr: errors.New("failed to add to room"), + }, + { + name: "context cancelled", + roomID: "test-room", + contextTimeout: true, + wantErr: true, + expectedErr: chaterrors.ErrContextCancelled, + }, + { + name: "interface mismatch", + roomID: "test-room", + mockAddFunc: nil, // This will cause the type assertion to fail + wantErr: true, + expectedErr: chaterrors.ErrInterfaceMisMatch, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a context that can be cancelled if needed + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // Cancel the context if the test requires it + if tt.contextTimeout { + cancel() + } + + // Create a dummy state + s := &state.State{} + + // Create the process + process := NewAddToRoom(tt.roomID) + + // Use different mock processor for interface mismatch test + var processor interfaces.Processor + if tt.name == "interface mismatch" { + processor = &MockProcessorWithoutAdd{} + } else { + processor = &MockProcessor{ + addFunc: tt.mockAddFunc, + } + } + + // Execute the process + err := process.Process(ctx, processor, s) + + // Check if the error matches expectations + if (err != nil) != tt.wantErr { + t.Errorf("Process() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if tt.wantErr && tt.expectedErr != nil && err.Error() != tt.expectedErr.Error() { + t.Errorf("Process() error = %v, expectedErr %v", err, tt.expectedErr) + } + }) + } +} diff --git a/pkg/middleware/chat/process/create_room_test.go b/pkg/middleware/chat/process/create_room_test.go new file mode 100644 index 0000000..e7f22a9 --- /dev/null +++ b/pkg/middleware/chat/process/create_room_test.go @@ -0,0 +1,149 @@ +package process + +import ( + "context" + "errors" + "testing" + "time" + + chaterrors "github.com/harshabose/socket-comm/pkg/middleware/chat/errors" + "github.com/harshabose/socket-comm/pkg/middleware/chat/interfaces" + "github.com/harshabose/socket-comm/pkg/middleware/chat/room" + "github.com/harshabose/socket-comm/pkg/middleware/chat/state" + "github.com/harshabose/socket-comm/pkg/middleware/chat/types" +) + +// MockCreateRoomProcessor is a mock implementation of the Processor interface with CanCreateRoom +type MockCreateRoomProcessor struct { + createRoomFunc func(types.RoomID, []types.ClientID, time.Duration) (*room.Room, error) +} + +// CreateRoom is a mock implementation of the CanCreateRoom interface +func (m *MockCreateRoomProcessor) CreateRoom(roomID types.RoomID, allowed []types.ClientID, ttl time.Duration) (*room.Room, error) { + if m.createRoomFunc != nil { + return m.createRoomFunc(roomID, allowed, ttl) + } + return &room.Room{}, nil +} + +// Process implements the CanProcess interface +func (m *MockCreateRoomProcessor) Process(ctx context.Context, p interfaces.CanBeProcessed, s *state.State) error { + // This method should not be called in our tests + return errors.New("Process method should not be called in tests") +} + +// ProcessBackground implements the CanProcessBackground interface +func (m *MockCreateRoomProcessor) ProcessBackground(ctx context.Context, p interfaces.CanBeProcessedBackground, s *state.State) interfaces.CanBeProcessedBackground { + // This method should not be called in our tests + return nil +} + +// MockProcessorWithoutCreateRoom is a mock implementation of the Processor interface without CanCreateRoom +type MockProcessorWithoutCreateRoom struct{} + +// Process implements the CanProcess interface +func (m *MockProcessorWithoutCreateRoom) Process(ctx context.Context, p interfaces.CanBeProcessed, s *state.State) error { + // This method should not be called in our tests + return errors.New("Process method should not be called in tests") +} + +// ProcessBackground implements the CanProcessBackground interface +func (m *MockProcessorWithoutCreateRoom) ProcessBackground(ctx context.Context, p interfaces.CanBeProcessedBackground, s *state.State) interfaces.CanBeProcessedBackground { + // This method should not be called in our tests + return nil +} + +func TestCreateRoom_Process(t *testing.T) { + tests := []struct { + name string + roomID types.RoomID + allowed []types.ClientID + ttl time.Duration + mockCreateRoomFunc func(types.RoomID, []types.ClientID, time.Duration) (*room.Room, error) + contextTimeout bool + wantErr bool + expectedErr error + }{ + { + name: "successful create room", + roomID: "test-room", + allowed: []types.ClientID{"client1", "client2"}, + ttl: time.Hour, + mockCreateRoomFunc: func(roomID types.RoomID, allowed []types.ClientID, ttl time.Duration) (*room.Room, error) { + return &room.Room{}, nil + }, + wantErr: false, + }, + { + name: "error creating room", + roomID: "test-room", + allowed: []types.ClientID{"client1", "client2"}, + ttl: time.Hour, + mockCreateRoomFunc: func(roomID types.RoomID, allowed []types.ClientID, ttl time.Duration) (*room.Room, error) { + return nil, errors.New("failed to create room") + }, + wantErr: true, + expectedErr: errors.New("failed to create room"), + }, + { + name: "context cancelled", + roomID: "test-room", + allowed: []types.ClientID{"client1", "client2"}, + ttl: time.Hour, + contextTimeout: true, + wantErr: true, + expectedErr: chaterrors.ErrContextCancelled, + }, + { + name: "interface mismatch", + roomID: "test-room", + allowed: []types.ClientID{"client1", "client2"}, + ttl: time.Hour, + mockCreateRoomFunc: nil, // This will cause the type assertion to fail + wantErr: true, + expectedErr: chaterrors.ErrInterfaceMisMatch, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a context that can be cancelled if needed + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // Cancel the context if the test requires it + if tt.contextTimeout { + cancel() + } + + // Create a dummy state + s := &state.State{} + + // Create the process + process := NewCreateRoom(tt.roomID, tt.allowed, tt.ttl) + + // Use different mock processor for interface mismatch test + var processor interfaces.Processor + if tt.name == "interface mismatch" { + processor = &MockProcessorWithoutCreateRoom{} + } else { + processor = &MockCreateRoomProcessor{ + createRoomFunc: tt.mockCreateRoomFunc, + } + } + + // Execute the process + err := process.Process(ctx, processor, s) + + // Check if the error matches expectations + if (err != nil) != tt.wantErr { + t.Errorf("Process() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if tt.wantErr && tt.expectedErr != nil && err.Error() != tt.expectedErr.Error() { + t.Errorf("Process() error = %v, expectedErr %v", err, tt.expectedErr) + } + }) + } +} diff --git a/pkg/middleware/chat/process/delete_room_test.go b/pkg/middleware/chat/process/delete_room_test.go new file mode 100644 index 0000000..cdb1219 --- /dev/null +++ b/pkg/middleware/chat/process/delete_room_test.go @@ -0,0 +1,139 @@ +package process + +import ( + "context" + "errors" + "testing" + + chaterrors "github.com/harshabose/socket-comm/pkg/middleware/chat/errors" + "github.com/harshabose/socket-comm/pkg/middleware/chat/interfaces" + "github.com/harshabose/socket-comm/pkg/middleware/chat/state" + "github.com/harshabose/socket-comm/pkg/middleware/chat/types" +) + +// MockDeleteRoomProcessor is a mock implementation of the Processor interface with CanDeleteRoom +type MockDeleteRoomProcessor struct { + deleteRoomFunc func(types.RoomID) error +} + +// DeleteRoom is a mock implementation of the CanDeleteRoom interface +func (m *MockDeleteRoomProcessor) DeleteRoom(roomID types.RoomID) error { + if m.deleteRoomFunc != nil { + return m.deleteRoomFunc(roomID) + } + return nil +} + +// Process implements the CanProcess interface +func (m *MockDeleteRoomProcessor) Process(ctx context.Context, p interfaces.CanBeProcessed, s *state.State) error { + // This method should not be called in our tests + return errors.New("Process method should not be called in tests") +} + +// ProcessBackground implements the CanProcessBackground interface +func (m *MockDeleteRoomProcessor) ProcessBackground(ctx context.Context, p interfaces.CanBeProcessedBackground, s *state.State) interfaces.CanBeProcessedBackground { + // This method should not be called in our tests + return nil +} + +// MockProcessorWithoutDeleteRoom is a mock implementation of the Processor interface without CanDeleteRoom +type MockProcessorWithoutDeleteRoom struct{} + +// Process implements the CanProcess interface +func (m *MockProcessorWithoutDeleteRoom) Process(ctx context.Context, p interfaces.CanBeProcessed, s *state.State) error { + // This method should not be called in our tests + return errors.New("Process method should not be called in tests") +} + +// ProcessBackground implements the CanProcessBackground interface +func (m *MockProcessorWithoutDeleteRoom) ProcessBackground(ctx context.Context, p interfaces.CanBeProcessedBackground, s *state.State) interfaces.CanBeProcessedBackground { + // This method should not be called in our tests + return nil +} + +func TestDeleteRoom_Process(t *testing.T) { + tests := []struct { + name string + roomID types.RoomID + mockDeleteRoomFunc func(types.RoomID) error + contextTimeout bool + wantErr bool + expectedErr error + }{ + { + name: "successful delete room", + roomID: "test-room", + mockDeleteRoomFunc: func(roomID types.RoomID) error { + return nil + }, + wantErr: false, + }, + { + name: "error deleting room", + roomID: "test-room", + mockDeleteRoomFunc: func(roomID types.RoomID) error { + return errors.New("failed to delete room") + }, + wantErr: true, + expectedErr: errors.New("failed to delete room"), + }, + { + name: "context cancelled", + roomID: "test-room", + contextTimeout: true, + wantErr: true, + expectedErr: chaterrors.ErrContextCancelled, + }, + { + name: "interface mismatch", + roomID: "test-room", + mockDeleteRoomFunc: nil, // This will cause the type assertion to fail + wantErr: true, + expectedErr: chaterrors.ErrInterfaceMisMatch, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a context that can be cancelled if needed + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // Cancel the context if the test requires it + if tt.contextTimeout { + cancel() + } + + // Create a dummy state + s := &state.State{} + + // Create the process + process := &DeleteRoom{ + RoomID: tt.roomID, + } + + // Use different mock processor for interface mismatch test + var processor interfaces.Processor + if tt.name == "interface mismatch" { + processor = &MockProcessorWithoutDeleteRoom{} + } else { + processor = &MockDeleteRoomProcessor{ + deleteRoomFunc: tt.mockDeleteRoomFunc, + } + } + + // Execute the process + err := process.Process(ctx, processor, s) + + // Check if the error matches expectations + if (err != nil) != tt.wantErr { + t.Errorf("Process() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if tt.wantErr && tt.expectedErr != nil && err.Error() != tt.expectedErr.Error() { + t.Errorf("Process() error = %v, expectedErr %v", err, tt.expectedErr) + } + }) + } +} diff --git a/pkg/middleware/chat/process/remove_from_room_test.go b/pkg/middleware/chat/process/remove_from_room_test.go new file mode 100644 index 0000000..bdd79e1 --- /dev/null +++ b/pkg/middleware/chat/process/remove_from_room_test.go @@ -0,0 +1,122 @@ +package process + +import ( + "context" + "errors" + "testing" + + chaterrors "github.com/harshabose/socket-comm/pkg/middleware/chat/errors" + "github.com/harshabose/socket-comm/pkg/middleware/chat/interfaces" + "github.com/harshabose/socket-comm/pkg/middleware/chat/state" + "github.com/harshabose/socket-comm/pkg/middleware/chat/types" +) + +// MockRemoveProcessor is a mock implementation of the Processor interface with CanRemove +type MockRemoveProcessor struct { + removeFunc func(types.RoomID, *state.State) error +} + +// Remove is a mock implementation of the CanRemove interface +func (m *MockRemoveProcessor) Remove(roomID types.RoomID, s *state.State) error { + if m.removeFunc != nil { + return m.removeFunc(roomID, s) + } + return nil +} + +// Process implements the CanProcess interface +func (m *MockRemoveProcessor) Process(ctx context.Context, p interfaces.CanBeProcessed, s *state.State) error { + // This method should not be called in our tests + return errors.New("Process method should not be called in tests") +} + +// ProcessBackground implements the CanProcessBackground interface +func (m *MockRemoveProcessor) ProcessBackground(ctx context.Context, p interfaces.CanBeProcessedBackground, s *state.State) interfaces.CanBeProcessedBackground { + // This method should not be called in our tests + return nil +} + +// MockProcessorWithoutRemove is a mock implementation of the Processor interface without CanRemove +type MockProcessorWithoutRemove struct{} + +// Process implements the CanProcess interface +func (m *MockProcessorWithoutRemove) Process(ctx context.Context, p interfaces.CanBeProcessed, s *state.State) error { + // This method should not be called in our tests + return errors.New("Process method should not be called in tests") +} + +// ProcessBackground implements the CanProcessBackground interface +func (m *MockProcessorWithoutRemove) ProcessBackground(ctx context.Context, p interfaces.CanBeProcessedBackground, s *state.State) interfaces.CanBeProcessedBackground { + // This method should not be called in our tests + return nil +} + +func TestRemoveFromRoom_Process(t *testing.T) { + tests := []struct { + name string + roomID types.RoomID + mockRemoveFunc func(types.RoomID, *state.State) error + wantErr bool + expectedErr error + }{ + { + name: "successful remove from room", + roomID: "test-room", + mockRemoveFunc: func(roomID types.RoomID, s *state.State) error { + return nil + }, + wantErr: false, + }, + { + name: "error removing from room", + roomID: "test-room", + mockRemoveFunc: func(roomID types.RoomID, s *state.State) error { + return errors.New("failed to remove from room") + }, + wantErr: true, + expectedErr: errors.New("failed to remove from room"), + }, + { + name: "interface mismatch", + roomID: "test-room", + mockRemoveFunc: nil, // This will cause the type assertion to fail + wantErr: true, + expectedErr: chaterrors.ErrInterfaceMisMatch, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a dummy state + s := &state.State{} + + // Create the process + process := &RemoveFromRoom{ + RoomID: tt.roomID, + } + + // Use different mock processor for interface mismatch test + var processor interfaces.Processor + if tt.name == "interface mismatch" { + processor = &MockProcessorWithoutRemove{} + } else { + processor = &MockRemoveProcessor{ + removeFunc: tt.mockRemoveFunc, + } + } + + // Execute the process + err := process.Process(context.Background(), processor, s) + + // Check if the error matches expectations + if (err != nil) != tt.wantErr { + t.Errorf("Process() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if tt.wantErr && tt.expectedErr != nil && err.Error() != tt.expectedErr.Error() { + t.Errorf("Process() error = %v, expectedErr %v", err, tt.expectedErr) + } + }) + } +} diff --git a/pkg/middleware/chat/process/update_health_test.go b/pkg/middleware/chat/process/update_health_test.go new file mode 100644 index 0000000..ab76c5f --- /dev/null +++ b/pkg/middleware/chat/process/update_health_test.go @@ -0,0 +1,306 @@ +package process + +import ( + "context" + "errors" + "testing" + "time" + + chaterrors "github.com/harshabose/socket-comm/pkg/middleware/chat/errors" + "github.com/harshabose/socket-comm/pkg/middleware/chat/health" + "github.com/harshabose/socket-comm/pkg/middleware/chat/interfaces" + "github.com/harshabose/socket-comm/pkg/middleware/chat/state" + "github.com/harshabose/socket-comm/pkg/middleware/chat/types" +) + +// MockUpdateProcessor is a mock implementation of the Processor interface with CanUpdate +type MockUpdateProcessor struct { + updateFunc func(types.RoomID, types.ClientID, *health.Stat) error +} + +// Update is a mock implementation of the CanUpdate interface +func (m *MockUpdateProcessor) Update(roomID types.RoomID, clientID types.ClientID, stat *health.Stat) error { + if m.updateFunc != nil { + return m.updateFunc(roomID, clientID, stat) + } + return nil +} + +// Process implements the CanProcess interface +func (m *MockUpdateProcessor) Process(ctx context.Context, p interfaces.CanBeProcessed, s *state.State) error { + // This method should not be called in our tests + return errors.New("Process method should not be called in tests") +} + +// ProcessBackground implements the CanProcessBackground interface +func (m *MockUpdateProcessor) ProcessBackground(ctx context.Context, p interfaces.CanBeProcessedBackground, s *state.State) interfaces.CanBeProcessedBackground { + // This method should not be called in our tests + return nil +} + +// MockProcessorWithoutUpdate is a mock implementation of the Processor interface without CanUpdate +type MockProcessorWithoutUpdate struct{} + +// Process implements the CanProcess interface +func (m *MockProcessorWithoutUpdate) Process(ctx context.Context, p interfaces.CanBeProcessed, s *state.State) error { + // Call the Process method on the CanBeProcessed interface + return p.Process(ctx, m, s) +} + +// ProcessBackground implements the CanProcessBackground interface +func (m *MockProcessorWithoutUpdate) ProcessBackground(ctx context.Context, p interfaces.CanBeProcessedBackground, s *state.State) interfaces.CanBeProcessedBackground { + // Return the CanBeProcessedBackground interface + return p +} + +// MockBackgroundProcessorWithoutUpdate is a mock implementation of the Processor interface without CanUpdate +// specifically for background processing tests +type MockBackgroundProcessorWithoutUpdate struct{} + +// Process implements the CanProcess interface +func (m *MockBackgroundProcessorWithoutUpdate) Process(ctx context.Context, p interfaces.CanBeProcessed, s *state.State) error { + // This method should not be called in our tests + return errors.New("Process method should not be called in tests") +} + +// ProcessBackground implements the CanProcessBackground interface +func (m *MockBackgroundProcessorWithoutUpdate) ProcessBackground(ctx context.Context, p interfaces.CanBeProcessedBackground, s *state.State) interfaces.CanBeProcessedBackground { + // This method should not be called in our tests + return p +} + +func TestUpdateHealthStat_Process(t *testing.T) { + tests := []struct { + name string + roomID types.RoomID + stat health.Stat + mockUpdateFunc func(types.RoomID, types.ClientID, *health.Stat) error + contextTimeout bool + wantErr bool + expectedErr error + }{ + { + name: "successful update health", + roomID: "test-room", + stat: health.Stat{}, + mockUpdateFunc: func(roomID types.RoomID, clientID types.ClientID, stat *health.Stat) error { + return nil + }, + wantErr: false, + }, + { + name: "error updating health", + roomID: "test-room", + stat: health.Stat{}, + mockUpdateFunc: func(roomID types.RoomID, clientID types.ClientID, stat *health.Stat) error { + return errors.New("failed to update health") + }, + wantErr: true, + expectedErr: errors.New("failed to update health"), + }, + { + name: "context cancelled", + roomID: "test-room", + stat: health.Stat{}, + contextTimeout: true, + wantErr: true, + expectedErr: chaterrors.ErrContextCancelled, + }, + { + name: "interface mismatch", + roomID: "test-room", + stat: health.Stat{}, + mockUpdateFunc: nil, // This will cause the type assertion to fail + wantErr: true, + expectedErr: chaterrors.ErrInterfaceMisMatch, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a context that can be cancelled if needed + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // Cancel the context if the test requires it + if tt.contextTimeout { + cancel() + } + + // Create a dummy state with a client id + s := &state.State{} + s.SetClientID("test-client") + + // Create the process + process := &UpdateHealthStat{ + RoomID: tt.roomID, + Stat: tt.stat, + } + + // Use different mock processor for interface mismatch test + var processor interfaces.Processor + if tt.name == "interface mismatch" { + processor = &MockProcessorWithoutUpdate{} + } else { + processor = &MockUpdateProcessor{ + updateFunc: tt.mockUpdateFunc, + } + } + + // Execute the process + err := process.Process(ctx, processor, s) + + // Check if the error matches expectations + if (err != nil) != tt.wantErr { + t.Errorf("Process() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if tt.wantErr && tt.expectedErr != nil && err.Error() != tt.expectedErr.Error() { + t.Errorf("Process() error = %v, expectedErr %v", err, tt.expectedErr) + } + }) + } +} + +func TestUpdateHealthStat_ProcessBackground(t *testing.T) { + tests := []struct { + name string + roomID types.RoomID + stat health.Stat + mockUpdateFunc func(types.RoomID, types.ClientID, *health.Stat) error + contextTimeout bool + wantErr bool + expectedErr error + }{ + { + name: "successful background update health", + roomID: "test-room", + stat: health.Stat{}, + mockUpdateFunc: func(roomID types.RoomID, clientID types.ClientID, stat *health.Stat) error { + return nil + }, + wantErr: false, + }, + { + name: "error updating health in background", + roomID: "test-room", + stat: health.Stat{}, + mockUpdateFunc: func(roomID types.RoomID, clientID types.ClientID, stat *health.Stat) error { + return errors.New("failed to update health") + }, + wantErr: true, + expectedErr: errors.New("failed to update health"), + }, + { + name: "context cancelled in background", + roomID: "test-room", + stat: health.Stat{}, + contextTimeout: true, + wantErr: true, + expectedErr: chaterrors.ErrContextCancelled, + }, + { + name: "interface mismatch in background", + roomID: "test-room", + stat: health.Stat{}, + mockUpdateFunc: nil, // This will cause the type assertion to fail + wantErr: true, + expectedErr: chaterrors.ErrInterfaceMisMatch, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a context that can be cancelled if needed + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // Cancel the context if the test requires it + if tt.contextTimeout { + cancel() + } + + // Create a dummy state with a client id + s := &state.State{} + s.SetClientID("test-client") + + // Create the process + process := &UpdateHealthStat{ + RoomID: tt.roomID, + Stat: tt.stat, + } + + process.AsyncProcess = AsyncProcess{ + CanBeProcessed: process, + } + + // Use different mock processor for interface mismatch test + var processor interfaces.Processor + if tt.name == "interface mismatch in background" { + processor = &MockBackgroundProcessorWithoutUpdate{} + } else { + processor = &MockUpdateProcessor{ + updateFunc: tt.mockUpdateFunc, + } + } + + // Execute the process in background + backgroundProcess := process.ProcessBackground(ctx, processor, s) + + // Wait for the background process to complete + err := backgroundProcess.Wait() + + // Check if the error matches expectations + if (err != nil) != tt.wantErr { + t.Errorf("ProcessBackground() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if tt.wantErr && tt.expectedErr != nil && err.Error() != tt.expectedErr.Error() { + t.Errorf("ProcessBackground() error = %v, expectedErr %v", err, tt.expectedErr) + } + }) + } +} + +func TestUpdateHealthStat_ProcessBackground_Stop(t *testing.T) { + // Create a context + ctx := context.Background() + + // Create a dummy state with a client id + s := &state.State{} + s.SetClientID("test-client") + + // Create a mock processor that sleeps to simulate a long-running process + processor := &MockUpdateProcessor{ + updateFunc: func(roomID types.RoomID, clientID types.ClientID, stat *health.Stat) error { + time.Sleep(500 * time.Millisecond) + return nil + }, + } + + // Create the process + process := &UpdateHealthStat{ + RoomID: "test-room", + Stat: health.Stat{}, + } + + process.AsyncProcess = AsyncProcess{ + CanBeProcessed: process, + } + + // Execute the process in background + backgroundProcess := process.ProcessBackground(ctx, processor, s) + + // Stop the background process immediately + backgroundProcess.Stop() + + // Wait for the background process to complete + err := backgroundProcess.Wait() + + // The process should have been cancelled + if err != chaterrors.ErrContextCancelled { + t.Errorf("ProcessBackground() after Stop() error = %v, want %v", err, chaterrors.ErrContextCancelled) + } +}