mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-10 04:36:43 +00:00
feat(BRIDGE-266): heartbeat telemetry update; extra integration tests;
This commit is contained in:
@ -19,9 +19,12 @@ package telemetry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/plan"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/updater"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@ -32,70 +35,66 @@ func NewHeartbeat(manager HeartbeatManager, imapPort, smtpPort int, cacheDir, ke
|
||||
manager: manager,
|
||||
metrics: HeartbeatData{
|
||||
MeasurementGroup: "bridge.any.usage",
|
||||
Event: "bridge_heartbeat",
|
||||
Event: "bridge_heartbeat_new",
|
||||
Dimensions: NewHeartbeatDimensions(),
|
||||
},
|
||||
defaultIMAPPort: imapPort,
|
||||
defaultSMTPPort: smtpPort,
|
||||
defaultCache: cacheDir,
|
||||
defaultKeychain: keychain,
|
||||
defaultUserPlan: plan.Unknown,
|
||||
}
|
||||
return heartbeat
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetRollout(val float64) {
|
||||
heartbeat.metrics.Dimensions.Rollout = strconv.Itoa(int(val * 100))
|
||||
heartbeat.metrics.Values.Rollout = int(math.Floor(val * 10))
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetNbAccount(val int) {
|
||||
heartbeat.metrics.Values.NbAccount = val
|
||||
func (heartbeat *Heartbeat) GetRollout() int {
|
||||
return heartbeat.metrics.Values.Rollout
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetNumberConnectedAccounts(val int) {
|
||||
heartbeat.metrics.Values.NumberConnectedAccounts = val
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetAutoUpdate(val bool) {
|
||||
if val {
|
||||
heartbeat.metrics.Dimensions.AutoUpdate = dimensionON
|
||||
} else {
|
||||
heartbeat.metrics.Dimensions.AutoUpdate = dimensionOFF
|
||||
}
|
||||
heartbeat.metrics.Dimensions.AutoUpdateEnabled = strconv.FormatBool(val)
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetAutoStart(val bool) {
|
||||
if val {
|
||||
heartbeat.metrics.Dimensions.AutoStart = dimensionON
|
||||
} else {
|
||||
heartbeat.metrics.Dimensions.AutoStart = dimensionOFF
|
||||
}
|
||||
heartbeat.metrics.Dimensions.AutoStartEnabled = strconv.FormatBool(val)
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetBeta(val updater.Channel) {
|
||||
if val == updater.EarlyChannel {
|
||||
heartbeat.metrics.Dimensions.Beta = dimensionON
|
||||
} else {
|
||||
heartbeat.metrics.Dimensions.Beta = dimensionOFF
|
||||
}
|
||||
heartbeat.metrics.Dimensions.BetaEnabled = strconv.FormatBool(val == updater.EarlyChannel)
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetDoh(val bool) {
|
||||
if val {
|
||||
heartbeat.metrics.Dimensions.Doh = dimensionON
|
||||
} else {
|
||||
heartbeat.metrics.Dimensions.Doh = dimensionOFF
|
||||
}
|
||||
heartbeat.metrics.Dimensions.DohEnabled = strconv.FormatBool(val)
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetSplitMode(val bool) {
|
||||
if val {
|
||||
heartbeat.metrics.Dimensions.SplitMode = dimensionON
|
||||
} else {
|
||||
heartbeat.metrics.Dimensions.SplitMode = dimensionOFF
|
||||
heartbeat.metrics.Dimensions.UseSplitMode = strconv.FormatBool(val)
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetUserPlan(val string) {
|
||||
mappedUserPlan := plan.MapUserPlan(val)
|
||||
if plan.IsHigherPriority(heartbeat.metrics.Dimensions.UserPlanGroup, mappedUserPlan) {
|
||||
heartbeat.metrics.Dimensions.UserPlanGroup = val
|
||||
}
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetContactedByAppleNotes(uaName string) {
|
||||
uaNameLowered := strings.ToLower(uaName)
|
||||
if strings.Contains(uaNameLowered, "mac") && strings.Contains(uaNameLowered, "notes") {
|
||||
heartbeat.metrics.Dimensions.ContactedByAppleNotes = strconv.FormatBool(true)
|
||||
}
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetShowAllMail(val bool) {
|
||||
if val {
|
||||
heartbeat.metrics.Dimensions.ShowAllMail = dimensionON
|
||||
} else {
|
||||
heartbeat.metrics.Dimensions.ShowAllMail = dimensionOFF
|
||||
}
|
||||
heartbeat.metrics.Dimensions.ShowAllMail = strconv.FormatBool(val)
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetIMAPConnectionMode(val bool) {
|
||||
@ -115,35 +114,19 @@ func (heartbeat *Heartbeat) SetSMTPConnectionMode(val bool) {
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetIMAPPort(val int) {
|
||||
if val == heartbeat.defaultIMAPPort {
|
||||
heartbeat.metrics.Dimensions.IMAPPort = dimensionDefault
|
||||
} else {
|
||||
heartbeat.metrics.Dimensions.IMAPPort = dimensionCustom
|
||||
}
|
||||
heartbeat.metrics.Dimensions.UseDefaultIMAPPort = strconv.FormatBool(val == heartbeat.defaultIMAPPort)
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetSMTPPort(val int) {
|
||||
if val == heartbeat.defaultSMTPPort {
|
||||
heartbeat.metrics.Dimensions.SMTPPort = dimensionDefault
|
||||
} else {
|
||||
heartbeat.metrics.Dimensions.SMTPPort = dimensionCustom
|
||||
}
|
||||
heartbeat.metrics.Dimensions.UseDefaultSMTPPort = strconv.FormatBool(val == heartbeat.defaultSMTPPort)
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetCacheLocation(val string) {
|
||||
if val == heartbeat.defaultCache {
|
||||
heartbeat.metrics.Dimensions.CacheLocation = dimensionDefault
|
||||
} else {
|
||||
heartbeat.metrics.Dimensions.CacheLocation = dimensionCustom
|
||||
}
|
||||
heartbeat.metrics.Dimensions.UseDefaultCacheLocation = strconv.FormatBool(val == heartbeat.defaultCache)
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetKeyChainPref(val string) {
|
||||
if val == heartbeat.defaultKeychain {
|
||||
heartbeat.metrics.Dimensions.KeychainPref = dimensionDefault
|
||||
} else {
|
||||
heartbeat.metrics.Dimensions.KeychainPref = dimensionCustom
|
||||
}
|
||||
heartbeat.metrics.Dimensions.UseDefaultKeychain = strconv.FormatBool(val == heartbeat.defaultKeychain)
|
||||
}
|
||||
|
||||
func (heartbeat *Heartbeat) SetPrevVersion(val string) {
|
||||
|
||||
@ -22,34 +22,38 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/plan"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/telemetry"
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/telemetry/mocks"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
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",
|
||||
Event: "bridge_heartbeat_new",
|
||||
Values: telemetry.HeartbeatValues{
|
||||
NbAccount: 1,
|
||||
NumberConnectedAccounts: 1,
|
||||
Rollout: 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",
|
||||
AutoUpdateEnabled: "true",
|
||||
AutoStartEnabled: "true",
|
||||
BetaEnabled: "false",
|
||||
DohEnabled: "false",
|
||||
UseSplitMode: "false",
|
||||
ShowAllMail: "false",
|
||||
UseDefaultIMAPPort: "true",
|
||||
UseDefaultSMTPPort: "true",
|
||||
UseDefaultCacheLocation: "true",
|
||||
UseDefaultKeychain: "true",
|
||||
ContactedByAppleNotes: "false",
|
||||
PrevVersion: "1.2.3",
|
||||
IMAPConnectionMode: "ssl",
|
||||
SMTPConnectionMode: "ssl",
|
||||
UserPlanGroup: plan.Unknown,
|
||||
},
|
||||
}
|
||||
|
||||
@ -81,7 +85,7 @@ func withHeartbeat(t *testing.T, imap, smtp int, cache, keychain string, tests f
|
||||
heartbeat := telemetry.NewHeartbeat(manager, imap, smtp, cache, keychain)
|
||||
|
||||
heartbeat.SetRollout(0.1)
|
||||
heartbeat.SetNbAccount(1)
|
||||
heartbeat.SetNumberConnectedAccounts(1)
|
||||
heartbeat.SetSplitMode(false)
|
||||
heartbeat.SetAutoStart(true)
|
||||
heartbeat.SetAutoUpdate(true)
|
||||
@ -98,3 +102,29 @@ func withHeartbeat(t *testing.T, imap, smtp int, cache, keychain string, tests f
|
||||
|
||||
tests(&heartbeat, manager)
|
||||
}
|
||||
|
||||
func Test_setRollout(t *testing.T) {
|
||||
hb := telemetry.Heartbeat{}
|
||||
type testStruct struct {
|
||||
val float64
|
||||
res int
|
||||
}
|
||||
|
||||
tests := []testStruct{
|
||||
{0.02, 0},
|
||||
{0.04, 0},
|
||||
{0.09999, 0},
|
||||
{0.1, 1},
|
||||
{0.132323, 1},
|
||||
{0.2, 2},
|
||||
{0.25, 2},
|
||||
{0.7111, 7},
|
||||
{0.93, 9},
|
||||
{0.999, 9},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
hb.SetRollout(test.val)
|
||||
require.Equal(t, test.res, hb.GetRollout())
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,14 +21,11 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/v3/internal/plan"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
dimensionON = "on"
|
||||
dimensionOFF = "off"
|
||||
dimensionDefault = "default"
|
||||
dimensionCustom = "custom"
|
||||
dimensionSSL = "ssl"
|
||||
dimensionStartTLS = "starttls"
|
||||
)
|
||||
@ -46,24 +43,29 @@ type HeartbeatManager interface {
|
||||
}
|
||||
|
||||
type HeartbeatValues struct {
|
||||
NbAccount int `json:"nb_account"`
|
||||
NumberConnectedAccounts int `json:"numberConnectedAccounts"`
|
||||
Rollout int `json:"rolloutPercentage"`
|
||||
}
|
||||
|
||||
type HeartbeatDimensions struct {
|
||||
AutoUpdate string `json:"auto_update"`
|
||||
AutoStart string `json:"auto_start"`
|
||||
Beta string `json:"beta"`
|
||||
Doh string `json:"doh"`
|
||||
SplitMode string `json:"split_mode"`
|
||||
ShowAllMail string `json:"show_all_mail"`
|
||||
IMAPConnectionMode string `json:"imap_connection_mode"`
|
||||
SMTPConnectionMode string `json:"smtp_connection_mode"`
|
||||
IMAPPort string `json:"imap_port"`
|
||||
SMTPPort string `json:"smtp_port"`
|
||||
CacheLocation string `json:"cache_location"`
|
||||
KeychainPref string `json:"keychain_pref"`
|
||||
PrevVersion string `json:"prev_version"`
|
||||
Rollout string `json:"rollout"`
|
||||
// Fields below correspond to bool
|
||||
AutoUpdateEnabled string `json:"isAutoUpdateEnabled"`
|
||||
AutoStartEnabled string `json:"isAutoStartEnabled"`
|
||||
BetaEnabled string `json:"isBetaEnabled"`
|
||||
DohEnabled string `json:"isDohEnabled"`
|
||||
UseSplitMode string `json:"usesSplitMode"`
|
||||
ShowAllMail string `json:"useAllMail"`
|
||||
UseDefaultIMAPPort string `json:"useDefaultImapPort"`
|
||||
UseDefaultSMTPPort string `json:"useDefaultSmtpPort"`
|
||||
UseDefaultCacheLocation string `json:"useDefaultCacheLocation"`
|
||||
UseDefaultKeychain string `json:"useDefaultKeychain"`
|
||||
ContactedByAppleNotes string `json:"isContactedByAppleNotes"`
|
||||
|
||||
// Fields below are enums.
|
||||
PrevVersion string `json:"prevVersion"` // Free text (exception)
|
||||
IMAPConnectionMode string `json:"imapConnectionMode"`
|
||||
SMTPConnectionMode string `json:"smtpConnectionMode"`
|
||||
UserPlanGroup string `json:"bridgePlanGroup"`
|
||||
}
|
||||
|
||||
type HeartbeatData struct {
|
||||
@ -82,4 +84,26 @@ type Heartbeat struct {
|
||||
defaultSMTPPort int
|
||||
defaultCache string
|
||||
defaultKeychain string
|
||||
defaultUserPlan string
|
||||
}
|
||||
|
||||
func NewHeartbeatDimensions() HeartbeatDimensions {
|
||||
return HeartbeatDimensions{
|
||||
AutoUpdateEnabled: "false",
|
||||
AutoStartEnabled: "false",
|
||||
BetaEnabled: "false",
|
||||
DohEnabled: "false",
|
||||
UseSplitMode: "false",
|
||||
ShowAllMail: "false",
|
||||
UseDefaultIMAPPort: "false",
|
||||
UseDefaultSMTPPort: "false",
|
||||
UseDefaultCacheLocation: "false",
|
||||
UseDefaultKeychain: "false",
|
||||
ContactedByAppleNotes: "false",
|
||||
|
||||
PrevVersion: "unknown",
|
||||
IMAPConnectionMode: dimensionSSL,
|
||||
SMTPConnectionMode: dimensionSSL,
|
||||
UserPlanGroup: plan.Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user