blob: e604e0f76edae7512534f57fbb05fe505ce1af8a [file] [log] [blame]
package anomaly
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"go.skia.org/infra/perf/go/types"
)
func TestHandler_AbsoluteStep(t *testing.T) {
// A simple step up in the middle.
trace := []float32{
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 10
}
req := DetectRequest{
Trace: trace,
Radius: 5,
Threshold: 3.0,
Algorithm: types.AbsoluteStep,
GroupAnomalies: true,
}
body, err := json.Marshal(req)
assert.NoError(t, err)
r := httptest.NewRequest("POST", "/_/playground/anomaly/v1/detect", bytes.NewBuffer(body))
w := httptest.NewRecorder()
Handler(w, r)
resp := w.Result()
assert.Equal(t, http.StatusOK, resp.StatusCode)
var detectResp DetectResponse
err = json.NewDecoder(resp.Body).Decode(&detectResp)
assert.NoError(t, err)
assert.NotEmpty(t, detectResp.Anomalies)
if len(detectResp.Anomalies) > 0 {
a := detectResp.Anomalies[0]
assert.Equal(t, 10, a.StartRevision)
assert.Equal(t, "untriaged", a.State)
}
}
func TestHandler_NoAnomaly(t *testing.T) {
// Flat trace
trace := []float32{
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
}
req := DetectRequest{
Trace: trace,
Radius: 5,
Threshold: 3.0,
Algorithm: types.OriginalStep,
}
body, err := json.Marshal(req)
assert.NoError(t, err)
r := httptest.NewRequest("POST", "/_/playground/anomaly/v1/detect", bytes.NewBuffer(body))
w := httptest.NewRecorder()
Handler(w, r)
resp := w.Result()
assert.Equal(t, http.StatusOK, resp.StatusCode)
var detectResp DetectResponse
err = json.NewDecoder(resp.Body).Decode(&detectResp)
assert.NoError(t, err)
assert.Empty(t, detectResp.Anomalies)
}
func TestHandler_MultipleAnomalies(t *testing.T) {
// Step up then step down.
trace := []float32{
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0-9
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 10-19 (Step up at 10)
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 20-29 (Step down at 20)
}
req := DetectRequest{
Trace: trace,
Radius: 3, // Smaller radius to avoid overlapping windows merging too much
Threshold: 2.0,
Algorithm: types.OriginalStep,
GroupAnomalies: true,
}
body, err := json.Marshal(req)
assert.NoError(t, err)
r := httptest.NewRequest("POST", "/_/playground/anomaly/v1/detect", bytes.NewBuffer(body))
w := httptest.NewRecorder()
Handler(w, r)
resp := w.Result()
assert.Equal(t, http.StatusOK, resp.StatusCode)
var detectResp DetectResponse
err = json.NewDecoder(resp.Body).Decode(&detectResp)
assert.NoError(t, err)
// Should have at least 2 anomalies.
assert.True(t, len(detectResp.Anomalies) >= 2, "Expected at least 2 anomalies, got %d", len(detectResp.Anomalies))
}
func TestHandler_BadRequest(t *testing.T) {
r := httptest.NewRequest("POST", "/_/playground/anomaly/v1/detect", bytes.NewBufferString("invalid json"))
w := httptest.NewRecorder()
Handler(w, r)
assert.Equal(t, http.StatusBadRequest, w.Result().StatusCode)
}
func TestHandler_ShortTrace(t *testing.T) {
trace := []float32{1, 5}
req := DetectRequest{
Trace: trace,
Radius: 5,
Threshold: 3.0,
Algorithm: types.OriginalStep,
}
body, err := json.Marshal(req)
assert.NoError(t, err)
r := httptest.NewRequest("POST", "/_/playground/anomaly/v1/detect", bytes.NewBuffer(body))
w := httptest.NewRecorder()
Handler(w, r)
resp := w.Result()
assert.Equal(t, http.StatusOK, resp.StatusCode)
var detectResp DetectResponse
err = json.NewDecoder(resp.Body).Decode(&detectResp)
assert.NoError(t, err)
assert.Empty(t, detectResp.Anomalies)
}