// Copyright (c) 2020 Proton Technologies AG // // This file is part of ProtonMail Bridge. // // ProtonMail 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. // // ProtonMail 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 ProtonMail Bridge. If not, see . package store import ( "net/mail" "testing" "time" "github.com/ProtonMail/proton-bridge/pkg/pmapi" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) func TestEventLoopProcessMoreEvents(t *testing.T) { m, clear := initMocks(t) defer clear() // Event expectations need to be defined before calling `newStoreNoEvents` // to force to use these for this particular test. // Also, event loop calls ListMessages again and we need to place it after // calling `newStoreNoEvents` to not break expectations for the first sync. gomock.InOrder( // Doesn't matter which IDs are used. // This test is trying to see whether event loop will immediately process // next event if there is `More` of them. m.api.EXPECT().GetEvent("latestEventID").Return(&pmapi.Event{ EventID: "event50", More: 1, }, nil), m.api.EXPECT().GetEvent("event50").Return(&pmapi.Event{ EventID: "event70", More: 0, }, nil), m.api.EXPECT().GetEvent("event70").Return(&pmapi.Event{ EventID: "event71", More: 0, }, nil), ) m.newStoreNoEvents(true) m.api.EXPECT().ListMessages(gomock.Any()).Return([]*pmapi.Message{}, 0, nil).AnyTimes() // Event loop runs in goroutine and will be stopped by deferred mock clearing. go m.store.eventLoop.start() // More events are processed right away. require.Eventually(t, func() bool { return m.store.eventLoop.currentEventID == "event70" }, time.Second, 10*time.Millisecond) // For normal event we need to wait to next polling. time.Sleep(pollInterval) require.Eventually(t, func() bool { return m.store.eventLoop.currentEventID == "event71" }, time.Second, 10*time.Millisecond) } func TestEventLoopUpdateMessageFromLoop(t *testing.T) { m, clear := initMocks(t) defer clear() subject := "old subject" newSubject := "new subject" // First sync will add message with old subject to database. m.api.EXPECT().GetMessage("msg1").Return(&pmapi.Message{ ID: "msg1", Subject: subject, }, nil) // Event will update the subject. m.api.EXPECT().GetEvent("latestEventID").Return(&pmapi.Event{ EventID: "event1", Messages: []*pmapi.EventMessage{{ EventItem: pmapi.EventItem{ ID: "msg1", Action: pmapi.EventUpdate, }, Updated: &pmapi.EventMessageUpdated{ ID: "msg1", Subject: &newSubject, }, }}, }, nil) m.newStoreNoEvents(true) // Event loop runs in goroutine and will be stopped by deferred mock clearing. go m.store.eventLoop.start() require.Eventually(t, func() bool { msg, err := m.store.getMessageFromDB("msg1") return err == nil && msg.Subject == newSubject }, time.Second, 10*time.Millisecond) } func TestEventLoopUpdateMessage(t *testing.T) { address1 := &mail.Address{Address: "user1@example.com"} address2 := &mail.Address{Address: "user2@example.com"} msg := &pmapi.Message{ ID: "msg1", Subject: "old", Unread: 0, Flags: 10, Sender: address1, ToList: []*mail.Address{address2}, CCList: []*mail.Address{address1}, BCCList: []*mail.Address{}, Time: 20, LabelIDs: []string{"old"}, } newMsg := &pmapi.Message{ ID: "msg1", Subject: "new", Unread: 1, Flags: 11, Sender: address2, ToList: []*mail.Address{address1}, CCList: []*mail.Address{address2}, BCCList: []*mail.Address{address1}, Time: 21, LabelIDs: []string{"new"}, } updateMessage(log, msg, &pmapi.EventMessageUpdated{ ID: "msg1", Subject: &newMsg.Subject, Unread: &newMsg.Unread, Flags: &newMsg.Flags, Sender: newMsg.Sender, ToList: &newMsg.ToList, CCList: &newMsg.CCList, BCCList: &newMsg.BCCList, Time: newMsg.Time, LabelIDs: newMsg.LabelIDs, }) require.Equal(t, newMsg, msg) }