github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/api/annotation_test.go (about) 1 package api_test 2 3 import ( 4 "context" 5 "errors" 6 "net/http" 7 "net/http/httptest" 8 "time" 9 10 . "github.com/onsi/ginkgo/v2" 11 . "github.com/onsi/gomega" 12 "github.com/pyroscope-io/pyroscope/pkg/api/router" 13 "github.com/pyroscope-io/pyroscope/pkg/model" 14 "github.com/sirupsen/logrus" 15 ) 16 17 type mockService struct { 18 createAnnotationResponse func(params model.CreateAnnotation) (*model.Annotation, error) 19 } 20 21 func (m *mockService) CreateAnnotation(ctx context.Context, params model.CreateAnnotation) (*model.Annotation, error) { 22 return m.createAnnotationResponse(params) 23 } 24 25 func (m *mockService) FindAnnotationsByTimeRange(ctx context.Context, appName string, startTime time.Time, endTime time.Time) ([]model.Annotation, error) { 26 return []model.Annotation{}, nil 27 } 28 29 var _ = Describe("AnnotationHandler", func() { 30 var ( 31 server *httptest.Server 32 svc *mockService 33 ) 34 35 AfterEach(func() { 36 server.Close() 37 }) 38 39 Describe("create annotation", func() { 40 When("all parameters are set", func() { 41 BeforeEach(func() { 42 svc = &mockService{ 43 createAnnotationResponse: func(params model.CreateAnnotation) (*model.Annotation, error) { 44 return &model.Annotation{ 45 AppName: "myApp", 46 Content: "mycontent", 47 Timestamp: time.Unix(1662729099, 0), 48 }, nil 49 }, 50 } 51 52 server = httptest.NewServer(newTestRouter(defaultUserCtx, router.Services{ 53 Logger: logrus.StandardLogger(), 54 AnnotationsService: svc, 55 })) 56 }) 57 58 It("creates correctly", func() { 59 url := server.URL + "/annotations" 60 61 expectResponse(newRequest(http.MethodPost, url, 62 "annotation/create_request.json"), 63 "annotation/create_response.json", 64 http.StatusCreated) 65 }) 66 }) 67 68 When("timestamp is absent", func() { 69 It("it defaults to zero-value", func() { 70 svc = &mockService{ 71 createAnnotationResponse: func(params model.CreateAnnotation) (m *model.Annotation, err error) { 72 // The service should receive a zero timestamp 73 Expect(params.Timestamp.IsZero()).To(BeTrue()) 74 75 return &model.Annotation{ 76 AppName: "myApp", 77 Content: "mycontent", 78 Timestamp: time.Unix(1662729099, 0), 79 }, nil 80 }, 81 } 82 83 server = httptest.NewServer(newTestRouter(defaultUserCtx, router.Services{ 84 Logger: logrus.StandardLogger(), 85 AnnotationsService: svc, 86 })) 87 88 url := server.URL + "/annotations" 89 90 expectResponse(newRequest(http.MethodPost, url, 91 "annotation/create_request_no_timestamp.json"), 92 "annotation/create_response.json", 93 http.StatusCreated) 94 }) 95 }) 96 97 When("multiple appNames are passed", func() { 98 BeforeEach(func() { 99 svc = &mockService{ 100 createAnnotationResponse: func(params model.CreateAnnotation) (*model.Annotation, error) { 101 return &model.Annotation{ 102 AppName: params.AppName, 103 Content: "mycontent", 104 Timestamp: time.Unix(1662729099, 0), 105 }, nil 106 }, 107 } 108 109 server = httptest.NewServer(newTestRouter(defaultUserCtx, router.Services{ 110 Logger: logrus.StandardLogger(), 111 AnnotationsService: svc, 112 })) 113 }) 114 115 It("creates correctly", func() { 116 url := server.URL + "/annotations" 117 118 expectResponse(newRequest(http.MethodPost, url, 119 "annotation/create_multiple_request.json"), 120 "annotation/create_multiple_response.json", 121 http.StatusCreated) 122 }) 123 }) 124 125 When("fields are invalid", func() { 126 BeforeEach(func() { 127 svc = &mockService{ 128 createAnnotationResponse: func(params model.CreateAnnotation) (*model.Annotation, error) { 129 return nil, model.ValidationError{errors.New("myerror")} 130 }, 131 } 132 133 server = httptest.NewServer(newTestRouter(defaultUserCtx, router.Services{ 134 Logger: logrus.StandardLogger(), 135 AnnotationsService: svc, 136 })) 137 }) 138 It("returns an error", func() { 139 url := server.URL + "/annotations" 140 141 expectResponse(newRequest(http.MethodPost, url, 142 "annotation/create_request_error.json"), 143 "annotation/create_response_error.json", 144 http.StatusBadRequest) 145 }) 146 }) 147 148 When("both 'appName' and 'appNames' are passed", func() { 149 BeforeEach(func() { 150 svc = &mockService{ 151 createAnnotationResponse: func(params model.CreateAnnotation) (*model.Annotation, error) { 152 return nil, nil 153 }, 154 } 155 156 server = httptest.NewServer(newTestRouter(defaultUserCtx, router.Services{ 157 Logger: logrus.StandardLogger(), 158 AnnotationsService: svc, 159 })) 160 }) 161 It("returns an error", func() { 162 url := server.URL + "/annotations" 163 164 expectResponse(newRequest(http.MethodPost, url, 165 "annotation/create_request_appName_appNames_error.json"), 166 "annotation/create_response_appName_appNames_error.json", 167 http.StatusBadRequest) 168 }) 169 }) 170 171 When("none of 'appName' and 'appNames' are passed", func() { 172 BeforeEach(func() { 173 svc = &mockService{ 174 createAnnotationResponse: func(params model.CreateAnnotation) (*model.Annotation, error) { 175 return nil, nil 176 }, 177 } 178 179 server = httptest.NewServer(newTestRouter(defaultUserCtx, router.Services{ 180 Logger: logrus.StandardLogger(), 181 AnnotationsService: svc, 182 })) 183 }) 184 It("returns an error", func() { 185 url := server.URL + "/annotations" 186 187 expectResponse(newRequest(http.MethodPost, url, 188 "annotation/create_request_appName_appNames_empty_error.json"), 189 "annotation/create_response_appName_appNames_empty_error.json", 190 http.StatusBadRequest) 191 }) 192 }) 193 }) 194 })