feat(GODT-2552): Add unit test.

This commit is contained in:
Romain LE JEUNE
2023-04-18 18:59:14 +02:00
committed by Romain Le Jeune
parent b250d49af8
commit 67b5e7f96a
5 changed files with 196 additions and 6 deletions

View File

@ -256,6 +256,7 @@ mocks:
mockgen --package mocks github.com/ProtonMail/gluon/async PanicHandler > internal/bridge/mocks/async_mocks.go
mockgen --package mocks github.com/ProtonMail/gluon/reporter Reporter > internal/bridge/mocks/gluon_mocks.go
mockgen --package mocks github.com/ProtonMail/proton-bridge/v3/internal/updater Downloader,Installer > internal/updater/mocks/mocks.go
mockgen --package mocks github.com/ProtonMail/proton-bridge/v3/internal/telemetry HeartbeatManager > internal/telemetry/mocks/mocks.go
lint: gofiles lint-golang lint-license lint-dependencies lint-changelog

View File

@ -29,7 +29,7 @@ func NewHeartbeat(manager HeartbeatManager, imapPort, smtpPort int, cacheDir, ke
log: logrus.WithField("pkg", "telemetry"),
manager: manager,
metrics: HeartbeatData{
MeasurementGroup: "bridge.amy.usage",
MeasurementGroup: "bridge.any.usage",
Event: "bridge_heartbeat",
},
defaultIMAPPort: imapPort,
@ -41,7 +41,7 @@ func NewHeartbeat(manager HeartbeatManager, imapPort, smtpPort int, cacheDir, ke
}
func (heartbeat *Heartbeat) SetRollout(val float64) {
heartbeat.metrics.Values.Rollout = int(val * 100)
heartbeat.metrics.Dimensions.Rollout = int(val * 100)
}
func (heartbeat *Heartbeat) SetNbAccount(val int) {
@ -129,7 +129,7 @@ func (heartbeat *Heartbeat) SetSMTPPort(val int) {
}
func (heartbeat *Heartbeat) SetCacheLocation(val string) {
if val != heartbeat.defaultCache {
if val == heartbeat.defaultCache {
heartbeat.metrics.Dimensions.CacheLocation = dimensionDefault
} else {
heartbeat.metrics.Dimensions.CacheLocation = dimensionCustom
@ -137,7 +137,7 @@ func (heartbeat *Heartbeat) SetCacheLocation(val string) {
}
func (heartbeat *Heartbeat) SetKeyChainPref(val string) {
if val != heartbeat.defaultKeychain {
if val == heartbeat.defaultKeychain {
heartbeat.metrics.Dimensions.KeychainPref = dimensionDefault
} else {
heartbeat.metrics.Dimensions.KeychainPref = dimensionCustom
@ -152,7 +152,7 @@ func (heartbeat *Heartbeat) StartSending() {
if heartbeat.manager.IsTelemetryAvailable() {
lastSent := heartbeat.manager.GetLastHeartbeatSent()
now := time.Now()
if now.Year() >= lastSent.Year() && now.YearDay() > lastSent.YearDay() {
if now.Year() > lastSent.Year() || (now.Year() == lastSent.Year() && now.YearDay() > lastSent.YearDay()) {
if !heartbeat.manager.SendHeartbeat(&heartbeat.metrics) {
heartbeat.log.WithFields(logrus.Fields{
"metrics": heartbeat.metrics,

View File

@ -0,0 +1,97 @@
// 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 telemetry_test
import (
"testing"
"time"
"github.com/ProtonMail/proton-bridge/v3/internal/telemetry"
"github.com/ProtonMail/proton-bridge/v3/internal/telemetry/mocks"
"github.com/golang/mock/gomock"
)
func TestHeartbeat_default_heartbeat(t *testing.T) {
withHeartbeat(t, 1143, 1025, "/tmp", "defaultKeychain", func(hb *telemetry.Heartbeat, mock *mocks.MockHeartbeatManager) {
data := telemetry.HeartbeatData{
MeasurementGroup: "bridge.any.usage",
Event: "bridge_heartbeat",
Values: telemetry.HeartbeatValues{
NbAccount: 1,
},
Dimensions: telemetry.HeartbeatDimensions{
AutoUpdate: "on",
AutoStart: "on",
Beta: "off",
Doh: "off",
SplitMode: "off",
ShowAllMail: "off",
IMAPConnectionMode: "ssl",
SMTPConnectionMode: "ssl",
IMAPPort: "default",
SMTPPort: "default",
CacheLocation: "default",
KeychainPref: "default",
PrevVersion: "1.2.3",
Rollout: 10,
},
}
mock.EXPECT().IsTelemetryAvailable().Return(true)
mock.EXPECT().GetLastHeartbeatSent().Return(time.Date(2022, 6, 4, 0, 0, 0, 0, time.UTC))
mock.EXPECT().SendHeartbeat(&data).Return(true)
mock.EXPECT().SetLastHeartbeatSent(gomock.Any()).Return(nil)
hb.StartSending()
})
}
func TestHeartbeat_already_sent_heartbeat(t *testing.T) {
withHeartbeat(t, 1143, 1025, "/tmp", "defaultKeychain", func(hb *telemetry.Heartbeat, mock *mocks.MockHeartbeatManager) {
mock.EXPECT().IsTelemetryAvailable().Return(true)
mock.EXPECT().GetLastHeartbeatSent().Return(time.Now().Truncate(24 * time.Hour))
hb.StartSending()
})
}
func withHeartbeat(t *testing.T, imap, smtp int, cache, keychain string, tests func(hb *telemetry.Heartbeat, mock *mocks.MockHeartbeatManager)) {
ctl := gomock.NewController(t)
defer ctl.Finish()
manager := mocks.NewMockHeartbeatManager(ctl)
heartbeat := telemetry.NewHeartbeat(manager, imap, smtp, cache, keychain)
heartbeat.SetRollout(0.1)
heartbeat.SetNbAccount(1)
heartbeat.SetSplitMode(false)
heartbeat.SetAutoStart(true)
heartbeat.SetAutoUpdate(true)
heartbeat.SetBeta("stable")
heartbeat.SetDoh(false)
heartbeat.SetShowAllMail(false)
heartbeat.SetIMAPConnectionMode(true)
heartbeat.SetSMTPConnectionMode(true)
heartbeat.SetIMAPPort(1143)
heartbeat.SetSMTPPort(1025)
heartbeat.SetCacheLocation("/tmp")
heartbeat.SetKeyChainPref("defaultKeychain")
heartbeat.SetPrevVersion("1.2.3")
tests(&heartbeat, manager)
}

View File

@ -0,0 +1,92 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/ProtonMail/proton-bridge/v3/internal/telemetry (interfaces: HeartbeatManager)
// Package mocks is a generated GoMock package.
package mocks
import (
reflect "reflect"
time "time"
telemetry "github.com/ProtonMail/proton-bridge/v3/internal/telemetry"
gomock "github.com/golang/mock/gomock"
)
// MockHeartbeatManager is a mock of HeartbeatManager interface.
type MockHeartbeatManager struct {
ctrl *gomock.Controller
recorder *MockHeartbeatManagerMockRecorder
}
// MockHeartbeatManagerMockRecorder is the mock recorder for MockHeartbeatManager.
type MockHeartbeatManagerMockRecorder struct {
mock *MockHeartbeatManager
}
// NewMockHeartbeatManager creates a new mock instance.
func NewMockHeartbeatManager(ctrl *gomock.Controller) *MockHeartbeatManager {
mock := &MockHeartbeatManager{ctrl: ctrl}
mock.recorder = &MockHeartbeatManagerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockHeartbeatManager) EXPECT() *MockHeartbeatManagerMockRecorder {
return m.recorder
}
// GetLastHeartbeatSent mocks base method.
func (m *MockHeartbeatManager) GetLastHeartbeatSent() time.Time {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetLastHeartbeatSent")
ret0, _ := ret[0].(time.Time)
return ret0
}
// GetLastHeartbeatSent indicates an expected call of GetLastHeartbeatSent.
func (mr *MockHeartbeatManagerMockRecorder) GetLastHeartbeatSent() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastHeartbeatSent", reflect.TypeOf((*MockHeartbeatManager)(nil).GetLastHeartbeatSent))
}
// IsTelemetryAvailable mocks base method.
func (m *MockHeartbeatManager) IsTelemetryAvailable() bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IsTelemetryAvailable")
ret0, _ := ret[0].(bool)
return ret0
}
// IsTelemetryAvailable indicates an expected call of IsTelemetryAvailable.
func (mr *MockHeartbeatManagerMockRecorder) IsTelemetryAvailable() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsTelemetryAvailable", reflect.TypeOf((*MockHeartbeatManager)(nil).IsTelemetryAvailable))
}
// SendHeartbeat mocks base method.
func (m *MockHeartbeatManager) SendHeartbeat(arg0 *telemetry.HeartbeatData) bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SendHeartbeat", arg0)
ret0, _ := ret[0].(bool)
return ret0
}
// SendHeartbeat indicates an expected call of SendHeartbeat.
func (mr *MockHeartbeatManagerMockRecorder) SendHeartbeat(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendHeartbeat", reflect.TypeOf((*MockHeartbeatManager)(nil).SendHeartbeat), arg0)
}
// SetLastHeartbeatSent mocks base method.
func (m *MockHeartbeatManager) SetLastHeartbeatSent(arg0 time.Time) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetLastHeartbeatSent", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// SetLastHeartbeatSent indicates an expected call of SetLastHeartbeatSent.
func (mr *MockHeartbeatManagerMockRecorder) SetLastHeartbeatSent(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastHeartbeatSent", reflect.TypeOf((*MockHeartbeatManager)(nil).SetLastHeartbeatSent), arg0)
}

View File

@ -40,7 +40,6 @@ type HeartbeatManager interface {
}
type HeartbeatValues struct {
Rollout int `json:"rollout"`
NbAccount int `json:"nb_account"`
}
@ -58,6 +57,7 @@ type HeartbeatDimensions struct {
CacheLocation string `json:"cache_location"`
KeychainPref string `json:"keychain_pref"`
PrevVersion string `json:"prev_version"`
Rollout int `json:"rollout"`
}
type HeartbeatData struct {