github.com/status-im/status-go@v1.1.0/centralizedmetrics/metrics_test.go (about) 1 package centralizedmetrics 2 3 import ( 4 "errors" 5 "fmt" 6 "sync" 7 "testing" 8 "time" 9 10 "github.com/stretchr/testify/require" 11 12 "github.com/status-im/status-go/centralizedmetrics/common" 13 "github.com/status-im/status-go/protocol/tt" 14 ) 15 16 var testMetric = common.Metric{ID: "user-id", EventName: "test-name", EventValue: map[string]interface{}{"test-name": "test-value"}, Platform: "android", AppVersion: "2.30.0"} 17 18 // TestMetricService covers the main functionalities of MetricService 19 func TestMetricService(t *testing.T) { 20 repository := &TestMetricRepository{} 21 processor := &TestMetricProcessor{} 22 service := NewMetricService(repository, processor, 1*time.Second) 23 24 // Start the service 25 service.Start() 26 defer service.Stop() 27 28 // Test adding a metric 29 if err := service.AddMetric(testMetric); err != nil { 30 t.Fatalf("failed to add metric: %v", err) 31 } 32 33 err := tt.RetryWithBackOff(func() error { 34 // Verify metrics were processed and deleted 35 if len(processor.processedMetrics) != 1 { 36 return fmt.Errorf("expected 1 processed metric, got %d", len(processor.processedMetrics)) 37 } 38 39 if len(repository.metrics) != 0 { 40 return fmt.Errorf("expected 0 metrics in repository, got %d", len(repository.metrics)) 41 } 42 return nil 43 }) 44 require.NoError(t, err) 45 } 46 47 // TestMetricRepository is a mock implementation of MetricRepository for testing 48 type TestMetricRepository struct { 49 metrics []common.Metric 50 enabled bool 51 userConfirmed bool 52 mutex sync.Mutex 53 } 54 55 func (r *TestMetricRepository) Poll() ([]common.Metric, error) { 56 r.mutex.Lock() 57 defer r.mutex.Unlock() 58 59 polledMetrics := r.metrics 60 r.metrics = []common.Metric{} 61 return polledMetrics, nil 62 } 63 64 func (r *TestMetricRepository) ToggleEnabled(enabled bool) error { 65 r.enabled = enabled 66 return nil 67 } 68 69 func (r *TestMetricRepository) Info() (*MetricsInfo, error) { 70 return &MetricsInfo{Enabled: r.enabled, UserConfirmed: r.userConfirmed}, nil 71 } 72 73 func (r *TestMetricRepository) Delete(metrics []common.Metric) error { 74 r.mutex.Lock() 75 defer r.mutex.Unlock() 76 77 // Simulate deleting from the repository 78 for _, metric := range metrics { 79 for i, m := range r.metrics { 80 if m.ID == metric.ID { 81 r.metrics = append(r.metrics[:i], r.metrics[i+1:]...) 82 break 83 } 84 } 85 } 86 return nil 87 } 88 89 func (r *TestMetricRepository) Add(metric common.Metric) error { 90 r.mutex.Lock() 91 defer r.mutex.Unlock() 92 93 r.metrics = append(r.metrics, metric) 94 return nil 95 } 96 97 // TestMetricProcessor is a mock implementation of MetricProcessor for testing 98 type TestMetricProcessor struct { 99 processedMetrics []common.Metric 100 mutex sync.Mutex 101 } 102 103 func (p *TestMetricProcessor) Process(metrics []common.Metric) error { 104 p.mutex.Lock() 105 defer p.mutex.Unlock() 106 107 p.processedMetrics = append(p.processedMetrics, metrics...) 108 return nil 109 } 110 111 func TestAddMetric(t *testing.T) { 112 repository := &TestMetricRepository{} 113 processor := &TestMetricProcessor{} 114 service := NewMetricService(repository, processor, 1*time.Second) 115 116 err := service.AddMetric(testMetric) 117 if err != nil { 118 t.Fatalf("failed to add metric: %v", err) 119 } 120 121 // Verify metric was added to the repository 122 if len(repository.metrics) != 1 { 123 t.Fatalf("expected 1 metric in repository, got %d", len(repository.metrics)) 124 } 125 126 require.Equal(t, testMetric.ID, repository.metrics[0].ID) 127 require.Equal(t, testMetric.EventValue, repository.metrics[0].EventValue) 128 require.Equal(t, testMetric.Platform, repository.metrics[0].Platform) 129 require.Equal(t, testMetric.AppVersion, repository.metrics[0].AppVersion) 130 } 131 132 func TestProcessMetrics(t *testing.T) { 133 repository := &TestMetricRepository{} 134 processor := &TestMetricProcessor{} 135 service := NewMetricService(repository, processor, 1*time.Second) 136 137 // Add metrics directly to repository for polling 138 require.NoError(t, repository.Add(common.Metric{ID: "3", EventValue: map[string]interface{}{"price": 6.28}})) 139 require.NoError(t, repository.Add(common.Metric{ID: "4", EventValue: map[string]interface{}{"price": 2.71}})) 140 141 service.processMetrics() 142 143 // Verify metrics were processed 144 if len(processor.processedMetrics) != 2 { 145 t.Fatalf("expected 2 processed metrics, got %d", len(processor.processedMetrics)) 146 } 147 148 // Verify metrics were deleted from repository 149 if len(repository.metrics) != 0 { 150 t.Fatalf("expected 0 metrics in repository, got %d", len(repository.metrics)) 151 } 152 } 153 154 func TestStartStop(t *testing.T) { 155 repository := &TestMetricRepository{} 156 processor := &TestMetricProcessor{} 157 service := NewMetricService(repository, processor, 1*time.Second) 158 159 service.Start() 160 require.True(t, service.started) 161 service.Stop() 162 163 err := tt.RetryWithBackOff(func() error { 164 if service.started { 165 return errors.New("expected service to be stopped, but it is still running") 166 } 167 return nil 168 169 }) 170 require.NoError(t, err) 171 } 172 173 func TestServiceWithoutMetrics(t *testing.T) { 174 repository := &TestMetricRepository{} 175 processor := &TestMetricProcessor{} 176 service := NewMetricService(repository, processor, 1*time.Second) 177 178 service.Start() 179 defer service.Stop() 180 181 // Verify no metrics were processed 182 if len(processor.processedMetrics) != 0 { 183 t.Fatalf("expected 0 processed metrics, got %d", len(processor.processedMetrics)) 184 } 185 } 186 187 func TestServiceEnabled(t *testing.T) { 188 repository := &TestMetricRepository{} 189 processor := &TestMetricProcessor{} 190 service := NewMetricService(repository, processor, 1*time.Second) 191 192 err := service.ToggleEnabled(true) 193 require.NoError(t, err) 194 require.True(t, service.started) 195 196 err = service.ToggleEnabled(false) 197 require.NoError(t, err) 198 require.False(t, service.started) 199 } 200 201 func TestServiceEnsureStarted(t *testing.T) { 202 repository := &TestMetricRepository{} 203 processor := &TestMetricProcessor{} 204 service := NewMetricService(repository, processor, 1*time.Second) 205 206 err := service.EnsureStarted() 207 require.NoError(t, err) 208 require.False(t, service.started) 209 210 repository.enabled = true 211 212 err = service.EnsureStarted() 213 require.NoError(t, err) 214 require.True(t, service.started) 215 }