GODT-2037: Handle and log API refresh event

This commit is contained in:
James Houlahan
2022-11-10 23:28:08 +01:00
parent 2023df3ef8
commit 59278913ca
12 changed files with 192 additions and 64 deletions

View File

@ -20,6 +20,7 @@ package bridge_test
import (
"context"
"crypto/tls"
"fmt"
"net/http"
"os"
"sync"
@ -536,3 +537,22 @@ func getConnectedUserIDs(t *testing.T, bridge *bridge.Bridge) []string {
return info.Connected
})
}
func chToType[In, Out any](inCh <-chan In, done func()) (<-chan Out, func()) {
outCh := make(chan Out)
go func() {
defer close(outCh)
for in := range inCh {
out, ok := any(in).(Out)
if !ok {
panic(fmt.Sprintf("unexpected type %T", in))
}
outCh <- out
}
}()
return outCh, done
}

View File

@ -203,22 +203,3 @@ func countBytesRead(ctl *liteapi.NetCtl, fn func()) uint64 {
return read
}
func chToType[In, Out any](inCh <-chan In, done func()) (<-chan Out, func()) {
outCh := make(chan Out)
go func() {
defer close(outCh)
for in := range inCh {
out, ok := any(in).(Out)
if !ok {
panic(fmt.Sprintf("unexpected type %T", in))
}
outCh <- out
}
}()
return outCh, done
}

View File

@ -257,14 +257,8 @@ func (bridge *Bridge) SetAddressMode(ctx context.Context, userID string, mode va
return fmt.Errorf("address mode is already %q", mode)
}
for addrID, gluonID := range user.GetGluonIDs() {
if err := bridge.imapServer.RemoveUser(ctx, gluonID, true); err != nil {
return fmt.Errorf("failed to remove user from IMAP server: %w", err)
}
if err := user.RemoveGluonID(addrID, gluonID); err != nil {
return fmt.Errorf("failed to remove gluon ID from user: %w", err)
}
if err := bridge.removeIMAPUser(ctx, user, true); err != nil {
return fmt.Errorf("failed to remove IMAP user: %w", err)
}
if err := user.SetAddressMode(ctx, mode); err != nil {

View File

@ -44,11 +44,13 @@ func (bridge *Bridge) handleUserEvent(ctx context.Context, user *user.User, even
return fmt.Errorf("failed to handle user address deleted event: %w", err)
}
case events.UserRefreshed:
if err := bridge.handleUserRefreshed(ctx, user); err != nil {
return fmt.Errorf("failed to handle user refreshed event: %w", err)
}
case events.UserDeauth:
safe.Lock(func() {
defer delete(bridge.users, user.ID())
bridge.logoutUser(ctx, user, false, false)
}, bridge.usersLock)
bridge.handleUserDeauth(ctx, user)
}
return nil
@ -100,3 +102,24 @@ func (bridge *Bridge) handleUserAddressDeleted(ctx context.Context, user *user.U
return nil
}
func (bridge *Bridge) handleUserRefreshed(ctx context.Context, user *user.User) error {
return safe.RLockRet(func() error {
if err := bridge.removeIMAPUser(ctx, user, true); err != nil {
return fmt.Errorf("failed to remove IMAP user: %w", err)
}
if err := bridge.addIMAPUser(ctx, user); err != nil {
return fmt.Errorf("failed to add IMAP user: %w", err)
}
return nil
}, bridge.usersLock)
}
func (bridge *Bridge) handleUserDeauth(ctx context.Context, user *user.User) {
safe.Lock(func() {
defer delete(bridge.users, user.ID())
bridge.logoutUser(ctx, user, false, false)
}, bridge.usersLock)
}

View File

@ -609,6 +609,34 @@ func TestBridge_UserInfo_Alias(t *testing.T) {
})
}
func TestBridge_User_Refresh(t *testing.T) {
withEnv(t, func(ctx context.Context, s *server.Server, netCtl *liteapi.NetCtl, locator bridge.Locator, vaultKey []byte) {
withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) {
// Get a channel of sync started events.
syncStartCh, done := chToType[events.Event, events.SyncStarted](bridge.GetEvents(events.SyncStarted{}))
defer done()
// Get a channel of sync finished events.
syncFinishCh, done := chToType[events.Event, events.SyncFinished](bridge.GetEvents(events.SyncFinished{}))
defer done()
// Log the user in.
userID := must(bridge.LoginFull(ctx, username, password, nil, nil))
// The sync should start and finish.
require.Equal(t, userID, (<-syncStartCh).UserID)
require.Equal(t, userID, (<-syncFinishCh).UserID)
// Trigger a refresh.
require.NoError(t, s.RefreshUser(userID, liteapi.RefreshAll))
// The sync should start and finish again.
require.Equal(t, userID, (<-syncStartCh).UserID)
require.Equal(t, userID, (<-syncFinishCh).UserID)
})
})
}
// getErr returns the error that was passed to it.
func getErr[T any](val T, err error) error {
return err