test: add test with changing address order

This commit is contained in:
James Houlahan
2020-05-06 09:57:34 +02:00
parent c61e8bdc71
commit 2d200f6f8c
19 changed files with 202 additions and 23 deletions

2
go.mod
View File

@ -8,6 +8,7 @@ require (
github.com/docker/docker-credential-helpers v0.0.0-00010101000000-000000000000 github.com/docker/docker-credential-helpers v0.0.0-00010101000000-000000000000
github.com/emersion/go-smtp v0.0.0-20180712174835-db5eec195e67 github.com/emersion/go-smtp v0.0.0-20180712174835-db5eec195e67
github.com/jameskeane/bcrypt v0.0.0-20170924085257-7509ea014998 github.com/jameskeane/bcrypt v0.0.0-20170924085257-7509ea014998
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
) )
require ( require (
@ -61,7 +62,6 @@ require (
github.com/twinj/uuid v1.0.0 // indirect github.com/twinj/uuid v1.0.0 // indirect
github.com/urfave/cli v1.22.3 github.com/urfave/cli v1.22.3
go.etcd.io/bbolt v1.3.3 go.etcd.io/bbolt v1.3.3
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/net v0.0.0-20200301022130-244492dfa37a golang.org/x/net v0.0.0-20200301022130-244492dfa37a
golang.org/x/text v0.3.2 golang.org/x/text v0.3.2
gopkg.in/stretchr/testify.v1 v1.2.2 // indirect gopkg.in/stretchr/testify.v1 v1.2.2 // indirect

13
go.sum
View File

@ -7,16 +7,12 @@ github.com/ProtonMail/crypto v0.0.0-20190604143603-d3d8a14a4d4f h1:cFhATQTJGK2iZ
github.com/ProtonMail/crypto v0.0.0-20190604143603-d3d8a14a4d4f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= github.com/ProtonMail/crypto v0.0.0-20190604143603-d3d8a14a4d4f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
github.com/ProtonMail/docker-credential-helpers v1.0.0 h1:0DQXbZNvUszWgXUuP7TzvQdwnkK1D5Zf/glBgCFJFCk= github.com/ProtonMail/docker-credential-helpers v1.0.0 h1:0DQXbZNvUszWgXUuP7TzvQdwnkK1D5Zf/glBgCFJFCk=
github.com/ProtonMail/docker-credential-helpers v1.0.0/go.mod h1:R1gQindzdYFcWJuuGXteYHDJzUCVtyU+EpEqp9aWcFs= github.com/ProtonMail/docker-credential-helpers v1.0.0/go.mod h1:R1gQindzdYFcWJuuGXteYHDJzUCVtyU+EpEqp9aWcFs=
github.com/ProtonMail/go-appdir v1.0.0 h1:PZXQ0HkveuEugga3LeDycxWtybrXQfKR0ThxURd6ojw=
github.com/ProtonMail/go-appdir v1.0.0/go.mod h1:3d8Y9F5mbEUjrYbcJ3rcDxcWbqbttF+011nVZmdRdzc=
github.com/ProtonMail/go-appdir v1.1.0 h1:9hdNDlU9kTqRKVNzmoqah8qqrj5QZyLByQdwQNlFWig= github.com/ProtonMail/go-appdir v1.1.0 h1:9hdNDlU9kTqRKVNzmoqah8qqrj5QZyLByQdwQNlFWig=
github.com/ProtonMail/go-appdir v1.1.0/go.mod h1:3d8Y9F5mbEUjrYbcJ3rcDxcWbqbttF+011nVZmdRdzc= github.com/ProtonMail/go-appdir v1.1.0/go.mod h1:3d8Y9F5mbEUjrYbcJ3rcDxcWbqbttF+011nVZmdRdzc=
github.com/ProtonMail/go-apple-mobileconfig v0.0.0-20160701194735-7ea9927a11f6 h1:YsSJ/mvZFYydQm/hRrt8R8UtgETixN2y3LK98f5LT60= github.com/ProtonMail/go-apple-mobileconfig v0.0.0-20160701194735-7ea9927a11f6 h1:YsSJ/mvZFYydQm/hRrt8R8UtgETixN2y3LK98f5LT60=
github.com/ProtonMail/go-apple-mobileconfig v0.0.0-20160701194735-7ea9927a11f6/go.mod h1:EtDfBMIDWmVe4viZCuBTEfe3OIIo0ghbpOaAZVO+hVg= github.com/ProtonMail/go-apple-mobileconfig v0.0.0-20160701194735-7ea9927a11f6/go.mod h1:EtDfBMIDWmVe4viZCuBTEfe3OIIo0ghbpOaAZVO+hVg=
github.com/ProtonMail/go-autostart v0.0.0-20181114175602-c5272053443a h1:fXK2KsfnkBV9Nh+9SKzHchYjuE9s0vI20JG1mbtEAcc= github.com/ProtonMail/go-autostart v0.0.0-20181114175602-c5272053443a h1:fXK2KsfnkBV9Nh+9SKzHchYjuE9s0vI20JG1mbtEAcc=
github.com/ProtonMail/go-autostart v0.0.0-20181114175602-c5272053443a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-autostart v0.0.0-20181114175602-c5272053443a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4=
github.com/ProtonMail/go-imap v0.0.0-20190327080220-0e686f0e855f h1:QkLm4yfhBQuBxrC46Vhy2sonOWVrwIJo5bgKpA82+TY=
github.com/ProtonMail/go-imap v0.0.0-20190327080220-0e686f0e855f/go.mod h1:+m2uLXghuYktgE/vc5AkmCxx1qhu33ZKHFWg1cGZPD0=
github.com/ProtonMail/go-imap-id v0.0.0-20190926060100-f94a56b9ecde h1:5koQozTDELymYOyFbQ/VSubexAEXzDR8qGM5mO8GRdw= github.com/ProtonMail/go-imap-id v0.0.0-20190926060100-f94a56b9ecde h1:5koQozTDELymYOyFbQ/VSubexAEXzDR8qGM5mO8GRdw=
github.com/ProtonMail/go-imap-id v0.0.0-20190926060100-f94a56b9ecde/go.mod h1:795VPXcRUIQ9JyMNHP4el582VokQfippgjkQP3Gk0r0= github.com/ProtonMail/go-imap-id v0.0.0-20190926060100-f94a56b9ecde/go.mod h1:795VPXcRUIQ9JyMNHP4el582VokQfippgjkQP3Gk0r0=
github.com/ProtonMail/go-mime v0.0.0-20190521135552-09454e3dbe72 h1:hGCc4Oc2fD3I5mNnZ1VlREncVc9EXJF8dxW3sw16gWM= github.com/ProtonMail/go-mime v0.0.0-20190521135552-09454e3dbe72 h1:hGCc4Oc2fD3I5mNnZ1VlREncVc9EXJF8dxW3sw16gWM=
@ -52,17 +48,14 @@ github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3E
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emersion/go-imap v0.0.0-20171113213225-939ec3994dbe h1:iAEcORtl7uQrqv7iRXGUqLqfXDcTGtXnvow31KkCmm8=
github.com/emersion/go-imap v0.0.0-20171113213225-939ec3994dbe/go.mod h1:oydmHwiyv92ZOiNfQY9BDax5heePWN8P2+W1B2T6qjc=
github.com/emersion/go-imap v0.0.0-20200415151653-89df427d2794 h1:tlFeCqKFZOhJaxW6ttvR6HWkYmQj4i+UR8cCzsx/Gis= github.com/emersion/go-imap v0.0.0-20200415151653-89df427d2794 h1:tlFeCqKFZOhJaxW6ttvR6HWkYmQj4i+UR8cCzsx/Gis=
github.com/emersion/go-imap v0.0.0-20200415151653-89df427d2794/go.mod h1:yKASt+C3ZiDAiCSssxg9caIckWF/JG7ZQTO7GAmvicU= github.com/emersion/go-imap v0.0.0-20200415151653-89df427d2794/go.mod h1:yKASt+C3ZiDAiCSssxg9caIckWF/JG7ZQTO7GAmvicU=
github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a h1:bMdSPm6sssuOFpIaveu3XGAijMS3Tq2S3EqFZmZxidc= github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a h1:bMdSPm6sssuOFpIaveu3XGAijMS3Tq2S3EqFZmZxidc=
github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a/go.mod h1:ikgISoP7pRAolqsVP64yMteJa2FIpS6ju88eBT6K1yQ= github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a/go.mod h1:ikgISoP7pRAolqsVP64yMteJa2FIpS6ju88eBT6K1yQ=
github.com/emersion/go-imap-idle v0.0.0-20190519112320-2704abd7050e h1:L7bswVJZcf2YHofgom49oFRwVqmBj/qZqDy9/SJpZMY= github.com/emersion/go-imap-idle v0.0.0-20190519112320-2704abd7050e h1:L7bswVJZcf2YHofgom49oFRwVqmBj/qZqDy9/SJpZMY=
github.com/emersion/go-imap-idle v0.0.0-20190519112320-2704abd7050e/go.mod h1:o14zPKCmEH5WC1vU5SdPoZGgNvQx7zzKSnxPQlobo78= github.com/emersion/go-imap-idle v0.0.0-20190519112320-2704abd7050e/go.mod h1:o14zPKCmEH5WC1vU5SdPoZGgNvQx7zzKSnxPQlobo78=
github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342 h1:5p1t3e1PomYgLWwEwhwEU5kVBwcyAcVrOpexv8AeZx0=
github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342/go.mod h1:QuMaZcKFDVI0yCrnAbPLfbwllz1wtOrZH8/vZ5yzp4w= github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342/go.mod h1:QuMaZcKFDVI0yCrnAbPLfbwllz1wtOrZH8/vZ5yzp4w=
github.com/emersion/go-imap-quota v0.0.0-20171113212021-e883a2bc54d6 h1:CQ9z5Gk5HBUI8+kM5XNZXUoAv8RF1GnXmYrN4OkDvZU=
github.com/emersion/go-imap-quota v0.0.0-20171113212021-e883a2bc54d6/go.mod h1:iApyhIQBiU4XFyr+3kdJyyGqle82TbQyuP2o+OZHrV0=
github.com/emersion/go-imap-quota v0.0.0-20200423100218-dcfd1b7d2b41 h1:z5lDGnSURauBEDdNLj3o0+HogVYKQCGeY3Anl/xyRfU= github.com/emersion/go-imap-quota v0.0.0-20200423100218-dcfd1b7d2b41 h1:z5lDGnSURauBEDdNLj3o0+HogVYKQCGeY3Anl/xyRfU=
github.com/emersion/go-imap-quota v0.0.0-20200423100218-dcfd1b7d2b41/go.mod h1:iApyhIQBiU4XFyr+3kdJyyGqle82TbQyuP2o+OZHrV0= github.com/emersion/go-imap-quota v0.0.0-20200423100218-dcfd1b7d2b41/go.mod h1:iApyhIQBiU4XFyr+3kdJyyGqle82TbQyuP2o+OZHrV0=
github.com/emersion/go-imap-specialuse v0.0.0-20161227184202-ba031ced6a62 h1:4ZAfwfc8aDlj26kkEap1UDSwwDnJp9Ie8Uj1MSXAkPk= github.com/emersion/go-imap-specialuse v0.0.0-20161227184202-ba031ced6a62 h1:4ZAfwfc8aDlj26kkEap1UDSwwDnJp9Ie8Uj1MSXAkPk=
@ -159,10 +152,6 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/therecipe/qt v0.0.0-20200126204426-5074eb6d8c41 h1:yBVcrpbaQYJBdKT2pxTdlL4hBE/eM4UPcyj9YpyvSok= github.com/therecipe/qt v0.0.0-20200126204426-5074eb6d8c41 h1:yBVcrpbaQYJBdKT2pxTdlL4hBE/eM4UPcyj9YpyvSok=
github.com/therecipe/qt v0.0.0-20200126204426-5074eb6d8c41/go.mod h1:SUUR2j3aE1z6/g76SdD6NwACEpvCxb3fvG82eKbD6us= github.com/therecipe/qt v0.0.0-20200126204426-5074eb6d8c41/go.mod h1:SUUR2j3aE1z6/g76SdD6NwACEpvCxb3fvG82eKbD6us=
github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200126204426-5074eb6d8c41 h1:My9HYsfDI/fJPZGyilw6066buBiZ7pgKRRgAyvKK5lA=
github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200126204426-5074eb6d8c41/go.mod h1:7m8PDYDEtEVqfjoUQc2UrFqhG0CDmoVJjRlQxexndFc=
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200126204426-5074eb6d8c41 h1:jTzKrQ6EIPvKw1B9/wwoKJLrXF+ManMsXoUzufxAdsg=
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200126204426-5074eb6d8c41/go.mod h1:mH55Ek7AZcdns5KPp99O0bg+78el64YCYWHiQKrOdt4=
github.com/twinj/uuid v1.0.0 h1:fzz7COZnDrXGTAOHGuUGYd6sG+JMq+AoE7+Jlu0przk= github.com/twinj/uuid v1.0.0 h1:fzz7COZnDrXGTAOHGuUGYd6sG+JMq+AoE7+Jlu0przk=
github.com/twinj/uuid v1.0.0/go.mod h1:mMgcE1RHFUFqe5AfiwlINXisXfDGro23fWdPUfOMjRY= github.com/twinj/uuid v1.0.0/go.mod h1:mMgcE1RHFUFqe5AfiwlINXisXfDGro23fWdPUfOMjRY=
github.com/urfave/cli v1.22.3 h1:FpNT6zq26xNpHZy08emi755QwzLPs6Pukqjlc7RfOMU= github.com/urfave/cli v1.22.3 h1:FpNT6zq26xNpHZy08emi755QwzLPs6Pukqjlc7RfOMU=

View File

@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// Code generated by ./credits.sh at Fri Apr 24 08:21:38 CEST 2020. DO NOT EDIT. // Code generated by ./credits.sh at Wed May 6 07:17:01 CEST 2020. DO NOT EDIT.
package bridge package bridge

View File

@ -34,6 +34,7 @@ const pollIntervalSpread = 5 * time.Second
type eventLoop struct { type eventLoop struct {
cache *Cache cache *Cache
currentEventID string currentEventID string
currentEvent *pmapi.Event
pollCh chan chan struct{} pollCh chan chan struct{}
stopCh chan struct{} stopCh chan struct{}
notifyStopCh chan struct{} notifyStopCh chan struct{}
@ -136,13 +137,18 @@ func (loop *eventLoop) start() { // nolint[funlen]
loop.log.WithField("lastEventID", loop.currentEventID).Warn("Subscription stopped") loop.log.WithField("lastEventID", loop.currentEventID).Warn("Subscription stopped")
}() }()
t := time.NewTicker(pollInterval - pollIntervalSpread)
defer t.Stop()
loop.hasInternet = true loop.hasInternet = true
go loop.pollNow() go loop.pollNow()
loop.loop()
}
// loop is the main body of the event loop.
func (loop *eventLoop) loop() {
t := time.NewTicker(pollInterval - pollIntervalSpread)
defer t.Stop()
for { for {
var eventProcessedCh chan struct{} var eventProcessedCh chan struct{}
select { select {
@ -251,6 +257,8 @@ func (loop *eventLoop) processNextEvent() (more bool, err error) { // nolint[fun
return false, errors.Wrap(err, "failed to get event") return false, errors.Wrap(err, "failed to get event")
} }
loop.currentEvent = event
if event == nil { if event == nil {
return false, errors.New("received empty event") return false, errors.New("received empty event")
} }

View File

@ -46,6 +46,11 @@ func (store *Store) TestGetEventLoop() *eventLoop { //nolint[golint]
return store.eventLoop return store.eventLoop
} }
// TestGetLastEvent returns last event processed by the store's event loop.
func (store *Store) TestGetLastEvent() *pmapi.Event { //nolint[golint]
return store.eventLoop.currentEvent
}
// TestGetStoreFilePath returns the filepath of the store's database file. // TestGetStoreFilePath returns the filepath of the store's database file.
func (store *Store) TestGetStoreFilePath() string { func (store *Store) TestGetStoreFilePath() string {
return store.filePath return store.filePath

View File

@ -174,6 +174,29 @@ func (c *client) GetAddresses() (addresses AddressList, err error) {
return res.Addresses, res.Err() return res.Addresses, res.Err()
} }
func (c *client) ReorderAddresses(addressIDs []string) (err error) {
defer c.UpdateUser()
var reqBody struct {
AddressIDs []string
}
reqBody.AddressIDs = addressIDs
req, err := c.NewJSONRequest("PUT", "/addresses/order", reqBody)
if err != nil {
return
}
var addContactsRes AddContactsResponse
if err = c.DoJSON(req, &addContactsRes); err != nil {
return
}
return
}
// Addresses returns the addresses stored in the client object itself rather than fetching from the API.
func (c *client) Addresses() AddressList { func (c *client) Addresses() AddressList {
return c.addresses return c.addresses
} }

View File

@ -121,6 +121,7 @@ type Client interface {
GetAddresses() (addresses AddressList, err error) GetAddresses() (addresses AddressList, err error)
Addresses() AddressList Addresses() AddressList
ReorderAddresses(addressIDs []string) error
GetEvent(eventID string) (*Event, error) GetEvent(eventID string) (*Event, error)

View File

@ -146,6 +146,10 @@ func (a *TestAccount) AddressID() string {
return a.addressToBeUsed.ID return a.addressToBeUsed.ID
} }
func (a *TestAccount) GetAddressID(addressTestID string) string {
return a.addressesByBDDAddressID[addressTestID].ID
}
// EnsureAddressID accepts address (simply the address) or bddAddressID used // EnsureAddressID accepts address (simply the address) or bddAddressID used
// in tests (in format [bddAddressID]) and returns always the real address ID. // in tests (in format [bddAddressID]) and returns always the real address ID.
// If the address is not found, the ID of main address is returned. // If the address is not found, the ID of main address is returned.
@ -163,6 +167,10 @@ func (a *TestAccount) EnsureAddressID(addressOrAddressTestID string) string {
return a.AddressID() return a.AddressID()
} }
func (a *TestAccount) GetAddress(addressTestID string) string {
return a.addressesByBDDAddressID[addressTestID].Email
}
// EnsureAddress accepts address (simply the address) or bddAddressID used // EnsureAddress accepts address (simply the address) or bddAddressID used
// in tests (in format [bddAddressID]) and returns always the address. // in tests (in format [bddAddressID]) and returns always the address.
// If the address ID cannot be found, the original value is returned. // If the address ID cannot be found, the original value is returned.

View File

@ -55,7 +55,8 @@ func (a *TestAccounts) GetTestAccount(username string) *TestAccount {
return a.GetTestAccountWithAddress(username, "") return a.GetTestAccountWithAddress(username, "")
} }
func (a *TestAccounts) GetTestAccountWithAddress(username, addressID string) *TestAccount { // GetTestAccount returns the test account with the given username configured to use the given bddAddressID.
func (a *TestAccounts) GetTestAccountWithAddress(username, bddAddressID string) *TestAccount {
// Do lookup by full address and convert to name in tests. // Do lookup by full address and convert to name in tests.
// Used by getting real data to ensure correct address or address ID. // Used by getting real data to ensure correct address or address ID.
for key, user := range a.Users { for key, user := range a.Users {
@ -71,7 +72,7 @@ func (a *TestAccounts) GetTestAccountWithAddress(username, addressID string) *Te
return newTestAccount( return newTestAccount(
user, user,
a.Addresses[user.Name], a.Addresses[user.Name],
addressID, bddAddressID,
a.Passwords[user.Name], a.Passwords[user.Name],
a.MailboxPasswords[user.Name], a.MailboxPasswords[user.Name],
a.TwoFAs[user.Name], a.TwoFAs[user.Name],

View File

@ -35,6 +35,7 @@ func BridgeActionsFeatureContext(s *godog.Suite) {
s.Step(`^the internet connection is lost$`, theInternetConnectionIsLost) s.Step(`^the internet connection is lost$`, theInternetConnectionIsLost)
s.Step(`^the internet connection is restored$`, theInternetConnectionIsRestored) s.Step(`^the internet connection is restored$`, theInternetConnectionIsRestored)
s.Step(`^(\d+) seconds pass$`, secondsPass) s.Step(`^(\d+) seconds pass$`, secondsPass)
s.Step(`^"([^"]*)" swaps address "([^"]*)" with address "([^"]*)"$`, swapsAddressWithAddress)
} }
func bridgeStarts() error { func bridgeStarts() error {
@ -132,3 +133,32 @@ func secondsPass(seconds int) error {
time.Sleep(time.Duration(seconds) * time.Second) time.Sleep(time.Duration(seconds) * time.Second)
return nil return nil
} }
func swapsAddressWithAddress(bddUserID, bddAddressID1, bddAddressID2 string) error {
account := ctx.GetTestAccount(bddUserID)
if account == nil {
return godog.ErrPending
}
address1ID := account.GetAddressID(bddAddressID1)
address2ID := account.GetAddressID(bddAddressID2)
var address1Index, address2Index int
var addressIDs []string
for i, v := range *account.Addresses() {
if v.ID == address1ID {
address1Index = i
}
if v.ID == address2ID {
address2Index = i
}
addressIDs = append(addressIDs, v.ID)
}
addressIDs[address1Index], addressIDs[address2Index] = addressIDs[address2Index], addressIDs[address1Index]
ctx.ReorderAddresses(account.Username(), bddAddressID1, bddAddressID2)
ctx.GetPMAPIController().ReorderAddresses(account.User(), addressIDs)
return nil
}

View File

@ -36,8 +36,8 @@ func (ctx *TestContext) GetTestAccount(bddUserID string) *accounts.TestAccount {
return ctx.testAccounts.GetTestAccount(bddUserID) return ctx.testAccounts.GetTestAccount(bddUserID)
} }
func (ctx *TestContext) GetTestAccountWithAddress(bddUserID, addressID string) *accounts.TestAccount { func (ctx *TestContext) GetTestAccountWithAddress(bddUserID, bddAddressID string) *accounts.TestAccount {
return ctx.testAccounts.GetTestAccountWithAddress(bddUserID, addressID) return ctx.testAccounts.GetTestAccountWithAddress(bddUserID, bddAddressID)
} }
func (ctx *TestContext) EnsureAddressID(bddUserID, addressOrAddressTestID string) string { func (ctx *TestContext) EnsureAddressID(bddUserID, addressOrAddressTestID string) string {
@ -55,3 +55,9 @@ func (ctx *TestContext) EnsureAddress(bddUserID, addressOrAddressTestID string)
} }
return account.EnsureAddress(addressOrAddressTestID) return account.EnsureAddress(addressOrAddressTestID)
} }
func (ctx *TestContext) ReorderAddresses(userID, addressA, addressB string) {
addresses := ctx.testAccounts.Addresses[userID]
addresses[addressA], addresses[addressB] = addresses[addressB], addresses[addressA]
}

View File

@ -33,6 +33,7 @@ type PMAPIController interface {
GetLabelIDs(username string, labelNames []string) ([]string, error) GetLabelIDs(username string, labelNames []string) ([]string, error)
AddUserMessage(username string, message *pmapi.Message) error AddUserMessage(username string, message *pmapi.Message) error
GetMessageID(username, messageIndex string) string GetMessageID(username, messageIndex string) string
ReorderAddresses(user *pmapi.User, addressIDs []string) error
PrintCalls() PrintCalls()
WasCalled(method, path string, expectedRequest []byte) bool WasCalled(method, path string, expectedRequest []byte) bool
GetCalls(method, path string) [][]byte GetCalls(method, path string) [][]byte

View File

@ -18,6 +18,7 @@
package fakeapi package fakeapi
import ( import (
"errors"
"fmt" "fmt"
"strings" "strings"
@ -44,6 +45,15 @@ func (ctl *Controller) TurnInternetConnectionOn() {
ctl.noInternetConnection = false ctl.noInternetConnection = false
} }
func (ctl *Controller) ReorderAddresses(user *pmapi.User, addressIDs []string) error {
api := ctl.getFakeAPIForUser(user.ID)
if api == nil {
return errors.New("no such user")
}
return api.ReorderAddresses(addressIDs)
}
func (ctl *Controller) AddUser(user *pmapi.User, addresses *pmapi.AddressList, password string, twoFAEnabled bool) error { func (ctl *Controller) AddUser(user *pmapi.User, addresses *pmapi.AddressList, password string, twoFAEnabled bool) error {
ctl.usersByUsername[user.Name] = &fakeUser{ ctl.usersByUsername[user.Name] = &fakeUser{
user: user, user: user,
@ -131,6 +141,15 @@ func (ctl *Controller) AddUserMessage(username string, message *pmapi.Message) e
return nil return nil
} }
func (ctl *Controller) getFakeAPIForUser(userID string) *FakePMAPI {
for _, fakeAPI := range ctl.fakeAPIs {
if fakeAPI.userID == userID {
return fakeAPI
}
}
return nil
}
func (ctl *Controller) resetUsers() { func (ctl *Controller) resetUsers() {
for _, fakeAPI := range ctl.fakeAPIs { for _, fakeAPI := range ctl.fakeAPIs {
_ = fakeAPI.setUser(fakeAPI.username) _ = fakeAPI.setUser(fakeAPI.username)

View File

@ -40,20 +40,24 @@ func (api *FakePMAPI) GetEvent(eventID string) (*pmapi.Event, error) {
foundEvent = event foundEvent = event
continue continue
} }
if foundEvent != nil { if foundEvent != nil {
mergedEvent.EventID = event.EventID mergedEvent.EventID = event.EventID
mergedEvent.Refresh |= event.Refresh mergedEvent.Refresh |= event.Refresh
mergedEvent.Messages = append(mergedEvent.Messages, event.Messages...) mergedEvent.Messages = append(mergedEvent.Messages, event.Messages...)
mergedEvent.MessageCounts = append(mergedEvent.MessageCounts, event.MessageCounts...) mergedEvent.MessageCounts = append(mergedEvent.MessageCounts, event.MessageCounts...)
mergedEvent.Labels = append(mergedEvent.Labels, event.Labels...) mergedEvent.Labels = append(mergedEvent.Labels, event.Labels...)
mergedEvent.Addresses = append(mergedEvent.Addresses, event.Addresses...)
mergedEvent.Notices = append(mergedEvent.Notices, event.Notices...) mergedEvent.Notices = append(mergedEvent.Notices, event.Notices...)
mergedEvent.User = event.User mergedEvent.User = event.User
} }
} }
// If there isn't next event, return the same one. // If there isn't next event, return the same one.
if mergedEvent.EventID == "" { if mergedEvent.EventID == "" {
return foundEvent, nil return foundEvent, nil
} }
return mergedEvent, nil return mergedEvent, nil
} }
@ -103,6 +107,19 @@ func (api *FakePMAPI) addEventMessage(action pmapi.EventAction, message *pmapi.M
}) })
} }
func (api *FakePMAPI) addEventAddress(action pmapi.EventAction, address *pmapi.Address) {
api.addEvent(&pmapi.Event{
EventID: api.eventIDGenerator.next("event"),
Addresses: []*pmapi.EventAddress{{
EventItem: pmapi.EventItem{
ID: address.ID,
Action: pmapi.EventUpdate,
},
Address: address,
}},
})
}
func (api *FakePMAPI) addEvent(event *pmapi.Event) { func (api *FakePMAPI) addEvent(event *pmapi.Event) {
api.events = append(api.events, event) api.events = append(api.events, event)
} }

View File

@ -57,6 +57,29 @@ func (api *FakePMAPI) GetAddresses() (pmapi.AddressList, error) {
return *api.addresses, nil return *api.addresses, nil
} }
func (api *FakePMAPI) ReorderAddresses(addressIDs []string) error {
if err := api.checkAndRecordCall(PUT, "/addresses/order", nil); err != nil {
return err
}
for wantedIndex, addressID := range addressIDs {
var currentIndex int
for i, v := range *api.addresses {
if v.ID == addressID {
currentIndex = i
break
}
}
(*api.addresses)[wantedIndex], (*api.addresses)[currentIndex] = (*api.addresses)[currentIndex], (*api.addresses)[wantedIndex]
(*api.addresses)[wantedIndex].Order = wantedIndex + 1 // Starts counting from 1.
api.addEventAddress(pmapi.EventUpdate, (*api.addresses)[wantedIndex])
}
return nil
}
func (api *FakePMAPI) Addresses() pmapi.AddressList { func (api *FakePMAPI) Addresses() pmapi.AddressList {
return *api.addresses return *api.addresses
} }

View File

@ -44,3 +44,12 @@ Feature: Address mode
| from | to | subject | | from | to | subject |
| john.doe@mail.com | [primary] | foo | | john.doe@mail.com | [primary] | foo |
| jane.doe@mail.com | [secondary] | bar | | jane.doe@mail.com | [secondary] | bar |
Scenario: Make secondary address primary in combined mode
Given there is "userMoreAddresses" in "combined" address mode
When "userMoreAddresses" swaps address "primary" with address "secondary"
And "userMoreAddresses" receives an address event
Then mailbox "Folders/mbox" for address "primary" of "userMoreAddresses" has messages
| from | to | subject |
| john.doe@mail.com | [primary] | foo |
| jane.doe@mail.com | [secondary] | bar |

View File

@ -24,7 +24,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func cleanup(client pmapi.Client) error { func cleanup(client pmapi.Client, addresses *pmapi.AddressList) error {
if err := cleanSystemFolders(client); err != nil { if err := cleanSystemFolders(client); err != nil {
return errors.Wrap(err, "failed to clean system folders") return errors.Wrap(err, "failed to clean system folders")
} }
@ -34,6 +34,9 @@ func cleanup(client pmapi.Client) error {
if err := cleanTrash(client); err != nil { if err := cleanTrash(client); err != nil {
return errors.Wrap(err, "failed to clean trash") return errors.Wrap(err, "failed to clean trash")
} }
if err := reorderAddresses(client, addresses); err != nil {
return errors.Wrap(err, "failed to clean trash")
}
return nil return nil
} }
@ -130,3 +133,13 @@ func emptyFolder(client pmapi.Client, labelID string) error {
} }
return nil return nil
} }
func reorderAddresses(client pmapi.Client, addresses *pmapi.AddressList) error {
addressIDs := []string{}
for _, address := range *addresses {
addressIDs = append(addressIDs, address.ID)
}
return client.ReorderAddresses(addressIDs)
}

View File

@ -50,7 +50,7 @@ func (ctl *Controller) AddUser(user *pmapi.User, addresses *pmapi.AddressList, p
return errors.Wrap(err, "failed to unlock addresses") return errors.Wrap(err, "failed to unlock addresses")
} }
if err := cleanup(client); err != nil { if err := cleanup(client, addresses); err != nil {
return errors.Wrap(err, "failed to clean user") return errors.Wrap(err, "failed to clean user")
} }
@ -58,3 +58,9 @@ func (ctl *Controller) AddUser(user *pmapi.User, addresses *pmapi.AddressList, p
return nil return nil
} }
func (ctl *Controller) ReorderAddresses(user *pmapi.User, addressIDs []string) error {
client := ctl.clientManager.GetClient(user.ID)
return client.ReorderAddresses(addressIDs)
}

View File

@ -18,11 +18,15 @@
package tests package tests
import ( import (
"time"
"github.com/cucumber/godog" "github.com/cucumber/godog"
"github.com/stretchr/testify/assert"
) )
func StoreActionsFeatureContext(s *godog.Suite) { func StoreActionsFeatureContext(s *godog.Suite) {
s.Step(`^the event loop of "([^"]*)" loops once$`, theEventLoopLoops) s.Step(`^the event loop of "([^"]*)" loops once$`, theEventLoopLoops)
s.Step(`^"([^"]*)" receives an address event$`, receivesAnAddressEvent)
} }
func theEventLoopLoops(username string) error { func theEventLoopLoops(username string) error {
@ -37,3 +41,19 @@ func theEventLoopLoops(username string) error {
store.TestPollNow() store.TestPollNow()
return nil return nil
} }
func receivesAnAddressEvent(username string) error {
acc := ctx.GetTestAccount(username)
if acc == nil {
return godog.ErrPending
}
store, err := ctx.GetStore(acc.Username())
if err != nil {
return internalError(err, "getting store of user %s", username)
}
assert.Eventually(ctx.GetTestingT(), func() bool {
store.TestPollNow()
return len(store.TestGetLastEvent().Addresses) > 0
}, 5*time.Second, time.Second)
return nil
}