package transport import ( "encoding/json" "net/http" "testing" "time" "github.com/golang/mock/gomock" "github.com/influxdata/influxdb/v2" influxdbtesting "github.com/influxdata/influxdb/v2/testing" "github.com/stretchr/testify/require" ) var ( testCreateAnnotation = influxdb.AnnotationCreate{ StreamTag: "sometag", Summary: "testing the api", Message: "stored annotation message", Stickers: map[string]string{"val1": "sticker1", "val2": "sticker2"}, EndTime: &now, StartTime: &now, } testEvent = influxdb.AnnotationEvent{ ID: *id, AnnotationCreate: testCreateAnnotation, } testReadAnnotation1 = influxdb.ReadAnnotation{ ID: *influxdbtesting.IDPtr(1), } testReadAnnotation2 = influxdb.ReadAnnotation{ ID: *influxdbtesting.IDPtr(2), } testStoredAnnotation = influxdb.StoredAnnotation{ ID: *id, OrgID: *orgID, StreamID: *influxdbtesting.IDPtr(3), StreamTag: "sometag", Summary: "testing the api", Message: "stored annotation message", Stickers: map[string]string{"val1": "sticker1", "val2": "sticker2"}, Lower: now.Format(time.RFC3339), Upper: now.Format(time.RFC3339), } testReadAnnotations = influxdb.ReadAnnotations{ "sometag": []influxdb.ReadAnnotation{ { ID: testStoredAnnotation.ID, Summary: testStoredAnnotation.Summary, Message: testStoredAnnotation.Message, Stickers: map[string]string{"val1": "sticker1", "val2": "sticker2"}, EndTime: testStoredAnnotation.Lower, StartTime: testStoredAnnotation.Upper, }, }, } ) func TestAnnotationRouter(t *testing.T) { t.Parallel() t.Run("get annotations happy path", func(t *testing.T) { ts, svc := newTestServer(t) defer ts.Close() req := newTestRequest(t, "GET", ts.URL+"/annotations", nil) q := req.URL.Query() q.Add("orgID", orgStr) q.Add("endTime", now.Format(time.RFC3339)) q.Add("stickerIncludes[product]", "oss") q.Add("stickerIncludes[env]", "dev") q.Add("streamIncludes", "stream1") q.Add("streamIncludes", "stream2") req.URL.RawQuery = q.Encode() want := []influxdb.AnnotationList{ { StreamTag: "stream1", Annotations: []influxdb.ReadAnnotation{testReadAnnotation1}, }, { StreamTag: "stream2", Annotations: []influxdb.ReadAnnotation{testReadAnnotation2}, }, } svc.EXPECT(). ListAnnotations(gomock.Any(), *orgID, influxdb.AnnotationListFilter{ StickerIncludes: map[string]string{"product": "oss", "env": "dev"}, StreamIncludes: []string{"stream1", "stream2"}, BasicFilter: influxdb.BasicFilter{ StartTime: &time.Time{}, EndTime: &now, }, }). Return([]influxdb.StoredAnnotation{ { ID: testReadAnnotation1.ID, StreamTag: "stream1", }, { ID: testReadAnnotation2.ID, StreamTag: "stream2", }, }, nil) res := doTestRequest(t, req, http.StatusOK, true) got := []influxdb.AnnotationList{} err := json.NewDecoder(res.Body).Decode(&got) require.NoError(t, err) require.ElementsMatch(t, want, got) }) t.Run("create annotations happy path", func(t *testing.T) { ts, svc := newTestServer(t) defer ts.Close() createAnnotations := []influxdb.AnnotationCreate{testCreateAnnotation} req := newTestRequest(t, "POST", ts.URL+"/annotations", createAnnotations) q := req.URL.Query() q.Add("orgID", orgStr) req.URL.RawQuery = q.Encode() want := []influxdb.AnnotationEvent{testEvent} svc.EXPECT(). CreateAnnotations(gomock.Any(), *orgID, createAnnotations). Return(want, nil) res := doTestRequest(t, req, http.StatusOK, true) got := []influxdb.AnnotationEvent{} err := json.NewDecoder(res.Body).Decode(&got) require.NoError(t, err) require.Equal(t, want, got) }) t.Run("delete annotations happy path", func(t *testing.T) { ts, svc := newTestServer(t) defer ts.Close() req := newTestRequest(t, "DELETE", ts.URL+"/annotations", nil) q := req.URL.Query() q.Add("orgID", orgStr) q.Add("stream", "someTag") q.Add("startTime", now.Format(time.RFC3339)) q.Add("endTime", later.Format(time.RFC3339)) req.URL.RawQuery = q.Encode() svc.EXPECT(). DeleteAnnotations(gomock.Any(), *orgID, influxdb.AnnotationDeleteFilter{ StreamTag: "someTag", StartTime: &now, EndTime: &later, Stickers: map[string]string{}, }). Return(nil) doTestRequest(t, req, http.StatusNoContent, false) }) t.Run("get annotation happy path", func(t *testing.T) { ts, svc := newTestServer(t) defer ts.Close() req := newTestRequest(t, "GET", ts.URL+"/annotations/"+idStr, nil) svc.EXPECT(). GetAnnotation(gomock.Any(), *id). Return(&testStoredAnnotation, nil) res := doTestRequest(t, req, http.StatusOK, true) got := &influxdb.AnnotationEvent{} err := json.NewDecoder(res.Body).Decode(got) require.NoError(t, err) require.Equal(t, &testEvent, got) }) t.Run("delete annotation happy path", func(t *testing.T) { ts, svc := newTestServer(t) defer ts.Close() req := newTestRequest(t, "DELETE", ts.URL+"/annotations/"+idStr, nil) svc.EXPECT(). DeleteAnnotation(gomock.Any(), *id). Return(nil) doTestRequest(t, req, http.StatusNoContent, false) }) t.Run("update annotation happy path", func(t *testing.T) { ts, svc := newTestServer(t) defer ts.Close() req := newTestRequest(t, "PUT", ts.URL+"/annotations/"+idStr, testCreateAnnotation) svc.EXPECT(). UpdateAnnotation(gomock.Any(), *id, testCreateAnnotation). Return(&testEvent, nil) res := doTestRequest(t, req, http.StatusOK, true) got := &influxdb.AnnotationEvent{} err := json.NewDecoder(res.Body).Decode(got) require.NoError(t, err) require.Equal(t, &testEvent, got) }) t.Run("invalid org ids return 400 when required", func(t *testing.T) { methods := []string{"POST", "GET", "DELETE"} for _, m := range methods { t.Run(m, func(t *testing.T) { ts, _ := newTestServer(t) defer ts.Close() req := newTestRequest(t, m, ts.URL+"/annotations", nil) q := req.URL.Query() q.Add("orgID", "badid") req.URL.RawQuery = q.Encode() doTestRequest(t, req, http.StatusBadRequest, false) }) } }) t.Run("invalid annotation ids return 400 when required", func(t *testing.T) { methods := []string{"GET", "DELETE", "PUT"} for _, m := range methods { t.Run(m, func(t *testing.T) { ts, _ := newTestServer(t) defer ts.Close() req := newTestRequest(t, m, ts.URL+"/annotations/badID", nil) doTestRequest(t, req, http.StatusBadRequest, false) }) } }) } func TestStoredAnnotationsToReadAnnotations(t *testing.T) { t.Parallel() got, err := storedAnnotationsToReadAnnotations([]influxdb.StoredAnnotation{testStoredAnnotation}) require.NoError(t, err) require.Equal(t, got, testReadAnnotations) } func TestStoredAnnotationToEvent(t *testing.T) { t.Parallel() got, err := storedAnnotationToEvent(&testStoredAnnotation) require.NoError(t, err) require.Equal(t, got, &testEvent) }