github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/service/api_key_test.go (about) 1 package service_test 2 3 import ( 4 "context" 5 "time" 6 7 . "github.com/onsi/ginkgo/v2" 8 . "github.com/onsi/gomega" 9 10 "github.com/pyroscope-io/pyroscope/pkg/model" 11 "github.com/pyroscope-io/pyroscope/pkg/service" 12 ) 13 14 var _ = Describe("APIKeyService", func() { 15 s := new(testSuite) 16 BeforeEach(s.BeforeEach) 17 AfterEach(s.AfterEach) 18 19 var svc service.APIKeyService 20 BeforeEach(func() { 21 svc = service.NewAPIKeyService(s.DB(), 0) 22 }) 23 24 Describe("API key creation", func() { 25 var ( 26 params = testCreateAPIKeyParams() 27 apiKey model.APIKey 28 key string 29 err error 30 ) 31 32 JustBeforeEach(func() { 33 apiKey, key, err = svc.CreateAPIKey(context.Background(), params) 34 }) 35 36 Context("when a new API key created", func() { 37 It("does not return error", func() { 38 Expect(err).ToNot(HaveOccurred()) 39 }) 40 41 It("should populate the fields correctly", func() { 42 expectAPIKeyMatches(apiKey, params) 43 }) 44 45 It("creates a valid secret", func() { 46 id, secret, err := model.DecodeAPIKey(key) 47 Expect(err).ToNot(HaveOccurred()) 48 Expect(id).To(Equal(apiKey.ID)) 49 Expect(apiKey.Verify(secret)).ToNot(HaveOccurred()) 50 }) 51 }) 52 53 Context("when API key name is already in use", func() { 54 BeforeEach(func() { 55 _, _, err = svc.CreateAPIKey(context.Background(), params) 56 Expect(err).ToNot(HaveOccurred()) 57 }) 58 59 It("returns validation error", func() { 60 Expect(model.IsValidationError(err)).To(BeTrue()) 61 }) 62 }) 63 64 Context("when parameters are invalid", func() { 65 BeforeEach(func() { 66 params = model.CreateAPIKeyParams{} 67 }) 68 69 It("returns validation error", func() { 70 Expect(model.IsValidationError(err)).To(BeTrue()) 71 }) 72 }) 73 }) 74 75 Describe("API key retrieval", func() { 76 Context("when an existing API key is queried", func() { 77 It("can be found by id", func() { 78 params := testCreateAPIKeyParams() 79 k, _, err := svc.CreateAPIKey(context.Background(), params) 80 Expect(err).ToNot(HaveOccurred()) 81 actual, err := svc.FindAPIKeyByID(context.Background(), k.ID) 82 Expect(err).ToNot(HaveOccurred()) 83 expectAPIKeyMatches(actual, params) 84 }) 85 }) 86 87 Context("when a non-existing API key is queried", func() { 88 It("returns ErrAPIKeyNotFound error of NotFoundError type", func() { 89 _, err := svc.FindAPIKeyByID(context.Background(), 13) 90 Expect(err).To(MatchError(model.ErrAPIKeyNotFound)) 91 }) 92 }) 93 }) 94 95 Describe("API keys retrieval", func() { 96 var ( 97 params = []model.CreateAPIKeyParams{ 98 {Name: "key-a", Role: model.AdminRole}, 99 {Name: "key-b", Role: model.ReadOnlyRole}, 100 } 101 apiKeys []model.APIKey 102 err error 103 ) 104 105 JustBeforeEach(func() { 106 apiKeys, err = svc.GetAllAPIKeys(context.Background()) 107 }) 108 109 Context("when all API keys are queried", func() { 110 BeforeEach(func() { 111 for _, user := range params { 112 _, _, err = svc.CreateAPIKey(context.Background(), user) 113 Expect(err).ToNot(HaveOccurred()) 114 } 115 }) 116 117 It("does not return error", func() { 118 Expect(err).ToNot(HaveOccurred()) 119 }) 120 121 It("returns all keys", func() { 122 apiKeyA, err := svc.FindAPIKeyByName(context.Background(), params[0].Name) 123 Expect(err).ToNot(HaveOccurred()) 124 apiKeyB, err := svc.FindAPIKeyByName(context.Background(), params[1].Name) 125 Expect(err).ToNot(HaveOccurred()) 126 Expect(apiKeys).To(ConsistOf(apiKeyA, apiKeyB)) 127 }) 128 }) 129 130 Context("when no API keys exist", func() { 131 It("returns no error", func() { 132 Expect(err).ToNot(HaveOccurred()) 133 Expect(apiKeys).To(BeEmpty()) 134 }) 135 }) 136 }) 137 138 Describe("API key delete", func() { 139 var ( 140 params = []model.CreateAPIKeyParams{ 141 {Name: "key-a", Role: model.AdminRole}, 142 {Name: "key-b", Role: model.ReadOnlyRole}, 143 } 144 apiKeys []model.APIKey 145 err error 146 ) 147 148 JustBeforeEach(func() { 149 err = svc.DeleteAPIKeyByID(context.Background(), apiKeys[0].ID) 150 }) 151 152 Context("when existing API key deleted", func() { 153 BeforeEach(func() { 154 apiKeys = apiKeys[:0] 155 for _, p := range params { 156 apiKey, _, err := svc.CreateAPIKey(context.Background(), p) 157 Expect(err).ToNot(HaveOccurred()) 158 apiKeys = append(apiKeys, apiKey) 159 } 160 }) 161 162 It("does not return error", func() { 163 Expect(err).ToNot(HaveOccurred()) 164 }) 165 166 It("removes API key from the database", func() { 167 _, err = svc.FindAPIKeyByName(context.Background(), apiKeys[0].Name) 168 Expect(err).To(MatchError(model.ErrAPIKeyNotFound)) 169 }) 170 171 It("does not affect other API keys", func() { 172 _, err = svc.FindAPIKeyByName(context.Background(), apiKeys[1].Name) 173 Expect(err).ToNot(HaveOccurred()) 174 }) 175 176 It("allows API key with the same name to be created", func() { 177 _, _, err = svc.CreateAPIKey(context.Background(), params[0]) 178 Expect(err).ToNot(HaveOccurred()) 179 }) 180 }) 181 182 Context("when non-existing API key deleted", func() { 183 It("does not return error", func() { 184 Expect(err).ToNot(HaveOccurred()) 185 }) 186 }) 187 }) 188 }) 189 190 func testCreateAPIKeyParams() model.CreateAPIKeyParams { 191 expiresAt := time.Date(3000, 12, 10, 4, 14, 0, 0, time.UTC) 192 return model.CreateAPIKeyParams{ 193 Name: "johndoe", 194 Role: model.ReadOnlyRole, 195 ExpiresAt: &expiresAt, 196 } 197 } 198 199 func expectAPIKeyMatches(apiKey model.APIKey, params model.CreateAPIKeyParams) { 200 Expect(apiKey.Name).To(Equal(params.Name)) 201 Expect(apiKey.Role).To(Equal(params.Role)) 202 Expect(apiKey.ExpiresAt).To(Equal(params.ExpiresAt)) 203 Expect(apiKey.CreatedAt).ToNot(BeZero()) 204 Expect(apiKey.LastSeenAt).To(BeZero()) 205 }