From 1f79e3b0a7d6e9b0f0ac8340d8062f7f2797c4dc Mon Sep 17 00:00:00 2001 From: Romain LE JEUNE Date: Thu, 29 Jun 2023 13:11:42 +0200 Subject: [PATCH] feat(GODT-2715): Add Unitary test for configStatus event. --- internal/configstatus/config_status_test.go | 206 ++++++++++++++++++ .../configstatus/configuration_abort_test.go | 75 +++++++ .../configstatus/configuration_progress.go | 3 + .../configuration_progress_test.go | 71 ++++++ .../configuration_recovery_test.go | 79 +++++++ .../configuration_success_test.go | 77 +++++++ tests/config_status_test.go | 2 +- 7 files changed, 512 insertions(+), 1 deletion(-) create mode 100644 internal/configstatus/config_status_test.go create mode 100644 internal/configstatus/configuration_abort_test.go create mode 100644 internal/configstatus/configuration_progress_test.go create mode 100644 internal/configstatus/configuration_recovery_test.go create mode 100644 internal/configstatus/configuration_success_test.go diff --git a/internal/configstatus/config_status_test.go b/internal/configstatus/config_status_test.go new file mode 100644 index 00000000..743618c2 --- /dev/null +++ b/internal/configstatus/config_status_test.go @@ -0,0 +1,206 @@ +// 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 . + +package configstatus_test + +import ( + "encoding/json" + "os" + "path/filepath" + "testing" + "time" + + "github.com/ProtonMail/proton-bridge/v3/internal/configstatus" + "github.com/stretchr/testify/require" +) + +func TestConfigStatus_init_virgin(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + require.Equal(t, "1.0.0", config.Data.Metadata.Version) + + require.Equal(t, false, config.Data.DataV1.PendingSince.IsZero()) + require.Equal(t, true, config.Data.DataV1.LastProgress.IsZero()) + + require.Equal(t, "", config.Data.DataV1.Autoconf) + require.Equal(t, uint64(0), config.Data.DataV1.ClickedLink) + require.Equal(t, false, config.Data.DataV1.ReportSent) + require.Equal(t, false, config.Data.DataV1.ReportClick) + require.Equal(t, "", config.Data.DataV1.FailureDetails) +} + +func TestConfigStatus_init_existing(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + var data = configstatus.ConfigurationStatusData{ + Metadata: configstatus.Metadata{Version: "1.0.0"}, + DataV1: configstatus.DataV1{Autoconf: "Mr TBird"}, + } + require.NoError(t, dumpConfigStatusInFile(&data, file)) + + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + require.Equal(t, "1.0.0", config.Data.Metadata.Version) + require.Equal(t, "Mr TBird", config.Data.DataV1.Autoconf) +} + +func TestConfigStatus_init_bad_version(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + var data = configstatus.ConfigurationStatusData{ + Metadata: configstatus.Metadata{Version: "2.0.0"}, + DataV1: configstatus.DataV1{Autoconf: "Mr TBird"}, + } + require.NoError(t, dumpConfigStatusInFile(&data, file)) + + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + require.Equal(t, "1.0.0", config.Data.Metadata.Version) + require.Equal(t, "", config.Data.DataV1.Autoconf) +} + +func TestConfigStatus_IsPending(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + require.Equal(t, true, config.IsPending()) + config.Data.DataV1.PendingSince = time.Time{} + require.Equal(t, false, config.IsPending()) +} + +func TestConfigStatus_IsFromFailure(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + require.Equal(t, false, config.IsFromFailure()) + config.Data.DataV1.FailureDetails = "test" + require.Equal(t, true, config.IsFromFailure()) +} + +func TestConfigStatus_ApplySuccess(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + require.Equal(t, true, config.IsPending()) + require.NoError(t, config.ApplySuccess()) + require.Equal(t, false, config.IsPending()) + + config2, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + require.Equal(t, "1.0.0", config2.Data.Metadata.Version) + require.Equal(t, true, config2.Data.DataV1.PendingSince.IsZero()) + require.Equal(t, true, config2.Data.DataV1.LastProgress.IsZero()) + require.Equal(t, "", config2.Data.DataV1.Autoconf) + require.Equal(t, uint64(0), config2.Data.DataV1.ClickedLink) + require.Equal(t, false, config2.Data.DataV1.ReportSent) + require.Equal(t, false, config2.Data.DataV1.ReportClick) + require.Equal(t, "", config2.Data.DataV1.FailureDetails) +} + +func TestConfigStatus_ApplyFailure(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + require.NoError(t, config.ApplySuccess()) + + require.NoError(t, config.ApplyFailure("Big Failure")) + require.Equal(t, true, config.IsFromFailure()) + require.Equal(t, true, config.IsPending()) + + config2, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + require.Equal(t, "1.0.0", config2.Data.Metadata.Version) + require.Equal(t, false, config2.Data.DataV1.PendingSince.IsZero()) + require.Equal(t, true, config2.Data.DataV1.LastProgress.IsZero()) + require.Equal(t, "", config2.Data.DataV1.Autoconf) + require.Equal(t, uint64(0), config2.Data.DataV1.ClickedLink) + require.Equal(t, false, config2.Data.DataV1.ReportSent) + require.Equal(t, false, config2.Data.DataV1.ReportClick) + require.Equal(t, "Big Failure", config2.Data.DataV1.FailureDetails) +} + +func TestConfigStatus_ApplyProgress(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + require.Equal(t, true, config.IsPending()) + require.Equal(t, true, config.Data.DataV1.LastProgress.IsZero()) + + require.NoError(t, config.ApplyProgress()) + + config2, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + require.Equal(t, "1.0.0", config2.Data.Metadata.Version) + require.Equal(t, false, config2.Data.DataV1.PendingSince.IsZero()) + require.Equal(t, false, config2.Data.DataV1.LastProgress.IsZero()) + require.Equal(t, "", config2.Data.DataV1.Autoconf) + require.Equal(t, uint64(0), config2.Data.DataV1.ClickedLink) + require.Equal(t, false, config2.Data.DataV1.ReportSent) + require.Equal(t, false, config2.Data.DataV1.ReportClick) + require.Equal(t, "", config2.Data.DataV1.FailureDetails) +} + +func TestConfigStatus_RecordLinkClicked(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + require.Equal(t, uint64(0), config.Data.DataV1.ClickedLink) + require.NoError(t, config.RecordLinkClicked(0)) + require.Equal(t, uint64(1), config.Data.DataV1.ClickedLink) + require.NoError(t, config.RecordLinkClicked(1)) + require.Equal(t, uint64(3), config.Data.DataV1.ClickedLink) + + config2, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + require.Equal(t, "1.0.0", config2.Data.Metadata.Version) + require.Equal(t, false, config2.Data.DataV1.PendingSince.IsZero()) + require.Equal(t, true, config2.Data.DataV1.LastProgress.IsZero()) + require.Equal(t, "", config2.Data.DataV1.Autoconf) + require.Equal(t, uint64(3), config2.Data.DataV1.ClickedLink) + require.Equal(t, false, config2.Data.DataV1.ReportSent) + require.Equal(t, false, config2.Data.DataV1.ReportClick) + require.Equal(t, "", config2.Data.DataV1.FailureDetails) +} + +func dumpConfigStatusInFile(data *configstatus.ConfigurationStatusData, file string) error { + f, err := os.Create(file) + if err != nil { + return err + } + defer func() { _ = f.Close() }() + + return json.NewEncoder(f).Encode(data) +} diff --git a/internal/configstatus/configuration_abort_test.go b/internal/configstatus/configuration_abort_test.go new file mode 100644 index 00000000..e076952a --- /dev/null +++ b/internal/configstatus/configuration_abort_test.go @@ -0,0 +1,75 @@ +// 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 . + +package configstatus_test + +import ( + "path/filepath" + "testing" + "time" + + "github.com/ProtonMail/proton-bridge/v3/internal/configstatus" + "github.com/stretchr/testify/require" +) + +func TestConfigurationAbort_default(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + var builder = configstatus.ConfigAbortBuilder{} + req := builder.New(config.Data) + + require.Equal(t, "bridge.any.configuration", req.MeasurementGroup) + require.Equal(t, "bridge_config_abort", req.Event) + require.Equal(t, 0, req.Values.Duration) + require.Equal(t, false, req.Dimensions.ReportClick) + require.Equal(t, false, req.Dimensions.ReportSent) + require.Equal(t, uint64(0), req.Dimensions.ClickedLink) +} + +func TestConfigurationAbort_fed(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + var data = configstatus.ConfigurationStatusData{ + Metadata: configstatus.Metadata{Version: "1.0.0"}, + DataV1: configstatus.DataV1{ + PendingSince: time.Now().Add(-10 * time.Minute), + LastProgress: time.Time{}, + Autoconf: "Mr TBird", + ClickedLink: 42, + ReportSent: false, + ReportClick: true, + FailureDetails: "Not an error", + }, + } + require.NoError(t, dumpConfigStatusInFile(&data, file)) + + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + var builder = configstatus.ConfigAbortBuilder{} + req := builder.New(config.Data) + + require.Equal(t, "bridge.any.configuration", req.MeasurementGroup) + require.Equal(t, "bridge_config_abort", req.Event) + require.Equal(t, 10, req.Values.Duration) + require.Equal(t, true, req.Dimensions.ReportClick) + require.Equal(t, false, req.Dimensions.ReportSent) + require.Equal(t, uint64(42), req.Dimensions.ClickedLink) +} diff --git a/internal/configstatus/configuration_progress.go b/internal/configstatus/configuration_progress.go index 37dfd2d8..8046e689 100644 --- a/internal/configstatus/configuration_progress.go +++ b/internal/configstatus/configuration_progress.go @@ -45,6 +45,9 @@ func (*ConfigProgressBuilder) New(data *ConfigurationStatusData) ConfigProgressD } func numberOfDay(now, prev time.Time) int { + if now.IsZero() || prev.IsZero() { + return 0 + } if now.Year() > prev.Year() { if now.YearDay() > prev.YearDay() { return 365 + (now.YearDay() - prev.YearDay()) diff --git a/internal/configstatus/configuration_progress_test.go b/internal/configstatus/configuration_progress_test.go new file mode 100644 index 00000000..ff0cd88c --- /dev/null +++ b/internal/configstatus/configuration_progress_test.go @@ -0,0 +1,71 @@ +// 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 . + +package configstatus_test + +import ( + "path/filepath" + "testing" + "time" + + "github.com/ProtonMail/proton-bridge/v3/internal/configstatus" + "github.com/stretchr/testify/require" +) + +func TestConfigurationProgress_default(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + var builder = configstatus.ConfigProgressBuilder{} + req := builder.New(config.Data) + + require.Equal(t, "bridge.any.configuration", req.MeasurementGroup) + require.Equal(t, "bridge_config_progress", req.Event) + require.Equal(t, 0, req.Values.NbDay) + require.Equal(t, 0, req.Values.NbDaySinceLast) +} + +func TestConfigurationProgress_fed(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + var data = configstatus.ConfigurationStatusData{ + Metadata: configstatus.Metadata{Version: "1.0.0"}, + DataV1: configstatus.DataV1{ + PendingSince: time.Now().AddDate(0, 0, -5), + LastProgress: time.Now().AddDate(0, 0, -2), + Autoconf: "Mr TBird", + ClickedLink: 42, + ReportSent: false, + ReportClick: true, + FailureDetails: "Not an error", + }, + } + require.NoError(t, dumpConfigStatusInFile(&data, file)) + + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + var builder = configstatus.ConfigProgressBuilder{} + req := builder.New(config.Data) + + require.Equal(t, "bridge.any.configuration", req.MeasurementGroup) + require.Equal(t, "bridge_config_progress", req.Event) + require.Equal(t, 5, req.Values.NbDay) + require.Equal(t, 2, req.Values.NbDaySinceLast) +} diff --git a/internal/configstatus/configuration_recovery_test.go b/internal/configstatus/configuration_recovery_test.go new file mode 100644 index 00000000..722e5245 --- /dev/null +++ b/internal/configstatus/configuration_recovery_test.go @@ -0,0 +1,79 @@ +// 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 . + +package configstatus_test + +import ( + "path/filepath" + "testing" + "time" + + "github.com/ProtonMail/proton-bridge/v3/internal/configstatus" + "github.com/stretchr/testify/require" +) + +func TestConfigurationRecovery_default(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + var builder = configstatus.ConfigRecoveryBuilder{} + req := builder.New(config.Data) + + require.Equal(t, "bridge.any.configuration", req.MeasurementGroup) + require.Equal(t, "bridge_config_recovery", req.Event) + require.Equal(t, 0, req.Values.Duration) + require.Equal(t, "", req.Dimensions.Autoconf) + require.Equal(t, false, req.Dimensions.ReportClick) + require.Equal(t, false, req.Dimensions.ReportSent) + require.Equal(t, uint64(0), req.Dimensions.ClickedLink) + require.Equal(t, "", req.Dimensions.FailureDetails) +} + +func TestConfigurationRecovery_fed(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + var data = configstatus.ConfigurationStatusData{ + Metadata: configstatus.Metadata{Version: "1.0.0"}, + DataV1: configstatus.DataV1{ + PendingSince: time.Now().Add(-10 * time.Minute), + LastProgress: time.Time{}, + Autoconf: "Mr TBird", + ClickedLink: 42, + ReportSent: false, + ReportClick: true, + FailureDetails: "Not an error", + }, + } + require.NoError(t, dumpConfigStatusInFile(&data, file)) + + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + var builder = configstatus.ConfigRecoveryBuilder{} + req := builder.New(config.Data) + + require.Equal(t, "bridge.any.configuration", req.MeasurementGroup) + require.Equal(t, "bridge_config_recovery", req.Event) + require.Equal(t, 10, req.Values.Duration) + require.Equal(t, "Mr TBird", req.Dimensions.Autoconf) + require.Equal(t, true, req.Dimensions.ReportClick) + require.Equal(t, false, req.Dimensions.ReportSent) + require.Equal(t, uint64(42), req.Dimensions.ClickedLink) + require.Equal(t, "Not an error", req.Dimensions.FailureDetails) +} diff --git a/internal/configstatus/configuration_success_test.go b/internal/configstatus/configuration_success_test.go new file mode 100644 index 00000000..83b73f24 --- /dev/null +++ b/internal/configstatus/configuration_success_test.go @@ -0,0 +1,77 @@ +// 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 . + +package configstatus_test + +import ( + "path/filepath" + "testing" + "time" + + "github.com/ProtonMail/proton-bridge/v3/internal/configstatus" + "github.com/stretchr/testify/require" +) + +func TestConfigurationSuccess_default(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + var builder = configstatus.ConfigSuccessBuilder{} + req := builder.New(config.Data) + + require.Equal(t, "bridge.any.configuration", req.MeasurementGroup) + require.Equal(t, "bridge_config_success", req.Event) + require.Equal(t, 0, req.Values.Duration) + require.Equal(t, "", req.Dimensions.Autoconf) + require.Equal(t, false, req.Dimensions.ReportClick) + require.Equal(t, false, req.Dimensions.ReportSent) + require.Equal(t, uint64(0), req.Dimensions.ClickedLink) +} + +func TestConfigurationSuccess_fed(t *testing.T) { + dir := t.TempDir() + file := filepath.Join(dir, "dummy.json") + var data = configstatus.ConfigurationStatusData{ + Metadata: configstatus.Metadata{Version: "1.0.0"}, + DataV1: configstatus.DataV1{ + PendingSince: time.Now().Add(-10 * time.Minute), + LastProgress: time.Time{}, + Autoconf: "Mr TBird", + ClickedLink: 42, + ReportSent: false, + ReportClick: true, + FailureDetails: "Not an error", + }, + } + require.NoError(t, dumpConfigStatusInFile(&data, file)) + + config, err := configstatus.LoadConfigurationStatus(file) + require.NoError(t, err) + + var builder = configstatus.ConfigSuccessBuilder{} + req := builder.New(config.Data) + + require.Equal(t, "bridge.any.configuration", req.MeasurementGroup) + require.Equal(t, "bridge_config_success", req.Event) + require.Equal(t, 10, req.Values.Duration) + require.Equal(t, "Mr TBird", req.Dimensions.Autoconf) + require.Equal(t, true, req.Dimensions.ReportClick) + require.Equal(t, false, req.Dimensions.ReportSent) + require.Equal(t, uint64(42), req.Dimensions.ClickedLink) +} diff --git a/tests/config_status_test.go b/tests/config_status_test.go index 254c2a1f..e6fff35c 100644 --- a/tests/config_status_test.go +++ b/tests/config_status_test.go @@ -119,7 +119,7 @@ func (s *scenario) forceConfigStatusProgressToBeSentForUser(username string) err if err != nil { return err } - defer f.Close() + defer func() { _ = f.Close() }() return json.NewEncoder(f).Encode(data) }