feat(BRIDGE-379): mailbox pre-checker on startup & conflict resolver for bridge internal mailboxes; TODO potentially add this for system mailboxes as well

This commit is contained in:
Atanas Janeshliev
2025-06-03 17:30:30 +02:00
parent d2742c81e5
commit 39f2362996
10 changed files with 541 additions and 32 deletions

View File

@ -121,7 +121,7 @@ func TestResolveConflict_UnexpectedLabelConflict(t *testing.T) {
connector := &imapservice.Connector{}
connector.SetAddrIDTest("addr-1")
resolver := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderFalse{}).
NewConflictResolver([]*imapservice.Connector{connector})
NewUserConflictResolver([]*imapservice.Connector{connector})
visited := make(map[string]bool)
_, err := resolver.ResolveConflict(ctx, label, visited)
@ -152,7 +152,7 @@ func TestResolveDiscrepancy_LabelDoesNotExist(t *testing.T) {
connectors := []*imapservice.Connector{connector}
manager := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderFalse{})
resolver := manager.NewConflictResolver(connectors)
resolver := manager.NewUserConflictResolver(connectors)
visited := make(map[string]bool)
fn, err := resolver.ResolveConflict(ctx, label, visited)
@ -185,7 +185,7 @@ func TestResolveConflict_MailboxFetchError(t *testing.T) {
connector := &imapservice.Connector{}
connector.SetAddrIDTest("addr-1")
resolver := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderFalse{}).
NewConflictResolver([]*imapservice.Connector{connector})
NewUserConflictResolver([]*imapservice.Connector{connector})
visited := make(map[string]bool)
_, err := resolver.ResolveConflict(ctx, label, visited)
@ -223,7 +223,7 @@ func TestResolveDiscrepancy_ConflictingLabelDeletedRemotely(t *testing.T) {
connectors := []*imapservice.Connector{connector}
manager := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderFalse{})
resolver := manager.NewConflictResolver(connectors)
resolver := manager.NewUserConflictResolver(connectors)
visited := make(map[string]bool)
fn, err := resolver.ResolveConflict(ctx, label, visited)
@ -266,7 +266,7 @@ func TestResolveDiscrepancy_LabelAlreadyCorrect(t *testing.T) {
connectors := []*imapservice.Connector{connector}
manager := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderFalse{})
resolver := manager.NewConflictResolver(connectors)
resolver := manager.NewUserConflictResolver(connectors)
visited := make(map[string]bool)
fn, err := resolver.ResolveConflict(ctx, label, visited)
@ -295,7 +295,7 @@ func TestResolveConflict_DeepNestedPath(t *testing.T) {
connector := &imapservice.Connector{}
connector.SetAddrIDTest("addr-1")
resolver := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderFalse{}).
NewConflictResolver([]*imapservice.Connector{connector})
NewUserConflictResolver([]*imapservice.Connector{connector})
visited := make(map[string]bool)
fn, err := resolver.ResolveConflict(ctx, label, visited)
@ -360,7 +360,7 @@ func TestResolveLabelDiscrepancy_LabelSwap(t *testing.T) {
connectors := []*imapservice.Connector{connector}
manager := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderFalse{})
resolver := manager.NewConflictResolver(connectors)
resolver := manager.NewUserConflictResolver(connectors)
visited := make(map[string]bool)
fn, err := resolver.ResolveConflict(context.Background(), apiLabels[0], visited)
@ -453,7 +453,7 @@ func TestResolveLabelDiscrepancy_LabelSwapExtended(t *testing.T) {
connectors := []*imapservice.Connector{connector}
manager := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderFalse{})
resolver := manager.NewConflictResolver(connectors)
resolver := manager.NewUserConflictResolver(connectors)
fn, err := resolver.ResolveConflict(context.Background(), apiLabels[0], make(map[string]bool))
require.NoError(t, err)
@ -538,7 +538,7 @@ func TestResolveLabelDiscrepancy_LabelSwapCyclic(t *testing.T) {
connectors := []*imapservice.Connector{connector}
manager := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderFalse{})
resolver := manager.NewConflictResolver(connectors)
resolver := manager.NewUserConflictResolver(connectors)
fn, err := resolver.ResolveConflict(context.Background(), apiLabels[0], make(map[string]bool))
require.NoError(t, err)
@ -612,7 +612,7 @@ func TestResolveLabelDiscrepancy_LabelSwapCyclicWithDeletedLabel(t *testing.T) {
connectors := []*imapservice.Connector{connector}
manager := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderFalse{})
resolver := manager.NewConflictResolver(connectors)
resolver := manager.NewUserConflictResolver(connectors)
fn, err := resolver.ResolveConflict(context.Background(), apiLabels[2], make(map[string]bool))
require.NoError(t, err)
@ -675,7 +675,7 @@ func TestResolveLabelDiscrepancy_LabelSwapCyclicWithDeletedLabel_KillSwitchEnabl
connectors := []*imapservice.Connector{connector}
manager := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderTrue{})
resolver := manager.NewConflictResolver(connectors)
resolver := manager.NewUserConflictResolver(connectors)
fn, err := resolver.ResolveConflict(context.Background(), apiLabels[2], make(map[string]bool))
require.NoError(t, err)
@ -683,3 +683,185 @@ func TestResolveLabelDiscrepancy_LabelSwapCyclicWithDeletedLabel_KillSwitchEnabl
updates := fn()
assert.Empty(t, updates)
}
func TestInternalLabelConflictResolver_NoConflicts(t *testing.T) {
ctx := context.Background()
mockLabelProvider := new(mockLabelNameProvider)
mockClient := new(mockAPIClient)
mockIDProvider := new(mockIDProvider)
mockReporter := new(mockReporter)
mockIDProvider.On("GetGluonID", "addr-1").Return("gluon-id-1", true)
mockLabelProvider.On("GetUserMailboxByName", mock.Anything, "gluon-id-1", []string{"Folders"}).
Return(imap.MailboxData{}, db.ErrNotFound)
mockLabelProvider.On("GetUserMailboxByName", mock.Anything, "gluon-id-1", []string{"Labels"}).
Return(imap.MailboxData{}, db.ErrNotFound)
connector := &imapservice.Connector{}
connector.SetAddrIDTest("addr-1")
connectors := []*imapservice.Connector{connector}
manager := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderFalse{})
resolver := manager.NewInternalLabelConflictResolver(connectors)
fn, err := resolver.ResolveConflict(ctx)
assert.NoError(t, err)
updates := fn()
assert.Empty(t, updates)
}
func TestInternalLabelConflictResolver_CorrectIDs(t *testing.T) {
ctx := context.Background()
mockLabelProvider := new(mockLabelNameProvider)
mockClient := new(mockAPIClient)
mockIDProvider := new(mockIDProvider)
mockReporter := new(mockReporter)
mockIDProvider.On("GetGluonID", "addr-1").Return("gluon-id-1", true)
mockLabelProvider.On("GetUserMailboxByName", mock.Anything, "gluon-id-1", []string{"Folders"}).
Return(imap.MailboxData{RemoteID: "Folders", BridgeName: []string{"Folders"}}, nil)
mockLabelProvider.On("GetUserMailboxByName", mock.Anything, "gluon-id-1", []string{"Labels"}).
Return(imap.MailboxData{RemoteID: "Labels", BridgeName: []string{"Labels"}}, nil)
connector := &imapservice.Connector{}
connector.SetAddrIDTest("addr-1")
connectors := []*imapservice.Connector{connector}
manager := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderFalse{})
resolver := manager.NewInternalLabelConflictResolver(connectors)
fn, err := resolver.ResolveConflict(ctx)
assert.NoError(t, err)
updates := fn()
assert.Empty(t, updates)
}
func TestInternalLabelConflictResolver_ConflictingFoldersID(t *testing.T) {
ctx := context.Background()
mockLabelProvider := new(mockLabelNameProvider)
mockClient := new(mockAPIClient)
mockIDProvider := new(mockIDProvider)
mockReporter := new(mockReporter)
mockIDProvider.On("GetGluonID", "addr-1").Return("gluon-id-1", true)
mockLabelProvider.On("GetUserMailboxByName", mock.Anything, "gluon-id-1", []string{"Folders"}).
Return(imap.MailboxData{RemoteID: "wrong-id", BridgeName: []string{"Folders"}}, nil)
mockLabelProvider.On("GetUserMailboxByName", mock.Anything, "gluon-id-1", []string{"Labels"}).
Return(imap.MailboxData{}, db.ErrNotFound)
connector := &imapservice.Connector{}
connector.SetAddrIDTest("addr-1")
connectors := []*imapservice.Connector{connector}
manager := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderFalse{})
resolver := manager.NewInternalLabelConflictResolver(connectors)
fn, err := resolver.ResolveConflict(ctx)
assert.NoError(t, err)
updates := fn()
assert.Len(t, updates, 1)
deleted, ok := updates[0].(*imap.MailboxDeleted)
assert.True(t, ok)
assert.Equal(t, imap.MailboxID("Folders"), deleted.MailboxID)
}
func TestInternalLabelConflictResolver_BothConflicting(t *testing.T) {
ctx := context.Background()
mockLabelProvider := new(mockLabelNameProvider)
mockClient := new(mockAPIClient)
mockIDProvider := new(mockIDProvider)
mockReporter := new(mockReporter)
mockIDProvider.On("GetGluonID", "addr-1").Return("gluon-id-1", true)
mockLabelProvider.On("GetUserMailboxByName", mock.Anything, "gluon-id-1", []string{"Folders"}).
Return(imap.MailboxData{RemoteID: "wrong-folders-id", BridgeName: []string{"Folders"}}, nil)
mockLabelProvider.On("GetUserMailboxByName", mock.Anything, "gluon-id-1", []string{"Labels"}).
Return(imap.MailboxData{RemoteID: "wrong-labels-id", BridgeName: []string{"Labels"}}, nil)
connector := &imapservice.Connector{}
connector.SetAddrIDTest("addr-1")
connectors := []*imapservice.Connector{connector}
manager := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderFalse{})
resolver := manager.NewInternalLabelConflictResolver(connectors)
fn, err := resolver.ResolveConflict(ctx)
assert.NoError(t, err)
updates := fn()
assert.Len(t, updates, 2)
updateOne, ok := updates[0].(*imap.MailboxDeleted)
assert.True(t, ok)
assert.Equal(t, imap.MailboxID("Folders"), updateOne.MailboxID)
updateTwo, ok := updates[1].(*imap.MailboxDeleted)
assert.True(t, ok)
assert.Equal(t, imap.MailboxID("Labels"), updateTwo.MailboxID)
}
func TestInternalLabelConflictResolver_MailboxFetchError(t *testing.T) {
ctx := context.Background()
mockLabelProvider := new(mockLabelNameProvider)
mockClient := new(mockAPIClient)
mockIDProvider := new(mockIDProvider)
mockReporter := new(mockReporter)
mockIDProvider.On("GetGluonID", "addr-1").Return("gluon-id-1", true)
mockLabelProvider.On("GetUserMailboxByName", mock.Anything, "gluon-id-1", []string{"Folders"}).
Return(imap.MailboxData{}, errors.New("database connection error"))
connector := &imapservice.Connector{}
connector.SetAddrIDTest("addr-1")
connectors := []*imapservice.Connector{connector}
manager := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderFalse{})
resolver := manager.NewInternalLabelConflictResolver(connectors)
_, err := resolver.ResolveConflict(ctx)
assert.Error(t, err)
assert.Contains(t, err.Error(), "database connection error")
}
func TestNewInternalLabelConflictResolver_KillSwitchEnabled(t *testing.T) {
ctx := context.Background()
mockLabelProvider := new(mockLabelNameProvider)
mockClient := new(mockAPIClient)
mockIDProvider := new(mockIDProvider)
mockReporter := new(mockReporter)
mockIDProvider.On("GetGluonID", "addr-1").Return("gluon-id-1", true)
mockLabelProvider.On("GetUserMailboxByName", mock.Anything, "gluon-id-1", []string{"Folders"}).
Return(imap.MailboxData{RemoteID: "wrong-folders-id", BridgeName: []string{"Folders"}}, nil)
mockLabelProvider.On("GetUserMailboxByName", mock.Anything, "gluon-id-1", []string{"Labels"}).
Return(imap.MailboxData{RemoteID: "wrong-labels-id", BridgeName: []string{"Labels"}}, nil)
connector := &imapservice.Connector{}
connector.SetAddrIDTest("addr-1")
connectors := []*imapservice.Connector{connector}
manager := imapservice.NewLabelConflictManager(mockLabelProvider, mockIDProvider, mockClient, mockReporter, ffProviderTrue{})
resolver := manager.NewInternalLabelConflictResolver(connectors)
fn, err := resolver.ResolveConflict(ctx)
assert.NoError(t, err)
updates := fn()
assert.Empty(t, updates)
}