status-go/centralizedmetrics/metrics_test.go
Andrea Maria Piana 9a59d6a459 feat(metrics)_: add centralized metrics
This commit adds support for centralized metrics.
There are two providers as of now, and we haven't quite decided which
one to go for, so for the time being both are supported.
It also introduces a new endpoint InitializeApplication that replaces
OpenAccounts
2024-07-11 10:05:31 +01:00

216 lines
5.8 KiB
Go

package centralizedmetrics
import (
"errors"
"fmt"
"sync"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/status-im/status-go/centralizedmetrics/common"
"github.com/status-im/status-go/protocol/tt"
)
var testMetric = common.Metric{ID: "user-id", EventName: "test-name", EventValue: map[string]interface{}{"test-name": "test-value"}, Platform: "android", AppVersion: "2.30.0"}
// TestMetricService covers the main functionalities of MetricService
func TestMetricService(t *testing.T) {
repository := &TestMetricRepository{}
processor := &TestMetricProcessor{}
service := NewMetricService(repository, processor, 1*time.Second)
// Start the service
service.Start()
defer service.Stop()
// Test adding a metric
if err := service.AddMetric(testMetric); err != nil {
t.Fatalf("failed to add metric: %v", err)
}
err := tt.RetryWithBackOff(func() error {
// Verify metrics were processed and deleted
if len(processor.processedMetrics) != 1 {
return fmt.Errorf("expected 1 processed metric, got %d", len(processor.processedMetrics))
}
if len(repository.metrics) != 0 {
return fmt.Errorf("expected 0 metrics in repository, got %d", len(repository.metrics))
}
return nil
})
require.NoError(t, err)
}
// TestMetricRepository is a mock implementation of MetricRepository for testing
type TestMetricRepository struct {
metrics []common.Metric
enabled bool
userConfirmed bool
mutex sync.Mutex
}
func (r *TestMetricRepository) Poll() ([]common.Metric, error) {
r.mutex.Lock()
defer r.mutex.Unlock()
polledMetrics := r.metrics
r.metrics = []common.Metric{}
return polledMetrics, nil
}
func (r *TestMetricRepository) ToggleEnabled(enabled bool) error {
r.enabled = enabled
return nil
}
func (r *TestMetricRepository) Info() (*MetricsInfo, error) {
return &MetricsInfo{Enabled: r.enabled, UserConfirmed: r.userConfirmed}, nil
}
func (r *TestMetricRepository) Delete(metrics []common.Metric) error {
r.mutex.Lock()
defer r.mutex.Unlock()
// Simulate deleting from the repository
for _, metric := range metrics {
for i, m := range r.metrics {
if m.ID == metric.ID {
r.metrics = append(r.metrics[:i], r.metrics[i+1:]...)
break
}
}
}
return nil
}
func (r *TestMetricRepository) Add(metric common.Metric) error {
r.mutex.Lock()
defer r.mutex.Unlock()
r.metrics = append(r.metrics, metric)
return nil
}
// TestMetricProcessor is a mock implementation of MetricProcessor for testing
type TestMetricProcessor struct {
processedMetrics []common.Metric
mutex sync.Mutex
}
func (p *TestMetricProcessor) Process(metrics []common.Metric) error {
p.mutex.Lock()
defer p.mutex.Unlock()
p.processedMetrics = append(p.processedMetrics, metrics...)
return nil
}
func TestAddMetric(t *testing.T) {
repository := &TestMetricRepository{}
processor := &TestMetricProcessor{}
service := NewMetricService(repository, processor, 1*time.Second)
err := service.AddMetric(testMetric)
if err != nil {
t.Fatalf("failed to add metric: %v", err)
}
// Verify metric was added to the repository
if len(repository.metrics) != 1 {
t.Fatalf("expected 1 metric in repository, got %d", len(repository.metrics))
}
require.Equal(t, testMetric.ID, repository.metrics[0].ID)
require.Equal(t, testMetric.EventValue, repository.metrics[0].EventValue)
require.Equal(t, testMetric.Platform, repository.metrics[0].Platform)
require.Equal(t, testMetric.AppVersion, repository.metrics[0].AppVersion)
}
func TestProcessMetrics(t *testing.T) {
repository := &TestMetricRepository{}
processor := &TestMetricProcessor{}
service := NewMetricService(repository, processor, 1*time.Second)
// Add metrics directly to repository for polling
require.NoError(t, repository.Add(common.Metric{ID: "3", EventValue: map[string]interface{}{"price": 6.28}}))
require.NoError(t, repository.Add(common.Metric{ID: "4", EventValue: map[string]interface{}{"price": 2.71}}))
service.processMetrics()
// Verify metrics were processed
if len(processor.processedMetrics) != 2 {
t.Fatalf("expected 2 processed metrics, got %d", len(processor.processedMetrics))
}
// Verify metrics were deleted from repository
if len(repository.metrics) != 0 {
t.Fatalf("expected 0 metrics in repository, got %d", len(repository.metrics))
}
}
func TestStartStop(t *testing.T) {
repository := &TestMetricRepository{}
processor := &TestMetricProcessor{}
service := NewMetricService(repository, processor, 1*time.Second)
service.Start()
require.True(t, service.started)
service.Stop()
err := tt.RetryWithBackOff(func() error {
if service.started {
return errors.New("expected service to be stopped, but it is still running")
}
return nil
})
require.NoError(t, err)
}
func TestServiceWithoutMetrics(t *testing.T) {
repository := &TestMetricRepository{}
processor := &TestMetricProcessor{}
service := NewMetricService(repository, processor, 1*time.Second)
service.Start()
defer service.Stop()
// Verify no metrics were processed
if len(processor.processedMetrics) != 0 {
t.Fatalf("expected 0 processed metrics, got %d", len(processor.processedMetrics))
}
}
func TestServiceEnabled(t *testing.T) {
repository := &TestMetricRepository{}
processor := &TestMetricProcessor{}
service := NewMetricService(repository, processor, 1*time.Second)
err := service.ToggleEnabled(true)
require.NoError(t, err)
require.True(t, service.started)
err = service.ToggleEnabled(false)
require.NoError(t, err)
require.False(t, service.started)
}
func TestServiceEnsureStarted(t *testing.T) {
repository := &TestMetricRepository{}
processor := &TestMetricProcessor{}
service := NewMetricService(repository, processor, 1*time.Second)
err := service.EnsureStarted()
require.NoError(t, err)
require.False(t, service.started)
repository.enabled = true
err = service.EnsureStarted()
require.NoError(t, err)
require.True(t, service.started)
}