github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/api/api_key_test.go (about) 1 package api_test 2 3 import ( 4 "context" 5 "net/http" 6 "net/http/httptest" 7 "time" 8 9 "github.com/golang/mock/gomock" 10 "github.com/hashicorp/go-multierror" 11 . "github.com/onsi/ginkgo/v2" 12 . "github.com/onsi/gomega" 13 "github.com/sirupsen/logrus" 14 15 "github.com/pyroscope-io/pyroscope/pkg/api/mocks" 16 "github.com/pyroscope-io/pyroscope/pkg/api/router" 17 "github.com/pyroscope-io/pyroscope/pkg/model" 18 ) 19 20 var _ = Describe("APIKeyHandler", func() { 21 defer GinkgoRecover() 22 23 var ( 24 // Mocks setup. 25 ctrl *gomock.Controller 26 server *httptest.Server 27 m *mocks.MockAPIKeyService 28 29 // Default configuration for all scenarios. 30 method, url string 31 ) 32 33 BeforeEach(func() { 34 ctrl = gomock.NewController(GinkgoT()) 35 m = mocks.NewMockAPIKeyService(ctrl) 36 server = httptest.NewServer(newTestRouter(defaultUserCtx, router.Services{ 37 Logger: logrus.StandardLogger(), 38 APIKeyService: m, 39 })) 40 }) 41 42 AfterEach(func() { 43 ctrl.Finish() 44 server.Close() 45 }) 46 47 Describe("create API key", func() { 48 var ( 49 // Expected params passed to the mocked API key service. 50 expectedParams model.CreateAPIKeyParams 51 // API key and JWT token string returned by mocked service. 52 expectedAPIKey model.APIKey 53 expectedSecret string 54 ) 55 56 BeforeEach(func() { 57 // Defaults for all "create API key" scenarios. 58 method = http.MethodPost 59 url = server.URL + "/keys" 60 61 // Note that the actual ExpiresAt is populated during the handler execution 62 // and it is relative to time.Now(). Therefore use this mather to evaluate 63 // the actual expiration time: BeTemporally("~", time.Now(), time.Minute). 64 now := time.Date(2021, 12, 10, 4, 14, 0, 0, time.UTC) 65 expiresAt := now.Add(time.Minute) 66 67 expectedSecret = "secret-string" 68 expectedParams = model.CreateAPIKeyParams{ 69 Name: "some-api-key", 70 Role: model.ReadOnlyRole, 71 ExpiresAt: &expiresAt, 72 } 73 74 expectedAPIKey = model.APIKey{ 75 ID: 1, 76 Name: expectedParams.Name, 77 Role: expectedParams.Role, 78 ExpiresAt: expectedParams.ExpiresAt, 79 LastSeenAt: nil, 80 CreatedAt: now, 81 } 82 }) 83 84 Context("when request is complete and valid", func() { 85 It("responds with created API key", func() { 86 m.EXPECT(). 87 CreateAPIKey(gomock.Any(), gomock.Any()). 88 Return(expectedAPIKey, expectedSecret, nil). 89 Do(func(_ context.Context, actual model.CreateAPIKeyParams) { 90 defer GinkgoRecover() 91 Expect(*actual.ExpiresAt).To(BeTemporally("~", time.Now(), time.Minute)) 92 Expect(actual.Name).To(Equal(expectedParams.Name)) 93 Expect(actual.Role).To(Equal(expectedParams.Role)) 94 }) 95 96 expectResponse(newRequest(method, url, 97 "api_key/create_request.json"), 98 "api_key/create_response.json", 99 http.StatusCreated) 100 }) 101 }) 102 103 Context("when api key ttl is not specified", func() { 104 It("responds with created API key", func() { 105 expectedParams.ExpiresAt = nil 106 expectedAPIKey.ExpiresAt = nil 107 108 m.EXPECT(). 109 CreateAPIKey(gomock.Any(), expectedParams). 110 Return(expectedAPIKey, expectedSecret, nil) 111 112 expectResponse(newRequest(method, url, 113 "api_key/create_request_wo_ttl.json"), 114 "api_key/create_response_wo_ttl.json", 115 http.StatusCreated) 116 }) 117 }) 118 119 Context("when the request does not meet requirements", func() { 120 It("returns validation errors", func() { 121 m.EXPECT(). 122 CreateAPIKey(gomock.Any(), model.CreateAPIKeyParams{}). 123 Return(model.APIKey{}, "", &multierror.Error{Errors: []error{ 124 model.ErrAPIKeyNameEmpty, 125 model.ErrRoleUnknown, 126 }}) 127 128 expectResponse(newRequest(method, url, 129 "request_empty_object.json"), 130 "api_key/create_response_invalid.json", 131 http.StatusBadRequest) 132 }) 133 }) 134 }) 135 })