446 lines
12 KiB
Go
446 lines
12 KiB
Go
// Copyright (c) 2023 Proton AG
|
|
//
|
|
// This file is part of Proton Mail Bridge.
|
|
//
|
|
// Proton Mail Bridge is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Proton Mail Bridge is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
package useridentity
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/ProtonMail/go-proton-api"
|
|
"github.com/ProtonMail/proton-bridge/v3/internal/events"
|
|
mocks2 "github.com/ProtonMail/proton-bridge/v3/internal/events/mocks"
|
|
"github.com/ProtonMail/proton-bridge/v3/internal/services/userevents"
|
|
"github.com/ProtonMail/proton-bridge/v3/internal/services/useridentity/mocks"
|
|
"github.com/golang/mock/gomock"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
const TestUserID = "MyUserID"
|
|
|
|
func TestService_OnUserEvent(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
|
|
service, eventPublisher, _ := newTestService(t, mockCtrl)
|
|
|
|
eventPublisher.EXPECT().PublishEvent(gomock.Any(), gomock.Eq(events.UserChanged{UserID: TestUserID})).Times(1)
|
|
|
|
require.NoError(t, service.HandleUserEvent(context.Background(), newTestUser()))
|
|
}
|
|
|
|
func TestService_OnUserSpaceChanged(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
|
|
service, eventPublisher, _ := newTestService(t, mockCtrl)
|
|
|
|
eventPublisher.EXPECT().PublishEvent(gomock.Any(), gomock.Eq(events.UsedSpaceChanged{UserID: TestUserID, UsedSpace: 1024})).Times(1)
|
|
|
|
// Original value, no changes.
|
|
require.NoError(t, service.HandleUsedSpaceEvent(context.Background(), 0))
|
|
|
|
// New value, event should be published.
|
|
require.NoError(t, service.HandleUsedSpaceEvent(context.Background(), 1024))
|
|
require.Equal(t, uint64(1024), service.identity.User.UsedSpace)
|
|
}
|
|
|
|
func TestService_OnRefreshEvent(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
|
|
service, eventPublisher, provider := newTestService(t, mockCtrl)
|
|
|
|
eventPublisher.EXPECT().PublishEvent(gomock.Any(), gomock.Eq(events.UserRefreshed{UserID: TestUserID, CancelEventPool: false})).Times(1)
|
|
|
|
newUser := newTestUserRefreshed()
|
|
newAddresses := newTestAddressesRefreshed()
|
|
|
|
{
|
|
getUserCall := provider.EXPECT().GetUser(gomock.Any()).Times(1).Return(*newUser, nil)
|
|
provider.EXPECT().GetAddresses(gomock.Any()).After(getUserCall).Times(1).Return(newAddresses, nil)
|
|
}
|
|
|
|
// Original value, no changes.
|
|
require.NoError(t, service.HandleRefreshEvent(context.Background(), 0))
|
|
|
|
require.Equal(t, *newUser, service.identity.User)
|
|
require.Equal(t, newAddresses, service.identity.AddressesSorted)
|
|
}
|
|
|
|
func TestService_OnAddressCreated(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
|
|
service, eventPublisher, _ := newTestService(t, mockCtrl)
|
|
|
|
newAddress := proton.Address{
|
|
ID: "NewAddrID",
|
|
Email: "new@bar.com",
|
|
Status: proton.AddressStatusEnabled,
|
|
}
|
|
|
|
eventPublisher.EXPECT().PublishEvent(gomock.Any(), gomock.Eq(events.UserAddressCreated{
|
|
UserID: TestUserID,
|
|
AddressID: newAddress.ID,
|
|
Email: newAddress.Email,
|
|
})).Times(1)
|
|
|
|
err := service.HandleAddressEvents(context.Background(), []proton.AddressEvent{
|
|
{
|
|
EventItem: proton.EventItem{
|
|
ID: "",
|
|
Action: proton.EventCreate,
|
|
},
|
|
Address: newAddress,
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
require.Contains(t, service.identity.Addresses, newAddress.ID)
|
|
}
|
|
|
|
func TestService_OnAddressCreatedDisabledDoesNotProduceEvent(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
|
|
service, _, _ := newTestService(t, mockCtrl)
|
|
|
|
newAddress := proton.Address{
|
|
ID: "Address1",
|
|
Email: "new@bar.com",
|
|
Status: proton.AddressStatusEnabled,
|
|
}
|
|
|
|
err := service.HandleAddressEvents(context.Background(), []proton.AddressEvent{
|
|
{
|
|
EventItem: proton.EventItem{
|
|
ID: "",
|
|
Action: proton.EventCreate,
|
|
},
|
|
Address: newAddress,
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
require.Contains(t, service.identity.Addresses, newAddress.ID)
|
|
}
|
|
|
|
func TestService_OnAddressCreatedDuplicateDoesNotProduceEvent(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
|
|
service, _, _ := newTestService(t, mockCtrl)
|
|
|
|
newAddress := proton.Address{
|
|
ID: "NewAddrID",
|
|
Email: "new@bar.com",
|
|
Status: proton.AddressStatusDisabled,
|
|
}
|
|
|
|
err := service.HandleAddressEvents(context.Background(), []proton.AddressEvent{
|
|
{
|
|
EventItem: proton.EventItem{
|
|
ID: "",
|
|
Action: proton.EventCreate,
|
|
},
|
|
Address: newAddress,
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
require.Contains(t, service.identity.Addresses, newAddress.ID)
|
|
}
|
|
|
|
func TestService_OnAddressUpdated(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
|
|
service, eventPublisher, _ := newTestService(t, mockCtrl)
|
|
|
|
newAddress := proton.Address{
|
|
ID: "Address1",
|
|
Email: "new@bar.com",
|
|
Status: proton.AddressStatusEnabled,
|
|
}
|
|
|
|
eventPublisher.EXPECT().PublishEvent(gomock.Any(), gomock.Eq(events.UserAddressUpdated{
|
|
UserID: TestUserID,
|
|
AddressID: newAddress.ID,
|
|
Email: newAddress.Email,
|
|
})).Times(1)
|
|
|
|
err := service.HandleAddressEvents(context.Background(), []proton.AddressEvent{
|
|
{
|
|
EventItem: proton.EventItem{
|
|
ID: "",
|
|
Action: proton.EventUpdate,
|
|
},
|
|
Address: newAddress,
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, newAddress, service.identity.Addresses[newAddress.ID])
|
|
}
|
|
|
|
func TestService_OnAddressUpdatedDisableFollowedByEnable(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
|
|
service, eventPublisher, _ := newTestService(t, mockCtrl)
|
|
|
|
newAddressDisabled := proton.Address{
|
|
ID: "Address1",
|
|
Email: "new@bar.com",
|
|
Status: proton.AddressStatusDisabled,
|
|
}
|
|
newAddressEnabled := proton.Address{
|
|
ID: "Address1",
|
|
Email: "new@bar.com",
|
|
Status: proton.AddressStatusEnabled,
|
|
}
|
|
|
|
{
|
|
disabledCall := eventPublisher.EXPECT().PublishEvent(gomock.Any(), gomock.Eq(events.UserAddressDisabled{
|
|
UserID: TestUserID,
|
|
AddressID: newAddressDisabled.ID,
|
|
Email: newAddressDisabled.Email,
|
|
})).Times(1)
|
|
|
|
eventPublisher.EXPECT().PublishEvent(gomock.Any(), gomock.Eq(events.UserAddressEnabled{
|
|
UserID: TestUserID,
|
|
AddressID: newAddressEnabled.ID,
|
|
Email: newAddressEnabled.Email,
|
|
})).Times(1).After(disabledCall)
|
|
}
|
|
|
|
err := service.HandleAddressEvents(context.Background(), []proton.AddressEvent{
|
|
{
|
|
EventItem: proton.EventItem{
|
|
ID: "",
|
|
Action: proton.EventUpdate,
|
|
},
|
|
Address: newAddressDisabled,
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, newAddressDisabled, service.identity.Addresses[newAddressEnabled.ID])
|
|
|
|
err = service.HandleAddressEvents(context.Background(), []proton.AddressEvent{
|
|
{
|
|
EventItem: proton.EventItem{
|
|
ID: "",
|
|
Action: proton.EventUpdate,
|
|
},
|
|
Address: newAddressEnabled,
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, newAddressEnabled, service.identity.Addresses[newAddressEnabled.ID])
|
|
}
|
|
|
|
func TestService_OnAddressUpdateCreatedIfNotExists(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
|
|
service, eventPublisher, _ := newTestService(t, mockCtrl)
|
|
|
|
newAddress := proton.Address{
|
|
ID: "NewAddrID",
|
|
Email: "new@bar.com",
|
|
Status: proton.AddressStatusEnabled,
|
|
}
|
|
|
|
eventPublisher.EXPECT().PublishEvent(gomock.Any(), gomock.Eq(events.UserAddressCreated{
|
|
UserID: TestUserID,
|
|
AddressID: newAddress.ID,
|
|
Email: newAddress.Email,
|
|
})).Times(1)
|
|
|
|
err := service.HandleAddressEvents(context.Background(), []proton.AddressEvent{
|
|
{
|
|
EventItem: proton.EventItem{
|
|
ID: "",
|
|
Action: proton.EventUpdate,
|
|
},
|
|
Address: newAddress,
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
require.Contains(t, service.identity.Addresses, newAddress.ID)
|
|
}
|
|
|
|
func TestService_OnAddressDeleted(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
|
|
service, eventPublisher, _ := newTestService(t, mockCtrl)
|
|
|
|
address := proton.Address{
|
|
ID: "Address1",
|
|
Email: "foo@bar.com",
|
|
Status: proton.AddressStatusEnabled,
|
|
}
|
|
|
|
eventPublisher.EXPECT().PublishEvent(gomock.Any(), gomock.Eq(events.UserAddressDeleted{
|
|
UserID: TestUserID,
|
|
AddressID: address.ID,
|
|
Email: address.Email,
|
|
})).Times(1)
|
|
|
|
err := service.HandleAddressEvents(context.Background(), []proton.AddressEvent{
|
|
{
|
|
EventItem: proton.EventItem{
|
|
ID: address.ID,
|
|
Action: proton.EventDelete,
|
|
},
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
require.NotContains(t, service.identity.Addresses, address.ID)
|
|
}
|
|
|
|
func TestService_OnAddressDeleteDisabledDoesNotProduceEvent(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
|
|
service, _, _ := newTestService(t, mockCtrl)
|
|
|
|
address := proton.Address{
|
|
ID: "Address2",
|
|
Email: "foo2@bar.com",
|
|
Status: proton.AddressStatusDisabled,
|
|
}
|
|
|
|
err := service.HandleAddressEvents(context.Background(), []proton.AddressEvent{
|
|
{
|
|
EventItem: proton.EventItem{
|
|
ID: address.ID,
|
|
Action: proton.EventDelete,
|
|
},
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
require.NotContains(t, service.identity.Addresses, address.ID)
|
|
}
|
|
|
|
func TestService_OnAddressDeletedUnknownDoesNotProduceEvent(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
|
|
service, _, _ := newTestService(t, mockCtrl)
|
|
|
|
address := proton.Address{
|
|
ID: "UnknownID",
|
|
Email: "new@bar.com",
|
|
Status: proton.AddressStatusEnabled,
|
|
}
|
|
|
|
err := service.HandleAddressEvents(context.Background(), []proton.AddressEvent{
|
|
{
|
|
EventItem: proton.EventItem{
|
|
ID: address.ID,
|
|
Action: proton.EventDelete,
|
|
},
|
|
Address: address,
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func newTestService(_ *testing.T, mockCtrl *gomock.Controller) (*Service, *mocks2.MockEventPublisher, *mocks.MockIdentityProvider) {
|
|
subscribable := &userevents.NoOpSubscribable{}
|
|
eventPublisher := mocks2.NewMockEventPublisher(mockCtrl)
|
|
provider := mocks.NewMockIdentityProvider(mockCtrl)
|
|
user := newTestUser()
|
|
telemetry := mocks.NewMockTelemetry(mockCtrl)
|
|
bridgePassProvider := NewFixedBridgePassProvider([]byte("hello"))
|
|
|
|
service := NewService(subscribable, eventPublisher, NewState(*user, newTestAddresses(), provider), bridgePassProvider, telemetry)
|
|
return service, eventPublisher, provider
|
|
}
|
|
|
|
func newTestUser() *proton.User {
|
|
return &proton.User{
|
|
ID: TestUserID,
|
|
Name: "Foo",
|
|
DisplayName: "Foo",
|
|
Email: "foo@bar",
|
|
Keys: nil,
|
|
UsedSpace: 0,
|
|
MaxSpace: 0,
|
|
MaxUpload: 0,
|
|
Credit: 0,
|
|
Currency: "",
|
|
}
|
|
}
|
|
|
|
func newTestUserRefreshed() *proton.User {
|
|
return &proton.User{
|
|
ID: TestUserID,
|
|
Name: "Alternate",
|
|
DisplayName: "Universe",
|
|
Email: "foo2@bar",
|
|
Keys: nil,
|
|
UsedSpace: 0,
|
|
MaxSpace: 0,
|
|
MaxUpload: 0,
|
|
Credit: 0,
|
|
Currency: "USD",
|
|
}
|
|
}
|
|
|
|
func newTestAddresses() []proton.Address {
|
|
return []proton.Address{
|
|
{
|
|
ID: "Address1",
|
|
Email: "foo@bar.com",
|
|
Status: proton.AddressStatusEnabled,
|
|
Type: 0,
|
|
Order: 0,
|
|
DisplayName: "",
|
|
Keys: nil,
|
|
},
|
|
{
|
|
ID: "Address2",
|
|
Email: "foo2@bar.com",
|
|
Status: proton.AddressStatusDisabled,
|
|
Type: 0,
|
|
Order: 1,
|
|
DisplayName: "",
|
|
Keys: nil,
|
|
},
|
|
}
|
|
}
|
|
|
|
func newTestAddressesRefreshed() []proton.Address {
|
|
return []proton.Address{
|
|
{
|
|
ID: "Address1",
|
|
Email: "foo@bar.com",
|
|
Status: proton.AddressStatusEnabled,
|
|
Type: 0,
|
|
Order: 2,
|
|
DisplayName: "FOo barish",
|
|
Keys: nil,
|
|
},
|
|
{
|
|
ID: "Address2",
|
|
Email: "foo2@bar.com",
|
|
Status: proton.AddressStatusDisabled,
|
|
Type: 0,
|
|
Order: 4,
|
|
DisplayName: "New display name",
|
|
Keys: nil,
|
|
},
|
|
}
|
|
}
|