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  })