Skip to content

Commit

Permalink
add more unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
canercidam committed Aug 15, 2023
1 parent f8ab4a7 commit c61d8d1
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 94 deletions.
6 changes: 0 additions & 6 deletions package-lock.json

This file was deleted.

4 changes: 2 additions & 2 deletions services/components/prometheus/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func newGauge(desc *prometheus.Desc, value float64, labels ...string) prometheus
return metric
}

func transformHealthMetricsToProm(metrics healthMetrics) (promMetrics []prometheus.Metric) {
func transformHealthMetricsToProm(metricKinds []*MetricKind, metrics HealthMetrics) (promMetrics []prometheus.Metric) {
for _, metricKind := range metricKinds {
for _, mapping := range metricKind.Mappings {
if metric, ok := metrics.Get(mapping.FromHealth); ok {
Expand All @@ -39,7 +39,7 @@ type Mapping struct {
ToProm string
}

var metricKinds = []*MetricKind{
var knownMetricKinds = []*MetricKind{
////////// input stream

{
Expand Down
42 changes: 17 additions & 25 deletions services/components/prometheus/prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type ServiceHealth interface {

type promCollector struct {
serviceHealth ServiceHealth
metricKinds []*MetricKind
}

type promHTTPLogger struct{}
Expand All @@ -29,10 +30,17 @@ func (l promHTTPLogger) Println(v ...interface{}) {
}

// StartCollector starts a collector.
func StartCollector(serviceHealth ServiceHealth, port int) {
func StartCollector(serviceHealth ServiceHealth, metricKinds []*MetricKind, port int) {
prometheus.MustRegister(version.NewCollector("forta_node"))

var collector prometheus.Collector = &promCollector{serviceHealth: serviceHealth}
if metricKinds == nil {
metricKinds = knownMetricKinds
}

var collector prometheus.Collector = &promCollector{
serviceHealth: serviceHealth,
metricKinds: metricKinds,
}
prometheus.MustRegister(collector)

mux := http.NewServeMux()
Expand Down Expand Up @@ -68,22 +76,18 @@ func StartCollector(serviceHealth ServiceHealth, port int) {
func (pc *promCollector) Describe(ch chan<- *prometheus.Desc) {
}

type healthMetric struct {
type HealthMetric struct {
MetricName string
Report *health.Report
}

func (metric *healthMetric) Value() float64 {
func (metric *HealthMetric) Value() float64 {
return parseReportValue(metric.Report)
}

func (metric *healthMetric) SinceUnixTs() float64 {
return sinceUnixTs(metric.Report.Details)
}

type healthMetrics []*healthMetric
type HealthMetrics []*HealthMetric

func (metrics healthMetrics) Get(name string) (*healthMetric, bool) {
func (metrics HealthMetrics) Get(name string) (*HealthMetric, bool) {
for _, metric := range metrics {
if metric.MetricName == name {
return metric, true
Expand All @@ -93,7 +97,7 @@ func (metrics healthMetrics) Get(name string) (*healthMetric, bool) {
}

func (pc *promCollector) Collect(ch chan<- prometheus.Metric) {
var healthMetrics healthMetrics
var healthMetrics HealthMetrics
for _, report := range pc.serviceHealth.CheckServiceHealth() {
parts := strings.Split(report.Name, ".service.")
if len(parts) != 2 {
Expand All @@ -104,13 +108,13 @@ func (pc *promCollector) Collect(ch chan<- prometheus.Metric) {
continue
}

healthMetrics = append(healthMetrics, &healthMetric{
healthMetrics = append(healthMetrics, &HealthMetric{
MetricName: toPrometheusName(parts[1]),
Report: report,
})
}

sendMetrics(ch, transformHealthMetricsToProm(healthMetrics)...)
sendMetrics(ch, transformHealthMetricsToProm(pc.metricKinds, healthMetrics)...)
}

func sendMetrics(ch chan<- prometheus.Metric, metrics ...prometheus.Metric) {
Expand All @@ -119,18 +123,6 @@ func sendMetrics(ch chan<- prometheus.Metric, metrics ...prometheus.Metric) {
}
}

func newPrometheusMetric(value float64, serviceName, reportName string) (prometheus.Metric, error) {
desc := prometheus.NewDesc(
prometheus.BuildFQName("forta", serviceName, reportName),
"", nil, nil,
)
metric, err := prometheus.NewConstMetric(desc, prometheus.GaugeValue, value)
if err != nil {
metric = prometheus.NewInvalidMetric(desc, err)
}
return metric, err
}

func toPrometheusName(name string) string {
name = strings.ReplaceAll(name, "-", "_")
name = strings.ReplaceAll(name, ".", "_")
Expand Down
71 changes: 23 additions & 48 deletions services/components/prometheus/prometheus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,52 +18,38 @@ func (*testServiceHealth) CheckServiceHealth() (allReports health.Reports) {
Status: health.StatusOK,
Details: "1420687622144",
},
{
Name: "foo.service.bar.m2",
Status: health.StatusOK,
Details: "true",
},
{
Name: "foo.service.bar.m3",
Status: health.StatusOK,
Details: "2020-10-11T01:02:03Z",
},
{
Name: "foo.service.bar.m4",
Status: health.StatusOK,
Details: "message 1",
},
{
Name: "foo.service.bar.m5",
Status: health.StatusFailing,
Details: "message 2",
},
{
Name: "skipped-invalid-name-pattern",
Status: health.StatusFailing,
Details: "message X",
},
{
Name: "foo.service.skipped-single-name",
Status: health.StatusFailing,
Details: "message Y",
},
}
}

var testMetricKinds = []*MetricKind{
{
Desc: prometheus.NewDesc(
fqName("service_bar"), "",
[]string{"name"}, nil,
),
Mappings: []*Mapping{
{
FromHealth: "bar_m1",
ToProm: "m1",
},
},
},
}

func TestPrometheusCollector(t *testing.T) {
r := require.New(t)

collector := &promCollector{
serviceHealth: &testServiceHealth{},
metricKinds: testMetricKinds,
}

descCh := make(chan *prometheus.Desc, 1)
collector.Describe(descCh)
close(descCh)
r.Len(descCh, 0)

metricCh := make(chan prometheus.Metric, 5)
metricCh := make(chan prometheus.Metric, 1)
collector.Collect(metricCh)
close(metricCh)

Expand All @@ -72,29 +58,18 @@ func TestPrometheusCollector(t *testing.T) {
allMetrics = append(allMetrics, metric)
}

r.Len(allMetrics, 1)

var encodedMetric io_prometheus_client.Metric

m1 := allMetrics[0]
r.NoError(m1.Write(&encodedMetric))
r.Equal(float64(1420687622144), *encodedMetric.Gauge.Value)

m2 := allMetrics[1]
r.NoError(m2.Write(&encodedMetric))
r.Equal(float64(1), *encodedMetric.Gauge.Value)

m3 := allMetrics[2]
r.NoError(m3.Write(&encodedMetric))
r.Equal(float64(1602378123), *encodedMetric.Gauge.Value)

m4 := allMetrics[3]
r.NoError(m4.Write(&encodedMetric))
r.Equal(float64(0), *encodedMetric.Gauge.Value)

m5 := allMetrics[4]
r.NoError(m5.Write(&encodedMetric))
r.Equal(float64(1), *encodedMetric.Gauge.Value)
label := encodedMetric.GetLabel()[0]
r.Equal("name", label.GetName())
r.Equal("m1", label.GetValue())
}

func TestStartPrometheusCollector(t *testing.T) {
StartCollector(&testServiceHealth{}, 9107)
StartCollector(&testServiceHealth{}, testMetricKinds, 9107)
}
12 changes: 0 additions & 12 deletions services/components/prometheus/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,3 @@ func parseReportValue(report *health.Report) (value float64) {
}
return
}

func sinceUnixTs(numStr string) float64 {
num, err := strconv.ParseFloat(numStr, 64)
if err != nil {
return 0
}
if num == 0 {
return 0
}
since := time.Since(time.Unix(int64(num), 0))
return since.Round(time.Second).Seconds()
}
88 changes: 88 additions & 0 deletions services/components/prometheus/value_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package prometheus

import (
"testing"
"time"

"github.com/forta-network/forta-core-go/clients/health"
"github.com/stretchr/testify/require"
)

func TestParseReportValue(t *testing.T) {
testCases := []struct {
report *health.Report
expectedResult float64
approximate bool
}{
{
report: &health.Report{
Name: "foo.service.bar.m1",
Status: health.StatusOK,
Details: "1420687622144",
},
expectedResult: 1420687622144,
},
{
report: &health.Report{
Name: "foo.service.bar.m2",
Status: health.StatusOK,
Details: "true",
},
expectedResult: 1,
},
{
report: &health.Report{
Name: "foo.service.bar.m3",
Status: health.StatusOK,
Details: time.Now().Add(time.Second * -10).Format(time.RFC3339),
},
expectedResult: 10,
approximate: true,
},
{
report: &health.Report{
Name: "foo.service.bar.m4",
Status: health.StatusOK,
Details: "message 1",
},
expectedResult: 0,
},
{
report: &health.Report{
Name: "foo.service.bar.m5",
Status: health.StatusFailing,
Details: "message 2",
},
expectedResult: 1,
},
{
report: &health.Report{
Name: "skipped-invalid-name-pattern",
Status: health.StatusFailing,
Details: "message X",
},
expectedResult: 1,
},
{
report: &health.Report{
Name: "foo.service.skipped-single-name",
Status: health.StatusFailing,
Details: "message Y",
},
expectedResult: 1,
},
}

for _, testCase := range testCases {
t.Run(testCase.report.Name, func(t *testing.T) {
r := require.New(t)

result := parseReportValue(testCase.report)
if testCase.approximate {
r.InEpsilon(testCase.expectedResult, result, 0.5)
} else {
r.Equal(testCase.expectedResult, result)
}
})
}
}
2 changes: 1 addition & 1 deletion services/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func (runner *Runner) Start() error {

go runner.keepContainersAlive()

prometheus.StartCollector(runner, runner.cfg.PrometheusConfig.Port)
prometheus.StartCollector(runner, nil, runner.cfg.PrometheusConfig.Port)

return nil
}
Expand Down

0 comments on commit c61d8d1

Please sign in to comment.