Skip to content

Commit

Permalink
Add tests for metrics post
Browse files Browse the repository at this point in the history
  • Loading branch information
Gergely Bekesi committed Jan 3, 2019
1 parent ddcae6f commit 93bcd53
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 21 deletions.
6 changes: 6 additions & 0 deletions metrics/dogstatsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ const (
DogStatsDBuildCounterMetricName = "count_of_build_runs"
)

// DogStatsDInterface ...
type DogStatsDInterface interface {
Track(t Trackable, metricName string)
Close()
}

// DogStatsDMetrics ...
type DogStatsDMetrics struct {
client *statsd.Client
Expand Down
17 changes: 8 additions & 9 deletions models/build_analytics.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
package models

import (
"encoding/json"
"fmt"
"time"
)

// BuildAnalytics ...
type BuildAnalytics struct {
AppID string `json:"app_id"`
StackID string `json:"stack_id"`
Platform string `json:"platform"`
CLIVersion string `json:"cli_version"`
Status string `json:"status"`
StartTime time.Time `json:"start_time"`
Runtime time.Duration `json:"run_time"`
RawJSONData json.RawMessage `json:"raw_json_data"`
AppID string `json:"app_id"`
StackID string `json:"stack_id"`
Platform string `json:"platform"`
CLIVersion string `json:"cli_version"`
Status string `json:"status"`
StartTime time.Time `json:"start_time"`
Runtime time.Duration `json:"run_time"`

StepAnalytics []StepAnalytics `json:"step_analytics"`
}
Expand All @@ -30,6 +28,7 @@ func (a BuildAnalytics) GetTagArray() []string {
return []string{
fmt.Sprintf("app_id:%s", a.AppID),
fmt.Sprintf("stack_id:%s", a.StackID),
fmt.Sprintf("platform:%s", a.Platform),
fmt.Sprintf("cli_version:%s", a.CLIVersion),
fmt.Sprintf("status:%s", a.Status),
}
Expand Down
10 changes: 4 additions & 6 deletions models/step_analytics.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
package models

import (
"encoding/json"
"fmt"
"time"
)

// StepAnalytics ...
type StepAnalytics struct {
StepID string `json:"step_id"`
Status string `json:"status"`
StartTime time.Time `json:"start_time"`
Runtime time.Duration `json:"run_time"`
RawJSONData json.RawMessage `json:"raw_json_data"`
StepID string `json:"step_id"`
Status string `json:"status"`
StartTime time.Time `json:"start_time"`
Runtime time.Duration `json:"run_time"`
}

// GetProfileName ...
Expand Down
4 changes: 3 additions & 1 deletion router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/bitrise-io/api-utils/httpresponse"
"github.com/bitrise-team/bitrise-step-analytics/configs"
"github.com/bitrise-team/bitrise-step-analytics/metrics"
"github.com/bitrise-team/bitrise-step-analytics/service"
"go.uber.org/zap"
"gopkg.in/DataDog/dd-trace-go.v1/contrib/gorilla/mux"
Expand All @@ -19,7 +20,8 @@ func New(config configs.ConfigModel) *mux.Router {
}

middlewareProvider := service.MiddlewareProvider{
LoggerProvider: service.NewLoggerProvider(logger),
LoggerProvider: service.NewLoggerProvider(logger),
DogStatsDMetrics: metrics.NewDogStatsDMetrics(""),
}

r.Handle("/", middlewareProvider.CommonMiddleware().ThenFunc(service.RootHandler))
Expand Down
18 changes: 18 additions & 0 deletions service/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ package service
import (
"context"
"errors"

"github.com/bitrise-team/bitrise-step-analytics/metrics"
)

type tRequestContextKey string

const (
// ContextKeyLoggerProvider ...
ContextKeyLoggerProvider tRequestContextKey = "rck-logger-provider"
// ContextKeyDogStatsDMetrics ...
ContextKeyDogStatsDMetrics tRequestContextKey = "rck-dogstatsd-metrics"
)

// GetLoggerProviderFromContext ...
Expand All @@ -25,3 +29,17 @@ func GetLoggerProviderFromContext(ctx context.Context) (LoggerInterface, error)
func ContextWithLoggerProvider(ctx context.Context, lp LoggerInterface) context.Context {
return context.WithValue(ctx, ContextKeyLoggerProvider, lp)
}

// GetDogStatsDMetricsFromContext ...
func GetDogStatsDMetricsFromContext(ctx context.Context) (metrics.DogStatsDInterface, error) {
dsdi, ok := ctx.Value(ContextKeyDogStatsDMetrics).(metrics.DogStatsDInterface)
if !ok {
return dsdi, errors.New("DogStatsD not found in Context")
}
return dsdi, nil
}

// ContextWithDogStatsDMetrics ...
func ContextWithDogStatsDMetrics(ctx context.Context, dsdi metrics.DogStatsDInterface) context.Context {
return context.WithValue(ctx, ContextKeyDogStatsDMetrics, dsdi)
}
5 changes: 3 additions & 2 deletions service/custom_logs_post_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import (

func Test_CustomLogsPostHandler(t *testing.T) {
handler := service.CustomLogsPostHandler
core, recorded := observer.New(zapcore.InfoLevel)
zl := zap.New(core)

for _, tc := range []struct {
testName string
Expand Down Expand Up @@ -46,6 +44,9 @@ func Test_CustomLogsPostHandler(t *testing.T) {
},
} {
t.Run(tc.testName, func(t *testing.T) {
core, recorded := observer.New(zapcore.InfoLevel)
zl := zap.New(core)

r, err := http.NewRequest("POST", "/logs", bytes.NewBuffer([]byte(tc.requestBody)))
require.NoError(t, err)

Expand Down
9 changes: 9 additions & 0 deletions service/dog_statsd_metrics_for_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package service_test

import "github.com/bitrise-team/bitrise-step-analytics/metrics"

type testDogStatsdMetrics struct{}

func (m *testDogStatsdMetrics) Track(t metrics.Trackable, metricName string) {}

func (m *testDogStatsdMetrics) Close() {}
12 changes: 10 additions & 2 deletions service/metrics_post.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,29 @@ package service
import (
"encoding/json"
"net/http"
"reflect"

"github.com/bitrise-io/api-utils/httpresponse"
"github.com/bitrise-team/bitrise-step-analytics/metrics"
"github.com/bitrise-team/bitrise-step-analytics/models"
"github.com/pkg/errors"
)

// MetricsPostHandler ...
func MetricsPostHandler(w http.ResponseWriter, r *http.Request) error {
buildAnalytics := models.BuildAnalytics{}
var buildAnalytics models.BuildAnalytics
defer httpresponse.RequestBodyCloseWithErrorLog(r)
if err := json.NewDecoder(r.Body).Decode(&buildAnalytics); err != nil {
return httpresponse.RespondWithBadRequestError(w, "Invalid request body, JSON decode failed")
}

dogstatsd := metrics.NewDogStatsDMetrics("")
if reflect.DeepEqual(buildAnalytics, models.BuildAnalytics{}) {
return httpresponse.RespondWithBadRequestError(w, "Invalid request body, please provide metrics data")
}
dogstatsd, err := GetDogStatsDMetricsFromContext(r.Context())
if err != nil {
return errors.WithStack(err)
}

dogstatsd.Track(buildAnalytics, metrics.DogStatsDBuildCounterMetricName)
for _, aStepAnalytic := range buildAnalytics.StepAnalytics {
Expand Down
73 changes: 73 additions & 0 deletions service/metrics_post_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package service_test

import (
"bytes"
"net/http"
"net/http/httptest"
"testing"

"github.com/bitrise-team/bitrise-step-analytics/service"
"github.com/stretchr/testify/require"
)

func Test_MetricsPostHandler(t *testing.T) {
handler := service.MetricsPostHandler

for _, tc := range []struct {
testName string
requestBody string
expectedInternalErr string
expectedBody string
expectedLogContent map[string]interface{}
expectedStatusCode int
}{
{
testName: "ok, minimal",
requestBody: `{` +
`"app_id":"app-slug","stack_id":"standard1","platform":"ios","cli_version":"1.21","status":"success","start_time":"2019-01-03T18:11:53.171409Z","run_time":121` +
`,"step_analytics":[` +
`{"step_id":"deploy_to_bitrise_io","status":"0","start_time":"2019-01-03T18:11:53.171409Z","run_time":120}` +
`,{"step_id":"script","status":"0","start_time":"2019-01-03T18:11:53.171409Z","run_time":210}` +
`]` +
`}`,
expectedStatusCode: http.StatusOK,
expectedBody: `{"message":"ok"}` + "\n",
},
{
testName: "when no request body provided",
expectedStatusCode: http.StatusBadRequest,
expectedBody: `{"message":"Invalid request body, JSON decode failed"}` + "\n",
},
{
testName: "when no metrics data provided",
requestBody: `{}`,
expectedStatusCode: http.StatusBadRequest,
expectedBody: `{"message":"Invalid request body, please provide metrics data"}` + "\n",
},
} {
t.Run(tc.testName, func(t *testing.T) {
r, err := http.NewRequest("POST", "/metrics", bytes.NewBuffer([]byte(tc.requestBody)))
require.NoError(t, err)

r = r.WithContext(service.ContextWithDogStatsDMetrics(r.Context(), &testDogStatsdMetrics{}))

rr := httptest.NewRecorder()
internalServerError := handler(rr, r)

if tc.expectedBody != "" {
require.Equal(t, tc.expectedBody, rr.Body.String())
}

if tc.expectedInternalErr != "" {
require.EqualError(t, internalServerError, tc.expectedInternalErr,
"Expected internal err: %s | Request Body: %s | Response Code: %d, Expected Response Body: %s | Got Body: %s", tc.expectedInternalErr, tc.requestBody, rr.Code, tc.expectedBody, rr.Body.String())
} else {
require.NoError(t, internalServerError)
if tc.expectedStatusCode != 0 {
require.Equal(t, tc.expectedStatusCode, rr.Code,
"Expected body: %s | Got body: %s", tc.expectedBody, rr.Body.String())
}
}
})
}
}
20 changes: 19 additions & 1 deletion service/middlewares.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ package service
import (
"net/http"

"github.com/bitrise-team/bitrise-step-analytics/metrics"
"github.com/justinas/alice"
"github.com/rs/cors"
)

// MiddlewareProvider ...
type MiddlewareProvider struct {
LoggerProvider LoggerInterface
LoggerProvider LoggerInterface
DogStatsDMetrics metrics.DogStatsDInterface
}

func createSetLoggerProviderMiddleware(loggerProvider LoggerInterface) func(http.Handler) http.Handler {
Expand All @@ -21,6 +23,15 @@ func createSetLoggerProviderMiddleware(loggerProvider LoggerInterface) func(http
}
}

func createSetDogStatsDMetricsMiddleware(dogStatsDMetrics metrics.DogStatsDInterface) func(http.Handler) http.Handler {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := ContextWithDogStatsDMetrics(r.Context(), dogStatsDMetrics)
h.ServeHTTP(w, r.WithContext(ctx))
})
}
}

// CommonMiddleware ...
func (m MiddlewareProvider) CommonMiddleware() alice.Chain {
return alice.New(
Expand All @@ -34,3 +45,10 @@ func (m MiddlewareProvider) MiddlewareWithLoggerProvider() alice.Chain {
createSetLoggerProviderMiddleware(m.LoggerProvider),
)
}

// MiddlewareWithDogStatsDMetrics ...
func (m MiddlewareProvider) MiddlewareWithDogStatsDMetrics() alice.Chain {
return m.CommonMiddleware().Append(
createSetDogStatsDMetricsMiddleware(m.DogStatsDMetrics),
)
}

0 comments on commit 93bcd53

Please sign in to comment.