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