github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/api/user_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("UserHandler", func() { 21 defer GinkgoRecover() 22 23 var ( 24 // Mocks setup. 25 ctrl *gomock.Controller 26 server *httptest.Server 27 m *mocks.MockUserService 28 29 // Default configuration for all scenarios. 30 method, url string 31 ) 32 33 BeforeEach(func() { 34 ctrl = gomock.NewController(GinkgoT()) 35 m = mocks.NewMockUserService(ctrl) 36 server = httptest.NewServer(newTestRouter(defaultUserCtx, router.Services{ 37 Logger: logrus.StandardLogger(), 38 UserService: m, 39 })) 40 }) 41 42 AfterEach(func() { 43 ctrl.Finish() 44 server.Close() 45 }) 46 47 Describe("create user", func() { 48 var ( 49 // Expected params passed to the mocked user service. 50 expectedParams model.CreateUserParams 51 // user returned by mocked service. 52 expectedUser model.User 53 ) 54 55 BeforeEach(func() { 56 // Defaults for all "create user" scenarios. 57 method = http.MethodPost 58 url = server.URL + "/users" 59 60 expectedParams = model.CreateUserParams{ 61 Name: "johndoe", 62 Email: model.String("john@example.com"), 63 FullName: model.String("John Doe"), 64 Password: "qwerty", 65 Role: model.ReadOnlyRole, 66 } 67 68 now := time.Date(2021, 12, 10, 4, 14, 0, 0, time.UTC) 69 expectedUser = model.User{ 70 ID: 1, 71 Name: expectedParams.Name, 72 Email: expectedParams.Email, 73 FullName: expectedParams.FullName, 74 Role: expectedParams.Role, 75 PasswordHash: model.MustPasswordHash(expectedParams.Password), 76 PasswordChangedAt: now, 77 CreatedAt: now, 78 UpdatedAt: now, 79 } 80 }) 81 82 Context("when request is complete and valid", func() { 83 It("responds with created user", func() { 84 m.EXPECT(). 85 CreateUser(gomock.Any(), gomock.Any()). 86 Return(expectedUser, nil). 87 Do(func(_ context.Context, actual model.CreateUserParams) { 88 defer GinkgoRecover() 89 Expect(actual).To(Equal(expectedParams)) 90 }) 91 92 expectResponse(newRequest(method, url, 93 "user/create_request.json"), 94 "user/create_response.json", 95 http.StatusCreated) 96 }) 97 }) 98 99 Context("when user full name is not specified", func() { 100 It("responds with created user", func() { 101 expectedParams.FullName = nil 102 expectedUser.FullName = nil 103 104 m.EXPECT(). 105 CreateUser(gomock.Any(), gomock.Any()). 106 Return(expectedUser, nil). 107 Do(func(_ context.Context, actual model.CreateUserParams) { 108 defer GinkgoRecover() 109 Expect(actual).To(Equal(expectedParams)) 110 }) 111 112 expectResponse(newRequest(method, url, 113 "user/create_request_wo_full_name.json"), 114 "user/create_response_wo_full_name.json", 115 http.StatusCreated) 116 }) 117 }) 118 119 Context("when email already exists", func() { 120 It("returns ErrUserEmailExists error", func() { 121 m.EXPECT(). 122 CreateUser(gomock.Any(), gomock.Any()). 123 Return(model.User{}, &multierror.Error{Errors: []error{ 124 model.ErrUserEmailExists, 125 }}). 126 Do(func(_ context.Context, actual model.CreateUserParams) { 127 defer GinkgoRecover() 128 Expect(actual).To(Equal(expectedParams)) 129 }) 130 131 expectResponse(newRequest(method, url, 132 "user/create_request.json"), 133 "user/create_response_email_exists.json", 134 http.StatusBadRequest) 135 }) 136 }) 137 138 Context("when user name already exists", func() { 139 It("returns ErrUserNameExists error", func() { 140 m.EXPECT(). 141 CreateUser(gomock.Any(), gomock.Any()). 142 Return(model.User{}, &multierror.Error{Errors: []error{ 143 model.ErrUserNameExists, 144 }}). 145 Do(func(_ context.Context, actual model.CreateUserParams) { 146 defer GinkgoRecover() 147 Expect(actual).To(Equal(expectedParams)) 148 }) 149 150 expectResponse(newRequest(method, url, 151 "user/create_request.json"), 152 "user/create_response_user_name_exists.json", 153 http.StatusBadRequest) 154 }) 155 }) 156 157 Context("when request does not meet requirements", func() { 158 It("returns validation errors", func() { 159 m.EXPECT(). 160 CreateUser(gomock.Any(), gomock.Any()). 161 Return(model.User{}, &multierror.Error{Errors: []error{ 162 model.ErrUserNameEmpty, 163 model.ErrUserEmailInvalid, 164 model.ErrUserPasswordEmpty, 165 model.ErrRoleUnknown, 166 }}). 167 Do(func(_ context.Context, user model.CreateUserParams) { 168 defer GinkgoRecover() 169 Expect(user).To(BeZero()) 170 }) 171 172 expectResponse(newRequest(method, url, 173 "request_empty_object.json"), 174 "user/create_response_invalid.json", 175 http.StatusBadRequest) 176 }) 177 }) 178 179 Context("when request body malformed", func() { 180 It("returns error and does not call user service", func() { 181 m.EXPECT(). 182 CreateUser(gomock.Any(), gomock.Any()). 183 Times(0) 184 185 expectResponse(newRequest(method, url, 186 "request_malformed_json"), 187 "response_malformed_request_body.json", 188 http.StatusBadRequest) 189 }) 190 }) 191 192 Context("when request has empty body", func() { 193 It("returns error and does not call user service", func() { 194 m.EXPECT(). 195 CreateUser(gomock.Any(), gomock.Any()). 196 Times(0) 197 198 expectResponse(newRequest(method, url, 199 ""), // No request body. 200 "response_empty_request_body.json", 201 http.StatusBadRequest) 202 }) 203 }) 204 }) 205 })