You've already forked golang-saas-starter-kit
mirror of
https://github.com/raseels-repos/golang-saas-starter-kit.git
synced 2025-06-15 00:15:15 +02:00
Complated web-api crud endpoints and unittests. unittest for find
endpoints still need to be implemented.
This commit is contained in:
@ -22,6 +22,7 @@ type Project struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find godoc
|
// Find godoc
|
||||||
|
// TODO: Need to implement unittests on projects/find endpoint. There are none.
|
||||||
// @Summary List projects
|
// @Summary List projects
|
||||||
// @Description Find returns the existing projects in the system.
|
// @Description Find returns the existing projects in the system.
|
||||||
// @Tags project
|
// @Tags project
|
||||||
@ -275,7 +276,6 @@ func (p *Project) Update(ctx context.Context, w http.ResponseWriter, r *http.Req
|
|||||||
// @Success 204
|
// @Success 204
|
||||||
// @Failure 400 {object} web.ErrorResponse
|
// @Failure 400 {object} web.ErrorResponse
|
||||||
// @Failure 403 {object} web.ErrorResponse
|
// @Failure 403 {object} web.ErrorResponse
|
||||||
// @Failure 404 {object} web.ErrorResponse
|
|
||||||
// @Failure 500 {object} web.ErrorResponse
|
// @Failure 500 {object} web.ErrorResponse
|
||||||
// @Router /projects/archive [patch]
|
// @Router /projects/archive [patch]
|
||||||
func (p *Project) Archive(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
func (p *Project) Archive(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||||
@ -301,8 +301,6 @@ func (p *Project) Archive(ctx context.Context, w http.ResponseWriter, r *http.Re
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
cause := errors.Cause(err)
|
cause := errors.Cause(err)
|
||||||
switch cause {
|
switch cause {
|
||||||
case project.ErrNotFound:
|
|
||||||
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusNotFound))
|
|
||||||
case project.ErrForbidden:
|
case project.ErrForbidden:
|
||||||
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
|
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
|
||||||
default:
|
default:
|
||||||
@ -329,7 +327,6 @@ func (p *Project) Archive(ctx context.Context, w http.ResponseWriter, r *http.Re
|
|||||||
// @Success 204
|
// @Success 204
|
||||||
// @Failure 400 {object} web.ErrorResponse
|
// @Failure 400 {object} web.ErrorResponse
|
||||||
// @Failure 403 {object} web.ErrorResponse
|
// @Failure 403 {object} web.ErrorResponse
|
||||||
// @Failure 404 {object} web.ErrorResponse
|
|
||||||
// @Failure 500 {object} web.ErrorResponse
|
// @Failure 500 {object} web.ErrorResponse
|
||||||
// @Router /projects/{id} [delete]
|
// @Router /projects/{id} [delete]
|
||||||
func (p *Project) Delete(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
func (p *Project) Delete(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||||
@ -342,11 +339,14 @@ func (p *Project) Delete(ctx context.Context, w http.ResponseWriter, r *http.Req
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
cause := errors.Cause(err)
|
cause := errors.Cause(err)
|
||||||
switch cause {
|
switch cause {
|
||||||
case project.ErrNotFound:
|
|
||||||
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusNotFound))
|
|
||||||
case project.ErrForbidden:
|
case project.ErrForbidden:
|
||||||
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
|
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
|
||||||
default:
|
default:
|
||||||
|
_, ok := cause.(validator.ValidationErrors)
|
||||||
|
if ok {
|
||||||
|
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
|
||||||
|
}
|
||||||
|
|
||||||
return errors.Wrapf(err, "Id: %s", params["id"])
|
return errors.Wrapf(err, "Id: %s", params["id"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,6 @@ func API(shutdown chan os.Signal, log *log.Logger, masterDB *sqlx.DB, redis *red
|
|||||||
// This route is not authenticated
|
// This route is not authenticated
|
||||||
app.Handle("POST", "/v1/oauth/token", u.Token)
|
app.Handle("POST", "/v1/oauth/token", u.Token)
|
||||||
|
|
||||||
|
|
||||||
// Register user account management endpoints.
|
// Register user account management endpoints.
|
||||||
ua := UserAccount{
|
ua := UserAccount{
|
||||||
MasterDB: masterDB,
|
MasterDB: masterDB,
|
||||||
|
@ -27,6 +27,7 @@ type User struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find godoc
|
// Find godoc
|
||||||
|
// TODO: Need to implement unittests on users/find endpoint. There are none.
|
||||||
// @Summary List users
|
// @Summary List users
|
||||||
// @Description Find returns the existing users in the system.
|
// @Description Find returns the existing users in the system.
|
||||||
// @Tags user
|
// @Tags user
|
||||||
@ -40,7 +41,6 @@ type User struct {
|
|||||||
// @Param included-archived query boolean false "Included Archived, example: false"
|
// @Param included-archived query boolean false "Included Archived, example: false"
|
||||||
// @Success 200 {array} user.UserResponse
|
// @Success 200 {array} user.UserResponse
|
||||||
// @Failure 400 {object} web.ErrorResponse
|
// @Failure 400 {object} web.ErrorResponse
|
||||||
// @Failure 403 {object} web.ErrorResponse
|
|
||||||
// @Failure 500 {object} web.ErrorResponse
|
// @Failure 500 {object} web.ErrorResponse
|
||||||
// @Router /users [get]
|
// @Router /users [get]
|
||||||
func (u *User) Find(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
func (u *User) Find(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||||
@ -333,7 +333,6 @@ func (u *User) UpdatePassword(ctx context.Context, w http.ResponseWriter, r *htt
|
|||||||
// @Success 204
|
// @Success 204
|
||||||
// @Failure 400 {object} web.ErrorResponse
|
// @Failure 400 {object} web.ErrorResponse
|
||||||
// @Failure 403 {object} web.ErrorResponse
|
// @Failure 403 {object} web.ErrorResponse
|
||||||
// @Failure 404 {object} web.ErrorResponse
|
|
||||||
// @Failure 500 {object} web.ErrorResponse
|
// @Failure 500 {object} web.ErrorResponse
|
||||||
// @Router /users/archive [patch]
|
// @Router /users/archive [patch]
|
||||||
func (u *User) Archive(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
func (u *User) Archive(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||||
@ -359,8 +358,6 @@ func (u *User) Archive(ctx context.Context, w http.ResponseWriter, r *http.Reque
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
cause := errors.Cause(err)
|
cause := errors.Cause(err)
|
||||||
switch cause {
|
switch cause {
|
||||||
case user.ErrNotFound:
|
|
||||||
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusNotFound))
|
|
||||||
case user.ErrForbidden:
|
case user.ErrForbidden:
|
||||||
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
|
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
|
||||||
default:
|
default:
|
||||||
@ -387,7 +384,6 @@ func (u *User) Archive(ctx context.Context, w http.ResponseWriter, r *http.Reque
|
|||||||
// @Success 204
|
// @Success 204
|
||||||
// @Failure 400 {object} web.ErrorResponse
|
// @Failure 400 {object} web.ErrorResponse
|
||||||
// @Failure 403 {object} web.ErrorResponse
|
// @Failure 403 {object} web.ErrorResponse
|
||||||
// @Failure 404 {object} web.ErrorResponse
|
|
||||||
// @Failure 500 {object} web.ErrorResponse
|
// @Failure 500 {object} web.ErrorResponse
|
||||||
// @Router /users/{id} [delete]
|
// @Router /users/{id} [delete]
|
||||||
func (u *User) Delete(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
func (u *User) Delete(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||||
@ -400,12 +396,15 @@ func (u *User) Delete(ctx context.Context, w http.ResponseWriter, r *http.Reques
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
cause := errors.Cause(err)
|
cause := errors.Cause(err)
|
||||||
switch cause {
|
switch cause {
|
||||||
case user.ErrNotFound:
|
|
||||||
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusNotFound))
|
|
||||||
case user.ErrForbidden:
|
case user.ErrForbidden:
|
||||||
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
|
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
|
||||||
default:
|
default:
|
||||||
return errors.Wrapf(cause, "Id: %s", params["id"])
|
_, ok := cause.(validator.ValidationErrors)
|
||||||
|
if ok {
|
||||||
|
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.Wrapf(err, "Id: %s", params["id"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,10 +419,9 @@ func (u *User) Delete(ctx context.Context, w http.ResponseWriter, r *http.Reques
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Security OAuth2Password
|
// @Security OAuth2Password
|
||||||
// @Param account_id path int true "Account ID"
|
// @Param account_id path int true "Account ID"
|
||||||
// @Success 201
|
// @Success 200
|
||||||
// @Failure 400 {object} web.ErrorResponse
|
// @Failure 400 {object} web.ErrorResponse
|
||||||
// @Failure 403 {object} web.ErrorResponse
|
// @Failure 401 {object} web.ErrorResponse
|
||||||
// @Failure 404 {object} web.ErrorResponse
|
|
||||||
// @Failure 500 {object} web.ErrorResponse
|
// @Failure 500 {object} web.ErrorResponse
|
||||||
// @Router /users/switch-account/{account_id} [patch]
|
// @Router /users/switch-account/{account_id} [patch]
|
||||||
func (u *User) SwitchAccount(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
func (u *User) SwitchAccount(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||||
@ -453,7 +451,7 @@ func (u *User) SwitchAccount(ctx context.Context, w http.ResponseWriter, r *http
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return web.RespondJson(ctx, w, tkn, http.StatusNoContent)
|
return web.RespondJson(ctx, w, tkn, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Token godoc
|
// Token godoc
|
||||||
@ -464,10 +462,10 @@ func (u *User) SwitchAccount(ctx context.Context, w http.ResponseWriter, r *http
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Security BasicAuth
|
// @Security BasicAuth
|
||||||
// @Param scope query string false "Scope" Enums(user, admin)
|
// @Param scope query string false "Scope" Enums(user, admin)
|
||||||
// @Success 200 {object} user.Token
|
// @Success 200
|
||||||
// @Header 200 {string} Token "qwerty"
|
// @Failure 400 {object} web.ErrorResponse
|
||||||
// @Failure 400 {object} web.Error
|
// @Failure 401 {object} web.ErrorResponse
|
||||||
// @Failure 403 {object} web.Error
|
// @Failure 500 {object} web.ErrorResponse
|
||||||
// @Router /oauth/token [post]
|
// @Router /oauth/token [post]
|
||||||
func (u *User) Token(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
func (u *User) Token(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||||
v, ok := ctx.Value(web.KeyValues).(*web.Values)
|
v, ok := ctx.Value(web.KeyValues).(*web.Values)
|
||||||
@ -491,6 +489,11 @@ func (u *User) Token(ctx context.Context, w http.ResponseWriter, r *http.Request
|
|||||||
case user.ErrAuthenticationFailure:
|
case user.ErrAuthenticationFailure:
|
||||||
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusUnauthorized))
|
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusUnauthorized))
|
||||||
default:
|
default:
|
||||||
|
_, ok := cause.(validator.ValidationErrors)
|
||||||
|
if ok {
|
||||||
|
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
|
||||||
|
}
|
||||||
|
|
||||||
return errors.Wrap(err, "authenticating")
|
return errors.Wrap(err, "authenticating")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ type UserAccount struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find godoc
|
// Find godoc
|
||||||
|
// TODO: Need to implement unittests on user_accounts/find endpoint. There are none.
|
||||||
// @Summary List user accounts
|
// @Summary List user accounts
|
||||||
// @Description Find returns the existing user accounts in the system.
|
// @Description Find returns the existing user accounts in the system.
|
||||||
// @Tags user_account
|
// @Tags user_account
|
||||||
@ -275,7 +276,6 @@ func (u *UserAccount) Update(ctx context.Context, w http.ResponseWriter, r *http
|
|||||||
// @Success 204
|
// @Success 204
|
||||||
// @Failure 400 {object} web.ErrorResponse
|
// @Failure 400 {object} web.ErrorResponse
|
||||||
// @Failure 403 {object} web.ErrorResponse
|
// @Failure 403 {object} web.ErrorResponse
|
||||||
// @Failure 404 {object} web.ErrorResponse
|
|
||||||
// @Failure 500 {object} web.ErrorResponse
|
// @Failure 500 {object} web.ErrorResponse
|
||||||
// @Router /user_accounts/archive [patch]
|
// @Router /user_accounts/archive [patch]
|
||||||
func (u *UserAccount) Archive(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
func (u *UserAccount) Archive(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||||
@ -301,8 +301,6 @@ func (u *UserAccount) Archive(ctx context.Context, w http.ResponseWriter, r *htt
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
cause := errors.Cause(err)
|
cause := errors.Cause(err)
|
||||||
switch cause {
|
switch cause {
|
||||||
case user_account.ErrNotFound:
|
|
||||||
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusNotFound))
|
|
||||||
case user_account.ErrForbidden:
|
case user_account.ErrForbidden:
|
||||||
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
|
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
|
||||||
default:
|
default:
|
||||||
@ -329,7 +327,6 @@ func (u *UserAccount) Archive(ctx context.Context, w http.ResponseWriter, r *htt
|
|||||||
// @Success 204
|
// @Success 204
|
||||||
// @Failure 400 {object} web.ErrorResponse
|
// @Failure 400 {object} web.ErrorResponse
|
||||||
// @Failure 403 {object} web.ErrorResponse
|
// @Failure 403 {object} web.ErrorResponse
|
||||||
// @Failure 404 {object} web.ErrorResponse
|
|
||||||
// @Failure 500 {object} web.ErrorResponse
|
// @Failure 500 {object} web.ErrorResponse
|
||||||
// @Router /user_accounts [delete]
|
// @Router /user_accounts [delete]
|
||||||
func (u *UserAccount) Delete(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
func (u *UserAccount) Delete(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
|
||||||
@ -350,8 +347,6 @@ func (u *UserAccount) Delete(ctx context.Context, w http.ResponseWriter, r *http
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
cause := errors.Cause(err)
|
cause := errors.Cause(err)
|
||||||
switch cause {
|
switch cause {
|
||||||
case user_account.ErrNotFound:
|
|
||||||
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusNotFound))
|
|
||||||
case user_account.ErrForbidden:
|
case user_account.ErrForbidden:
|
||||||
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
|
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
|
||||||
default:
|
default:
|
||||||
@ -360,7 +355,7 @@ func (u *UserAccount) Delete(ctx context.Context, w http.ResponseWriter, r *http
|
|||||||
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
|
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.Wrapf(err, "UserID: %s AccountID: %s User Account: %+v", req.UserID, req.AccountID, &req)
|
return errors.Wrapf(err, "UserID: %s, AccountID: %s", req.UserID, req.AccountID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,335 +5,507 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/mid"
|
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/account"
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/account"
|
||||||
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/mid"
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/auth"
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/auth"
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/tests"
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/tests"
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/web"
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/web"
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
"github.com/pborman/uuid"
|
"github.com/pborman/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
func mockAccount() *account.Account {
|
// TestAccountCRUDAdmin tests all the account CRUD endpoints using an user with role admin.
|
||||||
req := account.AccountCreateRequest{
|
func TestAccountCRUDAdmin(t *testing.T) {
|
||||||
Name: uuid.NewRandom().String(),
|
|
||||||
Address1: "103 East Main St",
|
|
||||||
Address2: "Unit 546",
|
|
||||||
City: "Valdez",
|
|
||||||
Region: "AK",
|
|
||||||
Country: "USA",
|
|
||||||
Zipcode: "99686",
|
|
||||||
}
|
|
||||||
|
|
||||||
a, err := account.Create(tests.Context(), auth.Claims{}, test.MasterDB, req, time.Now().UTC().AddDate(-1, -1, -1))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestAccount is the entry point for the account endpoints.
|
|
||||||
func TestAccount(t *testing.T) {
|
|
||||||
defer tests.Recover(t)
|
defer tests.Recover(t)
|
||||||
|
|
||||||
t.Run("getAccount", getAccount)
|
tr := roleTests[auth.RoleAdmin]
|
||||||
t.Run("patchAccount", patchAccount)
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAccount validates get account by ID endpoint.
|
s := newMockSignup()
|
||||||
func getAccount(t *testing.T) {
|
tr.Account = s.account
|
||||||
|
tr.User = s.user
|
||||||
|
tr.Token = s.token
|
||||||
|
tr.Claims = s.claims
|
||||||
|
ctx := s.context
|
||||||
|
|
||||||
var rtests []requestTest
|
// Test create.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusMethodNotAllowed
|
||||||
|
|
||||||
forbiddenAccount := mockAccount()
|
req := mockUserCreateRequest()
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Create %d w/role %s", expectedStatus, tr.Role),
|
||||||
|
http.MethodPost,
|
||||||
|
"/v1/accounts",
|
||||||
|
req,
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
// Both roles should be able to read the account.
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
for rn, tr := range roleTests {
|
if !ok {
|
||||||
acc := tr.SignupResult.Account
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
// Test 200.
|
if len(w.Body.String()) != 0 {
|
||||||
rtests = append(rtests, requestTest{
|
if diff := cmpDiff(t, w.Body.Bytes(), nil); diff {
|
||||||
fmt.Sprintf("Role %s 200", rn),
|
t.Fatalf("\t%s\tReceived expected empty.", tests.Failed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected empty.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test read.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusOK
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Read %d w/role %s", expectedStatus, tr.Role),
|
||||||
http.MethodGet,
|
http.MethodGet,
|
||||||
fmt.Sprintf("/v1/accounts/%s", acc.ID),
|
fmt.Sprintf("/v1/accounts/%s", tr.Account.ID),
|
||||||
nil,
|
nil,
|
||||||
tr.Token,
|
tr.Token,
|
||||||
tr.Claims,
|
tr.Claims,
|
||||||
http.StatusOK,
|
expectedStatus,
|
||||||
nil,
|
nil,
|
||||||
func(treq requestTest, body []byte) bool {
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
var actual account.AccountResponse
|
var actual account.AccountResponse
|
||||||
if err := json.Unmarshal(body, &actual); err != nil {
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
t.Logf("\t\tGot error : %+v", err)
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
return false
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add claims to the context so they can be retrieved later.
|
|
||||||
ctx := context.WithValue(tests.Context(), auth.Key, tr.Claims)
|
|
||||||
|
|
||||||
expectedMap := map[string]interface{}{
|
expectedMap := map[string]interface{}{
|
||||||
"updated_at": web.NewTimeResponse(ctx, acc.UpdatedAt),
|
"updated_at": web.NewTimeResponse(ctx, tr.Account.UpdatedAt),
|
||||||
"id": acc.ID,
|
"id": tr.Account.ID,
|
||||||
"address2": acc.Address2,
|
"address2": tr.Account.Address2,
|
||||||
"region": acc.Region,
|
"region": tr.Account.Region,
|
||||||
"zipcode": acc.Zipcode,
|
"zipcode": tr.Account.Zipcode,
|
||||||
"timezone": acc.Timezone,
|
"timezone": tr.Account.Timezone,
|
||||||
"created_at": web.NewTimeResponse(ctx, acc.CreatedAt),
|
"created_at": web.NewTimeResponse(ctx, tr.Account.CreatedAt),
|
||||||
"country": acc.Country,
|
"country": tr.Account.Country,
|
||||||
"billing_user_id": &acc.BillingUserID,
|
"billing_user_id": &tr.Account.BillingUserID.String,
|
||||||
"name": acc.Name,
|
"name": tr.Account.Name,
|
||||||
"address1": acc.Address1,
|
"address1": tr.Account.Address1,
|
||||||
"city": acc.City,
|
"city": tr.Account.City,
|
||||||
"status": map[string]interface{}{
|
"status": map[string]interface{}{
|
||||||
"value": "active",
|
"value": "active",
|
||||||
"title": "Active",
|
"title": "Active",
|
||||||
"options": []map[string]interface{}{{"selected": false, "title": "[Active Pending Disabled]", "value": "[active pending disabled]"}},
|
"options": []map[string]interface{}{{"selected": false, "title": "[Active Pending Disabled]", "value": "[active pending disabled]"}},
|
||||||
},
|
},
|
||||||
"signup_user_id": &acc.SignupUserID,
|
"signup_user_id": &tr.Account.SignupUserID.String,
|
||||||
}
|
|
||||||
expectedJson, err := json.Marshal(expectedMap)
|
|
||||||
if err != nil {
|
|
||||||
t.Logf("\t\tGot error : %+v", err)
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var expected account.AccountResponse
|
var expected account.AccountResponse
|
||||||
if err := json.Unmarshal([]byte(expectedJson), &expected); err != nil {
|
if err := decodeMapToStruct(expectedMap, &expected); err != nil {
|
||||||
t.Logf("\t\tGot error : %+v", err)
|
t.Logf("\t\tGot error : %+v\nActual results to format expected : \n", err)
|
||||||
printResultMap(ctx, body)
|
printResultMap(ctx, w.Body.Bytes()) // used to help format expectedMap
|
||||||
return false
|
t.Fatalf("\t%s\tDecode expected failed.", tests.Failed)
|
||||||
}
|
}
|
||||||
|
|
||||||
if diff := cmp.Diff(actual, expected); diff != "" {
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
actualJSON, err := json.MarshalIndent(actual, "", " ")
|
t.Fatalf("\t%s\tReceived expected result.", tests.Failed)
|
||||||
if err != nil {
|
|
||||||
t.Logf("\t\tGot error : %+v", err)
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
t.Logf("\t\tGot : %s\n", actualJSON)
|
t.Logf("\t%s\tReceived expected result.", tests.Success)
|
||||||
|
|
||||||
expectedJSON, err := json.MarshalIndent(expected, "", " ")
|
|
||||||
if err != nil {
|
|
||||||
t.Logf("\t\tGot error : %+v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
t.Logf("\t\tExpected : %s\n", expectedJSON)
|
|
||||||
|
|
||||||
t.Logf("\t\tDiff : %s\n", diff)
|
|
||||||
|
|
||||||
if len(expectedMap) == 0 {
|
|
||||||
printResultMap(ctx, body)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
// Test Read with random ID.
|
||||||
}
|
{
|
||||||
|
expectedStatus := http.StatusNotFound
|
||||||
|
|
||||||
return true
|
randID := uuid.NewRandom().String()
|
||||||
},
|
rt := requestTest{
|
||||||
})
|
fmt.Sprintf("Read %d w/role %s using random ID", expectedStatus, tr.Role),
|
||||||
|
|
||||||
// Test 404.
|
|
||||||
invalidID := uuid.NewRandom().String()
|
|
||||||
rtests = append(rtests, requestTest{
|
|
||||||
fmt.Sprintf("Role %s 404 w/invalid ID", rn),
|
|
||||||
http.MethodGet,
|
http.MethodGet,
|
||||||
fmt.Sprintf("/v1/accounts/%s", invalidID),
|
fmt.Sprintf("/v1/accounts/%s", randID),
|
||||||
nil,
|
nil,
|
||||||
tr.Token,
|
tr.Token,
|
||||||
tr.Claims,
|
tr.Claims,
|
||||||
http.StatusNotFound,
|
expectedStatus,
|
||||||
web.ErrorResponse{
|
nil,
|
||||||
Error: fmt.Sprintf("account %s not found: Entity not found", invalidID),
|
}
|
||||||
},
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
func(treq requestTest, body []byte) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// Test 404 - Account exists but not allowed.
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
rtests = append(rtests, requestTest{
|
if !ok {
|
||||||
fmt.Sprintf("Role %s 404 w/random account ID", rn),
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: fmt.Sprintf("account %s not found: Entity not found", randID),
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test Read with forbidden ID.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusNotFound
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Read %d w/role %s using forbidden ID", expectedStatus, tr.Role),
|
||||||
http.MethodGet,
|
http.MethodGet,
|
||||||
fmt.Sprintf("/v1/accounts/%s", forbiddenAccount.ID),
|
fmt.Sprintf("/v1/accounts/%s", tr.ForbiddenAccount.ID),
|
||||||
nil,
|
nil,
|
||||||
tr.Token,
|
tr.Token,
|
||||||
tr.Claims,
|
tr.Claims,
|
||||||
http.StatusNotFound,
|
expectedStatus,
|
||||||
web.ErrorResponse{
|
nil,
|
||||||
Error: fmt.Sprintf("account %s not found: Entity not found", forbiddenAccount.ID),
|
}
|
||||||
},
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
func(treq requestTest, body []byte) bool {
|
|
||||||
return true
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
},
|
if !ok {
|
||||||
})
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
}
|
}
|
||||||
|
|
||||||
runRequestTests(t, rtests)
|
expected := web.ErrorResponse{
|
||||||
}
|
Error: fmt.Sprintf("account %s not found: Entity not found", tr.ForbiddenAccount.ID),
|
||||||
|
|
||||||
// patchAccount validates update account by ID endpoint.
|
|
||||||
func patchAccount(t *testing.T) {
|
|
||||||
|
|
||||||
var rtests []requestTest
|
|
||||||
|
|
||||||
// Test update an account
|
|
||||||
// Admin role: 204
|
|
||||||
// User role 403
|
|
||||||
for rn, tr := range roleTests {
|
|
||||||
var expectedStatus int
|
|
||||||
var expectedErr interface{}
|
|
||||||
|
|
||||||
// Test 204.
|
|
||||||
if rn == auth.RoleAdmin {
|
|
||||||
expectedStatus = http.StatusNoContent
|
|
||||||
} else {
|
|
||||||
expectedStatus = http.StatusForbidden
|
|
||||||
expectedErr = web.ErrorResponse{
|
|
||||||
Error: mid.ErrForbidden.Error(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newName := rn + uuid.NewRandom().String() + strconv.Itoa(len(rtests))
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
rtests = append(rtests, requestTest{
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
fmt.Sprintf("Role %s %d", rn, expectedStatus),
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test update.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusNoContent
|
||||||
|
|
||||||
|
newName := uuid.NewRandom().String()
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Update %d w/role %s", expectedStatus, tr.Role),
|
||||||
http.MethodPatch,
|
http.MethodPatch,
|
||||||
"/v1/accounts",
|
"/v1/accounts",
|
||||||
account.AccountUpdateRequest{
|
account.AccountUpdateRequest{
|
||||||
ID: tr.SignupResult.Account.ID,
|
ID: tr.Account.ID,
|
||||||
Name: &newName,
|
Name: &newName,
|
||||||
},
|
},
|
||||||
tr.Token,
|
tr.Token,
|
||||||
tr.Claims,
|
tr.Claims,
|
||||||
expectedStatus,
|
expectedStatus,
|
||||||
expectedErr,
|
nil,
|
||||||
func(treq requestTest, body []byte) bool {
|
}
|
||||||
return true
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
if len(w.Body.String()) != 0 {
|
||||||
|
if diff := cmpDiff(t, w.Body.Bytes(), nil); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected empty.", tests.Failed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected empty.", tests.Success)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestAccountCRUDUser tests all the account CRUD endpoints using an user with role user.
|
||||||
|
func TestAccountCRUDUser(t *testing.T) {
|
||||||
|
defer tests.Recover(t)
|
||||||
|
|
||||||
|
tr := roleTests[auth.RoleUser]
|
||||||
|
|
||||||
|
// Add claims to the context for the user.
|
||||||
|
ctx := context.WithValue(tests.Context(), auth.Key, tr.Claims)
|
||||||
|
|
||||||
|
// Test create.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusMethodNotAllowed
|
||||||
|
|
||||||
|
req := mockUserCreateRequest()
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Create %d w/role %s", expectedStatus, tr.Role),
|
||||||
|
http.MethodPost,
|
||||||
|
"/v1/accounts",
|
||||||
|
req,
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
if len(w.Body.String()) != 0 {
|
||||||
|
if diff := cmpDiff(t, w.Body.Bytes(), nil); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected empty.", tests.Failed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected empty.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test read.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusOK
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Read %d w/role %s", expectedStatus, tr.Role),
|
||||||
|
http.MethodGet,
|
||||||
|
fmt.Sprintf("/v1/accounts/%s", tr.Account.ID),
|
||||||
|
nil,
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual account.AccountResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMap := map[string]interface{}{
|
||||||
|
"updated_at": web.NewTimeResponse(ctx, tr.Account.UpdatedAt),
|
||||||
|
"id": tr.Account.ID,
|
||||||
|
"address2": tr.Account.Address2,
|
||||||
|
"region": tr.Account.Region,
|
||||||
|
"zipcode": tr.Account.Zipcode,
|
||||||
|
"timezone": tr.Account.Timezone,
|
||||||
|
"created_at": web.NewTimeResponse(ctx, tr.Account.CreatedAt),
|
||||||
|
"country": tr.Account.Country,
|
||||||
|
"billing_user_id": &tr.Account.BillingUserID.String,
|
||||||
|
"name": tr.Account.Name,
|
||||||
|
"address1": tr.Account.Address1,
|
||||||
|
"city": tr.Account.City,
|
||||||
|
"status": map[string]interface{}{
|
||||||
|
"value": "active",
|
||||||
|
"title": "Active",
|
||||||
|
"options": []map[string]interface{}{{"selected": false, "title": "[Active Pending Disabled]", "value": "[active pending disabled]"}},
|
||||||
},
|
},
|
||||||
})
|
"signup_user_id": &tr.Account.SignupUserID.String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test update an account with invalid data.
|
var expected account.AccountResponse
|
||||||
// Admin role: 400
|
if err := decodeMapToStruct(expectedMap, &expected); err != nil {
|
||||||
// User role 400
|
t.Logf("\t\tGot error : %+v\nActual results to format expected : \n", err)
|
||||||
for rn, tr := range roleTests {
|
printResultMap(ctx, w.Body.Bytes()) // used to help format expectedMap
|
||||||
var expectedStatus int
|
t.Fatalf("\t%s\tDecode expected failed.", tests.Failed)
|
||||||
var expectedErr interface{}
|
|
||||||
|
|
||||||
if rn == auth.RoleAdmin {
|
|
||||||
expectedStatus = http.StatusBadRequest
|
|
||||||
expectedErr = web.ErrorResponse{
|
|
||||||
Error: "field validation error",
|
|
||||||
Fields: []web.FieldError{
|
|
||||||
{Field: "status", Error: "Key: 'AccountUpdateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
expectedStatus = http.StatusForbidden
|
|
||||||
expectedErr = web.ErrorResponse{
|
|
||||||
Error: mid.ErrForbidden.Error(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
invalidStatus := account.AccountStatus("invalid status")
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
rtests = append(rtests, requestTest{
|
t.Fatalf("\t%s\tReceived expected result.", tests.Failed)
|
||||||
fmt.Sprintf("Role %s %d w/invalid data", rn, expectedStatus),
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected result.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test Read with random ID.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusNotFound
|
||||||
|
|
||||||
|
randID := uuid.NewRandom().String()
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Read %d w/role %s using random ID", expectedStatus, tr.Role),
|
||||||
|
http.MethodGet,
|
||||||
|
fmt.Sprintf("/v1/accounts/%s", randID),
|
||||||
|
nil,
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: fmt.Sprintf("account %s not found: Entity not found", randID),
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test Read with forbidden ID.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusNotFound
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Read %d w/role %s using forbidden ID", expectedStatus, tr.Role),
|
||||||
|
http.MethodGet,
|
||||||
|
fmt.Sprintf("/v1/accounts/%s", tr.ForbiddenAccount.ID),
|
||||||
|
nil,
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: fmt.Sprintf("account %s not found: Entity not found", tr.ForbiddenAccount.ID),
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test update.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusForbidden
|
||||||
|
|
||||||
|
newName := uuid.NewRandom().String()
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Update %d w/role %s", expectedStatus, tr.Role),
|
||||||
http.MethodPatch,
|
http.MethodPatch,
|
||||||
"/v1/accounts",
|
"/v1/accounts",
|
||||||
account.AccountUpdateRequest{
|
account.AccountUpdateRequest{
|
||||||
ID: tr.SignupResult.User.ID,
|
ID: tr.Account.ID,
|
||||||
|
Name: &newName,
|
||||||
|
},
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: mid.ErrForbidden.Error(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestAccountUpdate validates update account by ID endpoint.
|
||||||
|
func TestAccountUpdate(t *testing.T) {
|
||||||
|
defer tests.Recover(t)
|
||||||
|
|
||||||
|
tr := roleTests[auth.RoleAdmin]
|
||||||
|
|
||||||
|
// Add claims to the context for the user.
|
||||||
|
ctx := context.WithValue(tests.Context(), auth.Key, tr.Claims)
|
||||||
|
|
||||||
|
// Test create with invalid data.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusBadRequest
|
||||||
|
|
||||||
|
invalidStatus := account.AccountStatus("invalid status")
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Update %d w/role %s using invalid data", expectedStatus, tr.Role),
|
||||||
|
http.MethodPatch,
|
||||||
|
"/v1/accounts",
|
||||||
|
account.AccountUpdateRequest{
|
||||||
|
ID: tr.Account.ID,
|
||||||
Status: &invalidStatus,
|
Status: &invalidStatus,
|
||||||
},
|
},
|
||||||
tr.Token,
|
tr.Token,
|
||||||
tr.Claims,
|
tr.Claims,
|
||||||
expectedStatus,
|
expectedStatus,
|
||||||
expectedErr,
|
nil,
|
||||||
func(treq requestTest, body []byte) bool {
|
}
|
||||||
return true
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
},
|
|
||||||
})
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test update an account for with an invalid ID.
|
expected := web.ErrorResponse{
|
||||||
// Admin role: 403
|
Error: "field validation error",
|
||||||
// User role 403
|
Fields: []web.FieldError{
|
||||||
for rn, tr := range roleTests {
|
{Field: "status", Error: "Key: 'AccountUpdateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"},
|
||||||
var expectedStatus int
|
|
||||||
var expectedErr interface{}
|
|
||||||
|
|
||||||
// Test 403.
|
|
||||||
if rn == auth.RoleAdmin {
|
|
||||||
expectedStatus = http.StatusForbidden
|
|
||||||
expectedErr = web.ErrorResponse{
|
|
||||||
Error: account.ErrForbidden.Error(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
expectedStatus = http.StatusForbidden
|
|
||||||
expectedErr = web.ErrorResponse{
|
|
||||||
Error: mid.ErrForbidden.Error(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newName := rn + uuid.NewRandom().String() + strconv.Itoa(len(rtests))
|
|
||||||
invalidID := uuid.NewRandom().String()
|
|
||||||
rtests = append(rtests, requestTest{
|
|
||||||
fmt.Sprintf("Role %s %d w/invalid ID", rn, expectedStatus),
|
|
||||||
http.MethodPatch,
|
|
||||||
"/v1/accounts",
|
|
||||||
account.AccountUpdateRequest{
|
|
||||||
ID: invalidID,
|
|
||||||
Name: &newName,
|
|
||||||
},
|
},
|
||||||
tr.Token,
|
|
||||||
tr.Claims,
|
|
||||||
expectedStatus,
|
|
||||||
expectedErr,
|
|
||||||
func(treq requestTest, body []byte) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test update an account for with random account ID.
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
// Admin role: 403
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
// User role 403
|
|
||||||
forbiddenAccount := mockAccount()
|
|
||||||
for rn, tr := range roleTests {
|
|
||||||
var expectedStatus int
|
|
||||||
var expectedErr interface{}
|
|
||||||
|
|
||||||
// Test 403.
|
|
||||||
if rn == auth.RoleAdmin {
|
|
||||||
expectedStatus = http.StatusForbidden
|
|
||||||
expectedErr = web.ErrorResponse{
|
|
||||||
Error: account.ErrForbidden.Error(),
|
|
||||||
}
|
}
|
||||||
} else {
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
expectedStatus = http.StatusForbidden
|
|
||||||
expectedErr = web.ErrorResponse{
|
|
||||||
Error: mid.ErrForbidden.Error(),
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
newName := rn+uuid.NewRandom().String()+strconv.Itoa(len(rtests))
|
|
||||||
rtests = append(rtests, requestTest{
|
|
||||||
fmt.Sprintf("Role %s %d w/random account ID", rn, expectedStatus),
|
|
||||||
http.MethodPatch,
|
|
||||||
"/v1/accounts",
|
|
||||||
account.AccountUpdateRequest{
|
|
||||||
ID: forbiddenAccount.ID,
|
|
||||||
Name: &newName,
|
|
||||||
},
|
|
||||||
tr.Token,
|
|
||||||
tr.Claims,
|
|
||||||
expectedStatus,
|
|
||||||
expectedErr,
|
|
||||||
func(treq requestTest, body []byte) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
runRequestTests(t, rtests)
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,19 +1,30 @@
|
|||||||
package tests
|
package tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/account"
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/auth"
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/auth"
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/tests"
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/tests"
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/web"
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/web"
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/signup"
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/signup"
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/user"
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/user"
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
"github.com/pborman/uuid"
|
"github.com/pborman/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type mockSignup struct {
|
||||||
|
account *account.Account
|
||||||
|
user mockUser
|
||||||
|
token user.Token
|
||||||
|
claims auth.Claims
|
||||||
|
context context.Context
|
||||||
|
}
|
||||||
|
|
||||||
func mockSignupRequest() signup.SignupRequest {
|
func mockSignupRequest() signup.SignupRequest {
|
||||||
return signup.SignupRequest{
|
return signup.SignupRequest{
|
||||||
Account: signup.SignupAccount{
|
Account: signup.SignupAccount{
|
||||||
@ -34,40 +45,71 @@ func mockSignupRequest() signup.SignupRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestSignup is the entry point for the signup
|
func newMockSignup() mockSignup {
|
||||||
|
req := mockSignupRequest()
|
||||||
|
now := time.Now().UTC().AddDate(-1, -1, -1)
|
||||||
|
s, err := signup.Signup(tests.Context(), auth.Claims{}, test.MasterDB, req, now)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expires := time.Now().UTC().Sub(s.User.CreatedAt) + time.Hour
|
||||||
|
tkn, err := user.Authenticate(tests.Context(), test.MasterDB, authenticator, req.User.Email, req.User.Password, expires, now)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, err := authenticator.ParseClaims(tkn.AccessToken)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add claims to the context for the user.
|
||||||
|
ctx := context.WithValue(tests.Context(), auth.Key, claims)
|
||||||
|
|
||||||
|
return mockSignup{
|
||||||
|
account: s.Account,
|
||||||
|
user: mockUser{s.User, req.User.Password},
|
||||||
|
claims: claims,
|
||||||
|
token: tkn,
|
||||||
|
context: ctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestSignup validates the signup endpoint.
|
||||||
func TestSignup(t *testing.T) {
|
func TestSignup(t *testing.T) {
|
||||||
defer tests.Recover(t)
|
defer tests.Recover(t)
|
||||||
|
|
||||||
t.Run("postSigup", postSigup)
|
|
||||||
}
|
|
||||||
|
|
||||||
// postSigup validates the signup endpoint.
|
|
||||||
func postSigup(t *testing.T) {
|
|
||||||
|
|
||||||
var rtests []requestTest
|
|
||||||
|
|
||||||
// Test 201.
|
|
||||||
// Signup does not require auth, so empty token and claims should result in success.
|
|
||||||
req1 := mockSignupRequest()
|
|
||||||
rtests = append(rtests, requestTest{
|
|
||||||
"No Authorization Valid",
|
|
||||||
http.MethodPost,
|
|
||||||
"/v1/signup",
|
|
||||||
req1,
|
|
||||||
user.Token{},
|
|
||||||
auth.Claims{},
|
|
||||||
http.StatusCreated,
|
|
||||||
nil,
|
|
||||||
func(treq requestTest, body []byte) bool {
|
|
||||||
var actual signup.SignupResponse
|
|
||||||
if err := json.Unmarshal(body, &actual); err != nil {
|
|
||||||
t.Logf("\t\tGot error : %+v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := tests.Context()
|
ctx := tests.Context()
|
||||||
|
|
||||||
req := treq.request.(signup.SignupRequest )
|
// Test signup.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusCreated
|
||||||
|
|
||||||
|
req := mockSignupRequest()
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Signup %d w/no authorization", expectedStatus),
|
||||||
|
http.MethodPost,
|
||||||
|
"/v1/signup",
|
||||||
|
req,
|
||||||
|
user.Token{},
|
||||||
|
auth.Claims{},
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual signup.SignupResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
expectedMap := map[string]interface{}{
|
expectedMap := map[string]interface{}{
|
||||||
"user": map[string]interface{}{
|
"user": map[string]interface{}{
|
||||||
@ -94,92 +136,108 @@ func postSigup(t *testing.T) {
|
|||||||
"status": map[string]interface{}{
|
"status": map[string]interface{}{
|
||||||
"value": "active",
|
"value": "active",
|
||||||
"title": "Active",
|
"title": "Active",
|
||||||
"options": []map[string]interface{}{{"selected":false,"title":"[Active Pending Disabled]","value":"[active pending disabled]"}},
|
"options": []map[string]interface{}{{"selected": false, "title": "[Active Pending Disabled]", "value": "[active pending disabled]"}},
|
||||||
},
|
},
|
||||||
"signup_user_id": &actual.Account.SignupUserID,
|
"signup_user_id": &actual.Account.SignupUserID,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
expectedJson, err := json.Marshal(expectedMap)
|
|
||||||
if err != nil {
|
|
||||||
t.Logf("\t\tGot error : %+v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var expected signup.SignupResponse
|
var expected signup.SignupResponse
|
||||||
if err := json.Unmarshal([]byte(expectedJson), &expected); err != nil {
|
if err := decodeMapToStruct(expectedMap, &expected); err != nil {
|
||||||
t.Logf("\t\tGot error : %+v", err)
|
t.Logf("\t\tGot error : %+v\nActual results to format expected : \n", err)
|
||||||
printResultMap(ctx, body)
|
printResultMap(ctx, w.Body.Bytes()) // used to help format expectedMap
|
||||||
return false
|
t.Fatalf("\t%s\tDecode expected failed.", tests.Failed)
|
||||||
}
|
}
|
||||||
|
|
||||||
if diff := cmp.Diff(actual, expected); diff != "" {
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
actualJSON, err := json.MarshalIndent(actual, "", " ")
|
|
||||||
if err != nil {
|
|
||||||
t.Logf("\t\tGot error : %+v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
t.Logf("\t\tGot : %s\n", actualJSON)
|
|
||||||
|
|
||||||
expectedJSON, err := json.MarshalIndent(expected, "", " ")
|
|
||||||
if err != nil {
|
|
||||||
t.Logf("\t\tGot error : %+v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
t.Logf("\t\tExpected : %s\n", expectedJSON)
|
|
||||||
|
|
||||||
t.Logf("\t\tDiff : %s\n", diff)
|
|
||||||
|
|
||||||
if len(expectedMap) == 0 {
|
if len(expectedMap) == 0 {
|
||||||
printResultMap(ctx, body)
|
printResultMap(ctx, w.Body.Bytes()) // used to help format expectedMap
|
||||||
|
}
|
||||||
|
t.Fatalf("\t%s\tReceived expected result.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected result.", tests.Success)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
// Test signup w/empty request.
|
||||||
}
|
{
|
||||||
|
expectedStatus := http.StatusBadRequest
|
||||||
|
|
||||||
return true
|
rt := requestTest{
|
||||||
},
|
fmt.Sprintf("Signup %d w/empty request", expectedStatus),
|
||||||
})
|
|
||||||
|
|
||||||
// Test 404 w/empty request.
|
|
||||||
rtests = append(rtests, requestTest{
|
|
||||||
"Empty request",
|
|
||||||
http.MethodPost,
|
http.MethodPost,
|
||||||
"/v1/signup",
|
"/v1/signup",
|
||||||
nil,
|
nil,
|
||||||
user.Token{},
|
user.Token{},
|
||||||
auth.Claims{},
|
auth.Claims{},
|
||||||
http.StatusBadRequest,
|
expectedStatus,
|
||||||
web.ErrorResponse{
|
nil,
|
||||||
Error: "decode request body failed: EOF",
|
}
|
||||||
},
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
func(req requestTest, body []byte) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// Test 404 w/validation errors.
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
invalidReq := mockSignupRequest()
|
if !ok {
|
||||||
invalidReq.User.Email = ""
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
invalidReq.Account.Name = ""
|
}
|
||||||
rtests = append(rtests, requestTest{
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
"Invalid request",
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: "decode request body failed: EOF",
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test signup w/validation errors.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusBadRequest
|
||||||
|
|
||||||
|
req := mockSignupRequest()
|
||||||
|
req.User.Email = ""
|
||||||
|
req.Account.Name = ""
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Signup %d w/validation errors", expectedStatus),
|
||||||
http.MethodPost,
|
http.MethodPost,
|
||||||
"/v1/signup",
|
"/v1/signup",
|
||||||
invalidReq,
|
req,
|
||||||
user.Token{},
|
user.Token{},
|
||||||
auth.Claims{},
|
auth.Claims{},
|
||||||
http.StatusBadRequest,
|
expectedStatus,
|
||||||
web.ErrorResponse{
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
Error: "field validation error",
|
Error: "field validation error",
|
||||||
Fields: []web.FieldError{
|
Fields: []web.FieldError{
|
||||||
{Field: "name", Error: "Key: 'SignupRequest.account.name' Error:Field validation for 'name' failed on the 'required' tag"},
|
{Field: "name", Error: "Key: 'SignupRequest.account.name' Error:Field validation for 'name' failed on the 'required' tag"},
|
||||||
{Field: "email", Error: "Key: 'SignupRequest.user.email' Error:Field validation for 'email' failed on the 'required' tag"},
|
{Field: "email", Error: "Key: 'SignupRequest.user.email' Error:Field validation for 'email' failed on the 'required' tag"},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
func(req requestTest, body []byte) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
runRequestTests(t, rtests)
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/web"
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
@ -15,28 +14,33 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/account"
|
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/signup"
|
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/user_account"
|
|
||||||
"github.com/iancoleman/strcase"
|
|
||||||
"github.com/pborman/uuid"
|
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/cmd/web-api/handlers"
|
"geeks-accelerator/oss/saas-starter-kit/example-project/cmd/web-api/handlers"
|
||||||
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/account"
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/auth"
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/auth"
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/tests"
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/tests"
|
||||||
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/web"
|
||||||
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/signup"
|
||||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/user"
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/user"
|
||||||
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/user_account"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/iancoleman/strcase"
|
||||||
|
"github.com/pborman/uuid"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var a http.Handler
|
var a http.Handler
|
||||||
var test *tests.Test
|
var test *tests.Test
|
||||||
|
var authenticator *auth.Authenticator
|
||||||
|
|
||||||
// Information about the users we have created for testing.
|
// Information about the users we have created for testing.
|
||||||
type roleTest struct {
|
type roleTest struct {
|
||||||
|
Role string
|
||||||
Token user.Token
|
Token user.Token
|
||||||
Claims auth.Claims
|
Claims auth.Claims
|
||||||
SignupRequest *signup.SignupRequest
|
User mockUser
|
||||||
SignupResult *signup.SignupResult
|
|
||||||
User *user.User
|
|
||||||
Account *account.Account
|
Account *account.Account
|
||||||
|
ForbiddenUser mockUser
|
||||||
|
ForbiddenAccount *account.Account
|
||||||
}
|
}
|
||||||
|
|
||||||
type requestTest struct {
|
type requestTest struct {
|
||||||
@ -48,7 +52,6 @@ type requestTest struct {
|
|||||||
claims auth.Claims
|
claims auth.Claims
|
||||||
statusCode int
|
statusCode int
|
||||||
error interface{}
|
error interface{}
|
||||||
expected func(req requestTest, result []byte) bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var roleTests map[string]roleTest
|
var roleTests map[string]roleTest
|
||||||
@ -68,40 +71,28 @@ func testMain(m *testing.M) int {
|
|||||||
|
|
||||||
now := time.Date(2018, time.October, 1, 0, 0, 0, 0, time.UTC)
|
now := time.Date(2018, time.October, 1, 0, 0, 0, 0, time.UTC)
|
||||||
|
|
||||||
authenticator, err := auth.NewAuthenticatorMemory(now)
|
var err error
|
||||||
|
authenticator, err = auth.NewAuthenticatorMemory(now)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
shutdown := make(chan os.Signal, 1)
|
shutdown := make(chan os.Signal, 1)
|
||||||
a = handlers.API(shutdown, test.Log, test.MasterDB, nil, authenticator)
|
|
||||||
|
log := test.Log
|
||||||
|
log.SetOutput(ioutil.Discard)
|
||||||
|
a = handlers.API(shutdown, log, test.MasterDB, nil, authenticator)
|
||||||
|
|
||||||
// Create a new account directly business logic. This creates an
|
// Create a new account directly business logic. This creates an
|
||||||
// initial account and user that we will use for admin validated endpoints.
|
// initial account and user that we will use for admin validated endpoints.
|
||||||
signupReq := signup.SignupRequest{
|
signupReq1 := mockSignupRequest()
|
||||||
Account: signup.SignupAccount{
|
signup1, err := signup.Signup(tests.Context(), auth.Claims{}, test.MasterDB, signupReq1, now)
|
||||||
Name: uuid.NewRandom().String(),
|
|
||||||
Address1: "103 East Main St",
|
|
||||||
Address2: "Unit 546",
|
|
||||||
City: "Valdez",
|
|
||||||
Region: "AK",
|
|
||||||
Country: "USA",
|
|
||||||
Zipcode: "99686",
|
|
||||||
},
|
|
||||||
User: signup.SignupUser{
|
|
||||||
Name: "Lee Brown",
|
|
||||||
Email: uuid.NewRandom().String() + "@geeksinthewoods.com",
|
|
||||||
Password: "akTechFr0n!ier",
|
|
||||||
PasswordConfirm: "akTechFr0n!ier",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
signup, err := signup.Signup(tests.Context(), auth.Claims{}, test.MasterDB, signupReq, now)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expires := time.Now().UTC().Sub(signup.User.CreatedAt) + time.Hour
|
expires := time.Now().UTC().Sub(signup1.User.CreatedAt) + time.Hour
|
||||||
adminTkn, err := user.Authenticate(tests.Context(), test.MasterDB, authenticator, signupReq.User.Email, signupReq.User.Password, expires, now)
|
adminTkn, err := user.Authenticate(tests.Context(), test.MasterDB, authenticator, signupReq1.User.Email, signupReq1.User.Password, expires, now)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -111,13 +102,22 @@ func testMain(m *testing.M) int {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a second account that the first account user should not have access to.
|
||||||
|
signupReq2 := mockSignupRequest()
|
||||||
|
signup2, err := signup.Signup(tests.Context(), auth.Claims{}, test.MasterDB, signupReq2, now)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// First test will be for role Admin
|
||||||
roleTests[auth.RoleAdmin] = roleTest{
|
roleTests[auth.RoleAdmin] = roleTest{
|
||||||
|
Role: auth.RoleAdmin,
|
||||||
Token: adminTkn,
|
Token: adminTkn,
|
||||||
Claims: adminClaims,
|
Claims: adminClaims,
|
||||||
SignupRequest: &signupReq,
|
User: mockUser{signup1.User, signupReq1.User.Password},
|
||||||
SignupResult: signup,
|
Account: signup1.Account,
|
||||||
User: signup.User,
|
ForbiddenUser: mockUser{signup2.User, signupReq2.User.Password},
|
||||||
Account: signup.Account,
|
ForbiddenAccount: signup2.Account,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a regular user to use when calling regular validated endpoints.
|
// Create a regular user to use when calling regular validated endpoints.
|
||||||
@ -134,7 +134,7 @@ func testMain(m *testing.M) int {
|
|||||||
|
|
||||||
_, err = user_account.Create(tests.Context(), adminClaims, test.MasterDB, user_account.UserAccountCreateRequest{
|
_, err = user_account.Create(tests.Context(), adminClaims, test.MasterDB, user_account.UserAccountCreateRequest{
|
||||||
UserID: usr.ID,
|
UserID: usr.ID,
|
||||||
AccountID: signup.Account.ID,
|
AccountID: signup1.Account.ID,
|
||||||
Roles: []user_account.UserAccountRole{user_account.UserAccountRole_User},
|
Roles: []user_account.UserAccountRole{user_account.UserAccountRole_User},
|
||||||
// Status: use default value
|
// Status: use default value
|
||||||
}, now)
|
}, now)
|
||||||
@ -152,25 +152,22 @@ func testMain(m *testing.M) int {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Second test will be for role User
|
||||||
roleTests[auth.RoleUser] = roleTest{
|
roleTests[auth.RoleUser] = roleTest{
|
||||||
|
Role: auth.RoleUser,
|
||||||
Token: userTkn,
|
Token: userTkn,
|
||||||
Claims: userClaims,
|
Claims: userClaims,
|
||||||
SignupRequest: &signupReq,
|
Account: signup1.Account,
|
||||||
SignupResult: signup,
|
User: mockUser{usr, userReq.Password},
|
||||||
Account: signup.Account,
|
ForbiddenUser: mockUser{signup2.User, signupReq2.User.Password},
|
||||||
User: usr,
|
ForbiddenAccount: signup2.Account,
|
||||||
}
|
}
|
||||||
|
|
||||||
return m.Run()
|
return m.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// executeRequestTest provides request execution and basic response validation
|
||||||
// runRequestTests helper function for testing endpoints.
|
func executeRequestTest(t *testing.T, tt requestTest, ctx context.Context) (*httptest.ResponseRecorder, bool) {
|
||||||
func runRequestTests(t *testing.T, rtests []requestTest ) {
|
|
||||||
|
|
||||||
for i, tt := range rtests {
|
|
||||||
t.Logf("\tTest: %d\tWhen running test: %s", i, tt.name)
|
|
||||||
{
|
|
||||||
var req []byte
|
var req []byte
|
||||||
var rr io.Reader
|
var rr io.Reader
|
||||||
if tt.request != nil {
|
if tt.request != nil {
|
||||||
@ -181,13 +178,15 @@ func runRequestTests(t *testing.T, rtests []requestTest ) {
|
|||||||
req, err = json.Marshal(tt.request)
|
req, err = json.Marshal(tt.request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("\t\tGot err : %+v", err)
|
t.Logf("\t\tGot err : %+v", err)
|
||||||
t.Fatalf("\t%s\tEncode request failed.", tests.Failed)
|
t.Logf("\t\tEncode request failed.")
|
||||||
|
return nil, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rr = bytes.NewReader(req)
|
rr = bytes.NewReader(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
r := httptest.NewRequest(tt.method, tt.url , rr)
|
r := httptest.NewRequest(tt.method, tt.url, rr).WithContext(ctx)
|
||||||
|
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
r.Header.Set("Content-Type", web.MIMEApplicationJSONCharsetUTF8)
|
r.Header.Set("Content-Type", web.MIMEApplicationJSONCharsetUTF8)
|
||||||
@ -200,35 +199,67 @@ func runRequestTests(t *testing.T, rtests []requestTest ) {
|
|||||||
if w.Code != tt.statusCode {
|
if w.Code != tt.statusCode {
|
||||||
t.Logf("\t\tRequest : %s\n", string(req))
|
t.Logf("\t\tRequest : %s\n", string(req))
|
||||||
t.Logf("\t\tBody : %s\n", w.Body.String())
|
t.Logf("\t\tBody : %s\n", w.Body.String())
|
||||||
t.Fatalf("\t%s\tShould receive a status code of %d for the response : %v", tests.Failed, tt.statusCode, w.Code)
|
t.Logf("\t\tShould receive a status code of %d for the response : %v", tt.statusCode, w.Code)
|
||||||
|
return w, false
|
||||||
}
|
}
|
||||||
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
|
||||||
|
|
||||||
if tt.error != nil {
|
if tt.error != nil {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var actual web.ErrorResponse
|
var actual web.ErrorResponse
|
||||||
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
t.Logf("\t\tBody : %s\n", w.Body.String())
|
t.Logf("\t\tBody : %s\n", w.Body.String())
|
||||||
t.Logf("\t\tGot error : %+v", err)
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
t.Fatalf("\t%s\tShould get the expected error.", tests.Failed)
|
t.Logf("\t\tShould get the expected error.")
|
||||||
|
return w, false
|
||||||
}
|
}
|
||||||
|
|
||||||
if diff := cmp.Diff(actual, tt.error); diff != "" {
|
if diff := cmp.Diff(actual, tt.error); diff != "" {
|
||||||
t.Logf("\t\tDiff : %s\n", diff)
|
t.Logf("\t\tDiff : %s\n", diff)
|
||||||
t.Fatalf("\t%s\tShould get the expected error.", tests.Failed)
|
t.Logf("\t\tShould get the expected error.")
|
||||||
|
return w, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ok := tt.expected(tt, w.Body.Bytes()); !ok {
|
return w, true
|
||||||
t.Fatalf("\t%s\tShould get the expected result.", tests.Failed)
|
|
||||||
}
|
|
||||||
t.Logf("\t%s\tReceived expected result.", tests.Success)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// decodeMapToStruct used to covert map to json struct so don't have a bunch of raw json strings running around test files.
|
||||||
|
func decodeMapToStruct(expectedMap map[string]interface{}, expected interface{}) error {
|
||||||
|
expectedJson, err := json.Marshal(expectedMap)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal([]byte(expectedJson), &expected); err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// cmpDiff prints out the raw json to help with debugging.
|
||||||
|
func cmpDiff(t *testing.T, actual, expected interface{}) bool {
|
||||||
|
if actual == nil && expected == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(actual, expected); diff != "" {
|
||||||
|
actualJSON, err := json.MarshalIndent(actual, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("\t%s\tGot error : %+v", tests.Failed, err)
|
||||||
|
}
|
||||||
|
t.Logf("\t\tGot : %s\n", actualJSON)
|
||||||
|
|
||||||
|
expectedJSON, err := json.MarshalIndent(expected, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("\t%s\tGot error : %+v", tests.Failed, err)
|
||||||
|
}
|
||||||
|
t.Logf("\t\tExpected : %s\n", expectedJSON)
|
||||||
|
|
||||||
|
t.Logf("\t\tDiff : %s\n", diff)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func printResultMap(ctx context.Context, result []byte) {
|
func printResultMap(ctx context.Context, result []byte) {
|
||||||
var m map[string]interface{}
|
var m map[string]interface{}
|
||||||
@ -261,13 +292,13 @@ func printResultMapKeys(ctx context.Context, m map[string]interface{}, depth int
|
|||||||
fmt.Printf("%s\"%s\": []map[string]interface{}{\n", strings.Repeat("\t", depth), k)
|
fmt.Printf("%s\"%s\": []map[string]interface{}{\n", strings.Repeat("\t", depth), k)
|
||||||
|
|
||||||
for _, smv := range sm {
|
for _, smv := range sm {
|
||||||
printResultMapKeys(ctx, smv, depth +1)
|
printResultMapKeys(ctx, smv, depth+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("%s},\n", strings.Repeat("\t", depth))
|
fmt.Printf("%s},\n", strings.Repeat("\t", depth))
|
||||||
} else if sm, ok := kv.(map[string]interface{}); ok {
|
} else if sm, ok := kv.(map[string]interface{}); ok {
|
||||||
fmt.Printf("%s\"%s\": map[string]interface{}{\n", strings.Repeat("\t", depth), k)
|
fmt.Printf("%s\"%s\": map[string]interface{}{\n", strings.Repeat("\t", depth), k)
|
||||||
printResultMapKeys(ctx, sm, depth +1)
|
printResultMapKeys(ctx, sm, depth+1)
|
||||||
fmt.Printf("%s},\n", strings.Repeat("\t", depth))
|
fmt.Printf("%s},\n", strings.Repeat("\t", depth))
|
||||||
} else {
|
} else {
|
||||||
var pv string
|
var pv string
|
||||||
@ -282,4 +313,3 @@ func printResultMapKeys(ctx context.Context, m map[string]interface{}, depth int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
930
example-project/cmd/web-api/tests/user_account_test.go
Normal file
930
example-project/cmd/web-api/tests/user_account_test.go
Normal file
@ -0,0 +1,930 @@
|
|||||||
|
package tests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/account"
|
||||||
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/mid"
|
||||||
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/auth"
|
||||||
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/tests"
|
||||||
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/web"
|
||||||
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/user"
|
||||||
|
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/user_account"
|
||||||
|
"github.com/pborman/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// newMockUserAccount creates a new user user for testing and associates it with the supplied account ID.
|
||||||
|
func newMockUserAccount(accountID string, role user_account.UserAccountRole) *user_account.UserAccount {
|
||||||
|
req := mockUserCreateRequest()
|
||||||
|
u, err := user.Create(tests.Context(), auth.Claims{}, test.MasterDB, req, time.Now().UTC().AddDate(-1, -1, -1))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ua, err := user_account.Create(tests.Context(), auth.Claims{}, test.MasterDB, user_account.UserAccountCreateRequest{
|
||||||
|
UserID: u.ID,
|
||||||
|
AccountID: accountID,
|
||||||
|
Roles: []user_account.UserAccountRole{role},
|
||||||
|
}, time.Now().UTC().AddDate(-1, -1, -1))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ua
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestUserAccountCRUDAdmin tests all the user account CRUD endpoints using an user with role admin.
|
||||||
|
func TestUserAccountCRUDAdmin(t *testing.T) {
|
||||||
|
defer tests.Recover(t)
|
||||||
|
|
||||||
|
tr := roleTests[auth.RoleAdmin]
|
||||||
|
|
||||||
|
// Add claims to the context for the user_account.
|
||||||
|
ctx := context.WithValue(tests.Context(), auth.Key, tr.Claims)
|
||||||
|
|
||||||
|
// Test create.
|
||||||
|
var created user_account.UserAccountResponse
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusCreated
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Create %d w/role %s", expectedStatus, tr.Role),
|
||||||
|
http.MethodPost,
|
||||||
|
"/v1/user_accounts",
|
||||||
|
nil,
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
newUser, err := user.Create(tests.Context(), auth.Claims{}, test.MasterDB, mockUserCreateRequest(), time.Now().UTC().AddDate(-1, -1, -1))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("\t%s\tCreate new user failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
req := user_account.UserAccountCreateRequest{
|
||||||
|
UserID: newUser.ID,
|
||||||
|
AccountID: tr.Account.ID,
|
||||||
|
Roles: []user_account.UserAccountRole{user_account.UserAccountRole_User},
|
||||||
|
}
|
||||||
|
rt.request = req
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual user_account.UserAccountResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
created = actual
|
||||||
|
|
||||||
|
expectedMap := map[string]interface{}{
|
||||||
|
"updated_at": web.NewTimeResponse(ctx, actual.UpdatedAt.Value),
|
||||||
|
"id": actual.ID,
|
||||||
|
"account_id": req.AccountID,
|
||||||
|
"user_id": req.UserID,
|
||||||
|
"status": web.NewEnumResponse(ctx, "active", user_account.UserAccountStatus_Values),
|
||||||
|
"roles": req.Roles,
|
||||||
|
"created_at": web.NewTimeResponse(ctx, actual.CreatedAt.Value),
|
||||||
|
}
|
||||||
|
|
||||||
|
var expected user_account.UserAccountResponse
|
||||||
|
if err := decodeMapToStruct(expectedMap, &expected); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v\nActual results to format expected : \n", err)
|
||||||
|
printResultMap(ctx, w.Body.Bytes()) // used to help format expectedMap
|
||||||
|
t.Fatalf("\t%s\tDecode expected failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
if len(expectedMap) == 0 {
|
||||||
|
printResultMap(ctx, w.Body.Bytes()) // used to help format expectedMap
|
||||||
|
}
|
||||||
|
t.Fatalf("\t%s\tReceived expected result.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected result.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test read.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusOK
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Read %d w/role %s", expectedStatus, tr.Role),
|
||||||
|
http.MethodGet,
|
||||||
|
fmt.Sprintf("/v1/user_accounts/%s", created.ID),
|
||||||
|
nil,
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual user_account.UserAccountResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, created); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected result.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected result.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test Read with random ID.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusNotFound
|
||||||
|
|
||||||
|
randID := uuid.NewRandom().String()
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Read %d w/role %s using random ID", expectedStatus, tr.Role),
|
||||||
|
http.MethodGet,
|
||||||
|
fmt.Sprintf("/v1/user_accounts/%s", randID),
|
||||||
|
nil,
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: fmt.Sprintf("user account %s not found: Entity not found", randID),
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test Read with forbidden ID.
|
||||||
|
forbiddenUserAccount := newMockUserAccount(newMockSignup().account.ID, user_account.UserAccountRole_Admin)
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusNotFound
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Read %d w/role %s using forbidden ID", expectedStatus, tr.Role),
|
||||||
|
http.MethodGet,
|
||||||
|
fmt.Sprintf("/v1/user_accounts/%s", forbiddenUserAccount.ID),
|
||||||
|
nil,
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: fmt.Sprintf("user account %s not found: Entity not found", forbiddenUserAccount.ID),
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test update.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusNoContent
|
||||||
|
|
||||||
|
newStatus := user_account.UserAccountStatus_Invited
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Update %d w/role %s", expectedStatus, tr.Role),
|
||||||
|
http.MethodPatch,
|
||||||
|
"/v1/user_accounts",
|
||||||
|
user_account.UserAccountUpdateRequest{
|
||||||
|
UserID: created.UserID,
|
||||||
|
AccountID: created.AccountID,
|
||||||
|
Status: &newStatus,
|
||||||
|
},
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
if len(w.Body.String()) != 0 {
|
||||||
|
if diff := cmpDiff(t, w.Body.Bytes(), nil); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected empty.", tests.Failed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected empty.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test archive.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusNoContent
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Archive %d w/role %s", expectedStatus, tr.Role),
|
||||||
|
http.MethodPatch,
|
||||||
|
"/v1/user_accounts/archive",
|
||||||
|
user_account.UserAccountArchiveRequest{
|
||||||
|
UserID: created.UserID,
|
||||||
|
AccountID: created.AccountID,
|
||||||
|
},
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
if len(w.Body.String()) != 0 {
|
||||||
|
if diff := cmpDiff(t, w.Body.Bytes(), nil); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected empty.", tests.Failed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected empty.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test delete.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusNoContent
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Delete %d w/role %s", expectedStatus, tr.Role),
|
||||||
|
http.MethodDelete,
|
||||||
|
"/v1/user_accounts",
|
||||||
|
user_account.UserAccountDeleteRequest{
|
||||||
|
UserID: created.UserID,
|
||||||
|
AccountID: created.AccountID,
|
||||||
|
},
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
if len(w.Body.String()) != 0 {
|
||||||
|
if diff := cmpDiff(t, w.Body.Bytes(), nil); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected empty.", tests.Failed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected empty.", tests.Success)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestUserAccountCRUDUser tests all the user account CRUD endpoints using an user with role user_account.
|
||||||
|
func TestUserAccountCRUDUser(t *testing.T) {
|
||||||
|
defer tests.Recover(t)
|
||||||
|
|
||||||
|
tr := roleTests[auth.RoleUser]
|
||||||
|
|
||||||
|
// Add claims to the context for the user_account.
|
||||||
|
ctx := context.WithValue(tests.Context(), auth.Key, tr.Claims)
|
||||||
|
|
||||||
|
// Test create.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusForbidden
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Create %d w/role %s", expectedStatus, tr.Role),
|
||||||
|
http.MethodPost,
|
||||||
|
"/v1/user_accounts",
|
||||||
|
user_account.UserAccountCreateRequest{
|
||||||
|
UserID: uuid.NewRandom().String(),
|
||||||
|
AccountID: tr.Account.ID,
|
||||||
|
Roles: []user_account.UserAccountRole{user_account.UserAccountRole_User},
|
||||||
|
},
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: mid.ErrForbidden.Error(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since role doesn't support create, bypass auth to test other endpoints.
|
||||||
|
created := newMockUserAccount(tr.Account.ID, user_account.UserAccountRole_User).Response(ctx)
|
||||||
|
|
||||||
|
// Test read.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusOK
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Read %d w/role %s", expectedStatus, tr.Role),
|
||||||
|
http.MethodGet,
|
||||||
|
fmt.Sprintf("/v1/user_accounts/%s", created.ID),
|
||||||
|
nil,
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual *user_account.UserAccountResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, created); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected result.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected result.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test Read with random ID.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusNotFound
|
||||||
|
|
||||||
|
randID := uuid.NewRandom().String()
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Read %d w/role %s using random ID", expectedStatus, tr.Role),
|
||||||
|
http.MethodGet,
|
||||||
|
fmt.Sprintf("/v1/user_accounts/%s", randID),
|
||||||
|
nil,
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: fmt.Sprintf("user account %s not found: Entity not found", randID),
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test Read with forbidden ID.
|
||||||
|
forbiddenUserAccount := newMockUserAccount(newMockSignup().account.ID, user_account.UserAccountRole_Admin)
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusNotFound
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Read %d w/role %s using forbidden ID", expectedStatus, tr.Role),
|
||||||
|
http.MethodGet,
|
||||||
|
fmt.Sprintf("/v1/user_accounts/%s", forbiddenUserAccount.ID),
|
||||||
|
nil,
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: fmt.Sprintf("user account %s not found: Entity not found", forbiddenUserAccount.ID),
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test update.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusForbidden
|
||||||
|
|
||||||
|
newStatus := user_account.UserAccountStatus_Invited
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Update %d w/role %s", expectedStatus, tr.Role),
|
||||||
|
http.MethodPatch,
|
||||||
|
"/v1/user_accounts",
|
||||||
|
user_account.UserAccountUpdateRequest{
|
||||||
|
UserID: created.UserID,
|
||||||
|
AccountID: created.AccountID,
|
||||||
|
Status: &newStatus,
|
||||||
|
},
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: account.ErrForbidden.Error(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test archive.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusForbidden
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Archive %d w/role %s", expectedStatus, tr.Role),
|
||||||
|
http.MethodPatch,
|
||||||
|
"/v1/user_accounts/archive",
|
||||||
|
user_account.UserAccountArchiveRequest{
|
||||||
|
UserID: created.UserID,
|
||||||
|
AccountID: created.AccountID,
|
||||||
|
},
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: mid.ErrForbidden.Error(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test delete.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusForbidden
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Delete %d w/role %s", expectedStatus, tr.Role),
|
||||||
|
http.MethodDelete,
|
||||||
|
"/v1/user_accounts",
|
||||||
|
user_account.UserAccountArchiveRequest{
|
||||||
|
UserID: created.UserID,
|
||||||
|
AccountID: created.AccountID,
|
||||||
|
},
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: mid.ErrForbidden.Error(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestUserAccountCreate validates create user account endpoint.
|
||||||
|
func TestUserAccountCreate(t *testing.T) {
|
||||||
|
defer tests.Recover(t)
|
||||||
|
|
||||||
|
tr := roleTests[auth.RoleAdmin]
|
||||||
|
|
||||||
|
// Add claims to the context for the user_account.
|
||||||
|
ctx := context.WithValue(tests.Context(), auth.Key, tr.Claims)
|
||||||
|
|
||||||
|
// Test create with invalid data.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusBadRequest
|
||||||
|
|
||||||
|
invalidStatus := user_account.UserAccountStatus("invalid status")
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Create %d w/role %s using invalid data", expectedStatus, tr.Role),
|
||||||
|
http.MethodPost,
|
||||||
|
"/v1/user_accounts",
|
||||||
|
user_account.UserAccountCreateRequest{
|
||||||
|
UserID: uuid.NewRandom().String(),
|
||||||
|
AccountID: tr.Account.ID,
|
||||||
|
Roles: []user_account.UserAccountRole{user_account.UserAccountRole_User},
|
||||||
|
Status: &invalidStatus,
|
||||||
|
},
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: "field validation error",
|
||||||
|
Fields: []web.FieldError{
|
||||||
|
{Field: "status", Error: "Key: 'UserAccountCreateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestUserAccountUpdate validates update user account endpoint.
|
||||||
|
func TestUserAccountUpdate(t *testing.T) {
|
||||||
|
defer tests.Recover(t)
|
||||||
|
|
||||||
|
tr := roleTests[auth.RoleAdmin]
|
||||||
|
|
||||||
|
// Add claims to the context for the user_account.
|
||||||
|
ctx := context.WithValue(tests.Context(), auth.Key, tr.Claims)
|
||||||
|
|
||||||
|
// Test update with invalid data.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusBadRequest
|
||||||
|
|
||||||
|
invalidStatus := user_account.UserAccountStatus("invalid status")
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Update %d w/role %s using invalid data", expectedStatus, tr.Role),
|
||||||
|
http.MethodPatch,
|
||||||
|
"/v1/user_accounts",
|
||||||
|
user_account.UserAccountUpdateRequest{
|
||||||
|
UserID: uuid.NewRandom().String(),
|
||||||
|
AccountID: uuid.NewRandom().String(),
|
||||||
|
Status: &invalidStatus,
|
||||||
|
},
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: "field validation error",
|
||||||
|
Fields: []web.FieldError{
|
||||||
|
{Field: "status", Error: "Key: 'UserAccountUpdateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestUserAccountArchive validates archive user account endpoint.
|
||||||
|
func TestUserAccountArchive(t *testing.T) {
|
||||||
|
defer tests.Recover(t)
|
||||||
|
|
||||||
|
tr := roleTests[auth.RoleAdmin]
|
||||||
|
|
||||||
|
// Add claims to the context for the user_account.
|
||||||
|
ctx := context.WithValue(tests.Context(), auth.Key, tr.Claims)
|
||||||
|
|
||||||
|
// Test archive with invalid data.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusBadRequest
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Archive %d w/role %s using invalid data", expectedStatus, tr.Role),
|
||||||
|
http.MethodPatch,
|
||||||
|
"/v1/user_accounts/archive",
|
||||||
|
user_account.UserAccountArchiveRequest{
|
||||||
|
UserID: "foo",
|
||||||
|
AccountID: "bar",
|
||||||
|
},
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: "field validation error",
|
||||||
|
Fields: []web.FieldError{
|
||||||
|
{Field: "user_id", Error: "Key: 'UserAccountArchiveRequest.user_id' Error:Field validation for 'user_id' failed on the 'uuid' tag"},
|
||||||
|
{Field: "account_id", Error: "Key: 'UserAccountArchiveRequest.account_id' Error:Field validation for 'account_id' failed on the 'uuid' tag"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test archive with forbidden ID.
|
||||||
|
forbiddenUserAccount := newMockUserAccount(newMockSignup().account.ID, user_account.UserAccountRole_Admin)
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusForbidden
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Archive %d w/role %s using forbidden IDs", expectedStatus, tr.Role),
|
||||||
|
http.MethodPatch,
|
||||||
|
"/v1/user_accounts/archive",
|
||||||
|
user_account.UserAccountArchiveRequest{
|
||||||
|
UserID: forbiddenUserAccount.UserID,
|
||||||
|
AccountID: forbiddenUserAccount.AccountID,
|
||||||
|
},
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: user_account.ErrForbidden.Error(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestUserAccountDelete validates delete user account endpoint.
|
||||||
|
func TestUserAccountDelete(t *testing.T) {
|
||||||
|
defer tests.Recover(t)
|
||||||
|
|
||||||
|
tr := roleTests[auth.RoleAdmin]
|
||||||
|
|
||||||
|
// Add claims to the context for the user_account.
|
||||||
|
ctx := context.WithValue(tests.Context(), auth.Key, tr.Claims)
|
||||||
|
|
||||||
|
// Test delete with invalid data.
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusBadRequest
|
||||||
|
|
||||||
|
req := user_account.UserAccountDeleteRequest{
|
||||||
|
UserID: "foo",
|
||||||
|
AccountID: "bar",
|
||||||
|
}
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Delete %d w/role %s using invalid data", expectedStatus, tr.Role),
|
||||||
|
http.MethodDelete,
|
||||||
|
"/v1/user_accounts",
|
||||||
|
req,
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: "field validation error",
|
||||||
|
Fields: []web.FieldError{
|
||||||
|
{Field: "user_id", Error: "Key: 'UserAccountDeleteRequest.user_id' Error:Field validation for 'user_id' failed on the 'uuid' tag"},
|
||||||
|
{Field: "account_id", Error: "Key: 'UserAccountDeleteRequest.account_id' Error:Field validation for 'account_id' failed on the 'uuid' tag"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test delete with forbidden ID.
|
||||||
|
forbiddenUserAccount := newMockUserAccount(newMockSignup().account.ID, user_account.UserAccountRole_Admin)
|
||||||
|
{
|
||||||
|
expectedStatus := http.StatusForbidden
|
||||||
|
|
||||||
|
rt := requestTest{
|
||||||
|
fmt.Sprintf("Delete %d w/role %s using forbidden IDs", expectedStatus, tr.Role),
|
||||||
|
http.MethodDelete,
|
||||||
|
fmt.Sprintf("/v1/user_accounts"),
|
||||||
|
user_account.UserAccountDeleteRequest{
|
||||||
|
UserID: forbiddenUserAccount.UserID,
|
||||||
|
AccountID: forbiddenUserAccount.AccountID,
|
||||||
|
},
|
||||||
|
tr.Token,
|
||||||
|
tr.Claims,
|
||||||
|
expectedStatus,
|
||||||
|
nil,
|
||||||
|
}
|
||||||
|
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||||
|
|
||||||
|
w, ok := executeRequestTest(t, rt, ctx)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||||
|
|
||||||
|
var actual web.ErrorResponse
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||||
|
t.Logf("\t\tGot error : %+v", err)
|
||||||
|
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := web.ErrorResponse{
|
||||||
|
Error: user_account.ErrForbidden.Error(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmpDiff(t, actual, expected); diff {
|
||||||
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
||||||
|
}
|
||||||
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -568,7 +568,7 @@ func Delete(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, accountID
|
|||||||
|
|
||||||
// Defines the struct to apply validation
|
// Defines the struct to apply validation
|
||||||
req := struct {
|
req := struct {
|
||||||
ID string `validate:"required,uuid"`
|
ID string `json:"id" validate:"required,uuid"`
|
||||||
}{
|
}{
|
||||||
ID: accountID,
|
ID: accountID,
|
||||||
}
|
}
|
||||||
|
@ -151,12 +151,12 @@ func TestCreateValidation(t *testing.T) {
|
|||||||
func(req AccountCreateRequest, res *Account) *Account {
|
func(req AccountCreateRequest, res *Account) *Account {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
errors.New("Key: 'AccountCreateRequest.Name' Error:Field validation for 'Name' failed on the 'required' tag\n" +
|
errors.New("Key: 'AccountCreateRequest.name' Error:Field validation for 'name' failed on the 'required' tag\n" +
|
||||||
"Key: 'AccountCreateRequest.Address1' Error:Field validation for 'Address1' failed on the 'required' tag\n" +
|
"Key: 'AccountCreateRequest.address1' Error:Field validation for 'address1' failed on the 'required' tag\n" +
|
||||||
"Key: 'AccountCreateRequest.City' Error:Field validation for 'City' failed on the 'required' tag\n" +
|
"Key: 'AccountCreateRequest.city' Error:Field validation for 'city' failed on the 'required' tag\n" +
|
||||||
"Key: 'AccountCreateRequest.Region' Error:Field validation for 'Region' failed on the 'required' tag\n" +
|
"Key: 'AccountCreateRequest.region' Error:Field validation for 'region' failed on the 'required' tag\n" +
|
||||||
"Key: 'AccountCreateRequest.Country' Error:Field validation for 'Country' failed on the 'required' tag\n" +
|
"Key: 'AccountCreateRequest.country' Error:Field validation for 'country' failed on the 'required' tag\n" +
|
||||||
"Key: 'AccountCreateRequest.Zipcode' Error:Field validation for 'Zipcode' failed on the 'required' tag"),
|
"Key: 'AccountCreateRequest.zipcode' Error:Field validation for 'zipcode' failed on the 'required' tag"),
|
||||||
},
|
},
|
||||||
|
|
||||||
{"Default Timezone & Status",
|
{"Default Timezone & Status",
|
||||||
@ -204,7 +204,7 @@ func TestCreateValidation(t *testing.T) {
|
|||||||
func(req AccountCreateRequest, res *Account) *Account {
|
func(req AccountCreateRequest, res *Account) *Account {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
errors.New("Key: 'AccountCreateRequest.Status' Error:Field validation for 'Status' failed on the 'oneof' tag"),
|
errors.New("Key: 'AccountCreateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,7 +286,7 @@ func TestCreateValidationNameUnique(t *testing.T) {
|
|||||||
Country: "USA",
|
Country: "USA",
|
||||||
Zipcode: "99686",
|
Zipcode: "99686",
|
||||||
}
|
}
|
||||||
expectedErr := errors.New("Key: 'AccountCreateRequest.Name' Error:Field validation for 'Name' failed on the 'unique' tag")
|
expectedErr := errors.New("Key: 'AccountCreateRequest.name' Error:Field validation for 'name' failed on the 'unique' tag")
|
||||||
_, err = Create(ctx, auth.Claims{}, test.MasterDB, req2, now)
|
_, err = Create(ctx, auth.Claims{}, test.MasterDB, req2, now)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Logf("\t\tWant: %+v", expectedErr)
|
t.Logf("\t\tWant: %+v", expectedErr)
|
||||||
@ -403,7 +403,7 @@ func TestUpdateValidation(t *testing.T) {
|
|||||||
var accountTests = []accountTest{
|
var accountTests = []accountTest{
|
||||||
{"Required Fields",
|
{"Required Fields",
|
||||||
AccountUpdateRequest{},
|
AccountUpdateRequest{},
|
||||||
errors.New("Key: 'AccountUpdateRequest.ID' Error:Field validation for 'ID' failed on the 'required' tag"),
|
errors.New("Key: 'AccountUpdateRequest.id' Error:Field validation for 'id' failed on the 'required' tag"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,7 +413,7 @@ func TestUpdateValidation(t *testing.T) {
|
|||||||
ID: uuid.NewRandom().String(),
|
ID: uuid.NewRandom().String(),
|
||||||
Status: &invalidStatus,
|
Status: &invalidStatus,
|
||||||
},
|
},
|
||||||
errors.New("Key: 'AccountUpdateRequest.Status' Error:Field validation for 'Status' failed on the 'oneof' tag"),
|
errors.New("Key: 'AccountUpdateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"),
|
||||||
})
|
})
|
||||||
|
|
||||||
now := time.Date(2018, time.October, 1, 0, 0, 0, 0, time.UTC)
|
now := time.Date(2018, time.October, 1, 0, 0, 0, 0, time.UTC)
|
||||||
@ -494,7 +494,7 @@ func TestUpdateValidationNameUnique(t *testing.T) {
|
|||||||
ID: account2.ID,
|
ID: account2.ID,
|
||||||
Name: &account1.Name,
|
Name: &account1.Name,
|
||||||
}
|
}
|
||||||
expectedErr := errors.New("Key: 'AccountUpdateRequest.Name' Error:Field validation for 'Name' failed on the 'unique' tag")
|
expectedErr := errors.New("Key: 'AccountUpdateRequest.name' Error:Field validation for 'name' failed on the 'unique' tag")
|
||||||
err = Update(ctx, auth.Claims{}, test.MasterDB, updateReq, now)
|
err = Update(ctx, auth.Claims{}, test.MasterDB, updateReq, now)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Logf("\t\tWant: %+v", expectedErr)
|
t.Logf("\t\tWant: %+v", expectedErr)
|
||||||
|
@ -119,6 +119,3 @@ func parseAuthHeader(bearerStr string) (string, error) {
|
|||||||
|
|
||||||
return split[1], nil
|
return split[1], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -130,7 +130,6 @@ func ExtractWhereArgs(where string) (string, []interface{}, error) {
|
|||||||
return where, vals, nil
|
return where, vals, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func RequestIsJson(r *http.Request) bool {
|
func RequestIsJson(r *http.Request) bool {
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return false
|
return false
|
||||||
@ -155,4 +154,3 @@ func RequestIsJson(r *http.Request) bool {
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ func Read(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, id string, i
|
|||||||
|
|
||||||
res, err := find(ctx, claims, dbConn, query, []interface{}{}, includedArchived)
|
res, err := find(ctx, claims, dbConn, query, []interface{}{}, includedArchived)
|
||||||
if res == nil || len(res) == 0 {
|
if res == nil || len(res) == 0 {
|
||||||
err = errors.WithMessagef(ErrNotFound, "account %s not found", id)
|
err = errors.WithMessagef(ErrNotFound, "project %s not found", id)
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -424,8 +424,10 @@ func Delete(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, id string)
|
|||||||
|
|
||||||
// Defines the struct to apply validation
|
// Defines the struct to apply validation
|
||||||
req := struct {
|
req := struct {
|
||||||
ID string `validate:"required,uuid"`
|
ID string `json:"id" validate:"required,uuid"`
|
||||||
}{}
|
}{
|
||||||
|
ID: id,
|
||||||
|
}
|
||||||
|
|
||||||
// Validate the request.
|
// Validate the request.
|
||||||
v := web.NewValidator()
|
v := web.NewValidator()
|
||||||
|
@ -61,4 +61,3 @@ func (m *SignupResult) Response(ctx context.Context) *SignupResponse {
|
|||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,6 @@ func Signup(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, req Signup
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
f := func(fl validator.FieldLevel) bool {
|
f := func(fl validator.FieldLevel) bool {
|
||||||
if fl.Field().String() == "invalid" {
|
if fl.Field().String() == "invalid" {
|
||||||
return false
|
return false
|
||||||
|
@ -40,15 +40,15 @@ func TestSignupValidation(t *testing.T) {
|
|||||||
func(req SignupRequest, res *SignupResult) *SignupResult {
|
func(req SignupRequest, res *SignupResult) *SignupResult {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
errors.New("Key: 'SignupRequest.Account.Name' Error:Field validation for 'Name' failed on the 'required' tag\n" +
|
errors.New("Key: 'SignupRequest.account.name' Error:Field validation for 'name' failed on the 'required' tag\n" +
|
||||||
"Key: 'SignupRequest.Account.Address1' Error:Field validation for 'Address1' failed on the 'required' tag\n" +
|
"Key: 'SignupRequest.account.address1' Error:Field validation for 'address1' failed on the 'required' tag\n" +
|
||||||
"Key: 'SignupRequest.Account.City' Error:Field validation for 'City' failed on the 'required' tag\n" +
|
"Key: 'SignupRequest.account.city' Error:Field validation for 'city' failed on the 'required' tag\n" +
|
||||||
"Key: 'SignupRequest.Account.Region' Error:Field validation for 'Region' failed on the 'required' tag\n" +
|
"Key: 'SignupRequest.account.region' Error:Field validation for 'region' failed on the 'required' tag\n" +
|
||||||
"Key: 'SignupRequest.Account.Country' Error:Field validation for 'Country' failed on the 'required' tag\n" +
|
"Key: 'SignupRequest.account.country' Error:Field validation for 'country' failed on the 'required' tag\n" +
|
||||||
"Key: 'SignupRequest.Account.Zipcode' Error:Field validation for 'Zipcode' failed on the 'required' tag\n" +
|
"Key: 'SignupRequest.account.zipcode' Error:Field validation for 'zipcode' failed on the 'required' tag\n" +
|
||||||
"Key: 'SignupRequest.User.Name' Error:Field validation for 'Name' failed on the 'required' tag\n" +
|
"Key: 'SignupRequest.user.name' Error:Field validation for 'name' failed on the 'required' tag\n" +
|
||||||
"Key: 'SignupRequest.User.Email' Error:Field validation for 'Email' failed on the 'required' tag\n" +
|
"Key: 'SignupRequest.user.email' Error:Field validation for 'email' failed on the 'required' tag\n" +
|
||||||
"Key: 'SignupRequest.User.Password' Error:Field validation for 'Password' failed on the 'required' tag"),
|
"Key: 'SignupRequest.user.password' Error:Field validation for 'password' failed on the 'required' tag"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,8 +72,8 @@ func SwitchAccount(ctx context.Context, dbConn *sqlx.DB, tknGen TokenGenerator,
|
|||||||
|
|
||||||
// Defines struct to apply validation for the supplied claims and account ID.
|
// Defines struct to apply validation for the supplied claims and account ID.
|
||||||
req := struct {
|
req := struct {
|
||||||
UserID string `validate:"required,uuid"`
|
UserID string `json:"user_id" validate:"required,uuid"`
|
||||||
AccountID string `validate:"required,uuid"`
|
AccountID string `json:"account_id" validate:"required,uuid"`
|
||||||
}{
|
}{
|
||||||
UserID: claims.Subject,
|
UserID: claims.Subject,
|
||||||
AccountID: accountID,
|
AccountID: accountID,
|
||||||
|
@ -90,6 +90,22 @@ func CanReadUser(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, userI
|
|||||||
|
|
||||||
// CanModifyUser determines if claims has the authority to modify the specified user ID.
|
// CanModifyUser determines if claims has the authority to modify the specified user ID.
|
||||||
func CanModifyUser(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, userID string) error {
|
func CanModifyUser(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, userID string) error {
|
||||||
|
// If the request has claims from a specific user, ensure that the user
|
||||||
|
// has the correct role for creating a new user.
|
||||||
|
if claims.Subject != "" && claims.Subject != userID {
|
||||||
|
// Users with the role of admin are ony allows to create users.
|
||||||
|
if !claims.HasRole(auth.RoleAdmin) {
|
||||||
|
err := errors.WithStack(ErrForbidden)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := CanReadUser(ctx, claims, dbConn, userID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Review, this doesn't seem correct, replaced with above.
|
||||||
|
/*
|
||||||
// If the request has claims from a specific account, ensure that the user
|
// If the request has claims from a specific account, ensure that the user
|
||||||
// has the correct access to the account.
|
// has the correct access to the account.
|
||||||
if claims.Subject != "" && claims.Subject != userID {
|
if claims.Subject != "" && claims.Subject != userID {
|
||||||
@ -118,6 +134,7 @@ func CanModifyUser(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, use
|
|||||||
return errors.WithStack(ErrForbidden)
|
return errors.WithStack(ErrForbidden)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -598,7 +615,7 @@ func Delete(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, userID str
|
|||||||
|
|
||||||
// Defines the struct to apply validation
|
// Defines the struct to apply validation
|
||||||
req := struct {
|
req := struct {
|
||||||
ID string `validate:"required,uuid"`
|
ID string `json:"id" validate:"required,uuid"`
|
||||||
}{
|
}{
|
||||||
ID: userID,
|
ID: userID,
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/lib/pq"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@ -13,6 +12,7 @@ import (
|
|||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/huandu/go-sqlbuilder"
|
"github.com/huandu/go-sqlbuilder"
|
||||||
|
"github.com/lib/pq"
|
||||||
"github.com/pborman/uuid"
|
"github.com/pborman/uuid"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@ -149,9 +149,9 @@ func TestCreateValidation(t *testing.T) {
|
|||||||
func(req UserCreateRequest, res *User) *User {
|
func(req UserCreateRequest, res *User) *User {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
errors.New("Key: 'UserCreateRequest.Name' Error:Field validation for 'Name' failed on the 'required' tag\n" +
|
errors.New("Key: 'UserCreateRequest.name' Error:Field validation for 'name' failed on the 'required' tag\n" +
|
||||||
"Key: 'UserCreateRequest.Email' Error:Field validation for 'Email' failed on the 'required' tag\n" +
|
"Key: 'UserCreateRequest.email' Error:Field validation for 'email' failed on the 'required' tag\n" +
|
||||||
"Key: 'UserCreateRequest.Password' Error:Field validation for 'Password' failed on the 'required' tag"),
|
"Key: 'UserCreateRequest.password' Error:Field validation for 'password' failed on the 'required' tag"),
|
||||||
},
|
},
|
||||||
{"Valid Email",
|
{"Valid Email",
|
||||||
UserCreateRequest{
|
UserCreateRequest{
|
||||||
@ -163,7 +163,7 @@ func TestCreateValidation(t *testing.T) {
|
|||||||
func(req UserCreateRequest, res *User) *User {
|
func(req UserCreateRequest, res *User) *User {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
errors.New("Key: 'UserCreateRequest.Email' Error:Field validation for 'Email' failed on the 'email' tag"),
|
errors.New("Key: 'UserCreateRequest.email' Error:Field validation for 'email' failed on the 'email' tag"),
|
||||||
},
|
},
|
||||||
{"Passwords Match",
|
{"Passwords Match",
|
||||||
UserCreateRequest{
|
UserCreateRequest{
|
||||||
@ -175,7 +175,7 @@ func TestCreateValidation(t *testing.T) {
|
|||||||
func(req UserCreateRequest, res *User) *User {
|
func(req UserCreateRequest, res *User) *User {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
errors.New("Key: 'UserCreateRequest.PasswordConfirm' Error:Field validation for 'PasswordConfirm' failed on the 'eqfield' tag"),
|
errors.New("Key: 'UserCreateRequest.password_confirm' Error:Field validation for 'password_confirm' failed on the 'eqfield' tag"),
|
||||||
},
|
},
|
||||||
{"Default Timezone",
|
{"Default Timezone",
|
||||||
UserCreateRequest{
|
UserCreateRequest{
|
||||||
@ -276,7 +276,7 @@ func TestCreateValidationEmailUnique(t *testing.T) {
|
|||||||
Password: "W0rkL1fe#",
|
Password: "W0rkL1fe#",
|
||||||
PasswordConfirm: "W0rkL1fe#",
|
PasswordConfirm: "W0rkL1fe#",
|
||||||
}
|
}
|
||||||
expectedErr := errors.New("Key: 'UserCreateRequest.Email' Error:Field validation for 'Email' failed on the 'unique' tag")
|
expectedErr := errors.New("Key: 'UserCreateRequest.email' Error:Field validation for 'email' failed on the 'unique' tag")
|
||||||
_, err = Create(ctx, auth.Claims{}, test.MasterDB, req2, now)
|
_, err = Create(ctx, auth.Claims{}, test.MasterDB, req2, now)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Logf("\t\tWant: %+v", expectedErr)
|
t.Logf("\t\tWant: %+v", expectedErr)
|
||||||
@ -384,7 +384,7 @@ func TestUpdateValidation(t *testing.T) {
|
|||||||
var userTests = []userTest{
|
var userTests = []userTest{
|
||||||
{"Required Fields",
|
{"Required Fields",
|
||||||
UserUpdateRequest{},
|
UserUpdateRequest{},
|
||||||
errors.New("Key: 'UserUpdateRequest.ID' Error:Field validation for 'ID' failed on the 'required' tag"),
|
errors.New("Key: 'UserUpdateRequest.id' Error:Field validation for 'id' failed on the 'required' tag"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,7 +394,7 @@ func TestUpdateValidation(t *testing.T) {
|
|||||||
ID: uuid.NewRandom().String(),
|
ID: uuid.NewRandom().String(),
|
||||||
Email: &invalidEmail,
|
Email: &invalidEmail,
|
||||||
},
|
},
|
||||||
errors.New("Key: 'UserUpdateRequest.Email' Error:Field validation for 'Email' failed on the 'email' tag"),
|
errors.New("Key: 'UserUpdateRequest.email' Error:Field validation for 'email' failed on the 'email' tag"),
|
||||||
})
|
})
|
||||||
|
|
||||||
now := time.Date(2018, time.October, 1, 0, 0, 0, 0, time.UTC)
|
now := time.Date(2018, time.October, 1, 0, 0, 0, 0, time.UTC)
|
||||||
@ -469,7 +469,7 @@ func TestUpdateValidationEmailUnique(t *testing.T) {
|
|||||||
ID: user2.ID,
|
ID: user2.ID,
|
||||||
Email: &user1.Email,
|
Email: &user1.Email,
|
||||||
}
|
}
|
||||||
expectedErr := errors.New("Key: 'UserUpdateRequest.Email' Error:Field validation for 'Email' failed on the 'unique' tag")
|
expectedErr := errors.New("Key: 'UserUpdateRequest.email' Error:Field validation for 'email' failed on the 'unique' tag")
|
||||||
err = Update(ctx, auth.Claims{}, test.MasterDB, updateReq, now)
|
err = Update(ctx, auth.Claims{}, test.MasterDB, updateReq, now)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Logf("\t\tWant: %+v", expectedErr)
|
t.Logf("\t\tWant: %+v", expectedErr)
|
||||||
@ -533,8 +533,8 @@ func TestUpdatePassword(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure validation is working by trying UpdatePassword with an empty request.
|
// Ensure validation is working by trying UpdatePassword with an empty request.
|
||||||
expectedErr := errors.New("Key: 'UserUpdatePasswordRequest.ID' Error:Field validation for 'ID' failed on the 'required' tag\n" +
|
expectedErr := errors.New("Key: 'UserUpdatePasswordRequest.id' Error:Field validation for 'id' failed on the 'required' tag\n" +
|
||||||
"Key: 'UserUpdatePasswordRequest.Password' Error:Field validation for 'Password' failed on the 'required' tag")
|
"Key: 'UserUpdatePasswordRequest.password' Error:Field validation for 'password' failed on the 'required' tag")
|
||||||
err = UpdatePassword(ctx, auth.Claims{}, test.MasterDB, UserUpdatePasswordRequest{}, now)
|
err = UpdatePassword(ctx, auth.Claims{}, test.MasterDB, UserUpdatePasswordRequest{}, now)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Logf("\t\tWant: %+v", expectedErr)
|
t.Logf("\t\tWant: %+v", expectedErr)
|
||||||
|
@ -53,7 +53,7 @@ func (m *UserAccount) Response(ctx context.Context) *UserAccountResponse {
|
|||||||
UserID: m.UserID,
|
UserID: m.UserID,
|
||||||
AccountID: m.AccountID,
|
AccountID: m.AccountID,
|
||||||
Roles: m.Roles,
|
Roles: m.Roles,
|
||||||
Status: web.NewEnumResponse(ctx, m.Status, UserAccountRole_Values),
|
Status: web.NewEnumResponse(ctx, m.Status, UserAccountStatus_Values),
|
||||||
CreatedAt: web.NewTimeResponse(ctx, m.CreatedAt),
|
CreatedAt: web.NewTimeResponse(ctx, m.CreatedAt),
|
||||||
UpdatedAt: web.NewTimeResponse(ctx, m.UpdatedAt),
|
UpdatedAt: web.NewTimeResponse(ctx, m.UpdatedAt),
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ type UserAccountCreateRequest struct {
|
|||||||
type UserAccountUpdateRequest struct {
|
type UserAccountUpdateRequest struct {
|
||||||
UserID string `json:"user_id" validate:"required,uuid" example:"d69bdef7-173f-4d29-b52c-3edc60baf6a2"`
|
UserID string `json:"user_id" validate:"required,uuid" example:"d69bdef7-173f-4d29-b52c-3edc60baf6a2"`
|
||||||
AccountID string `json:"account_id" validate:"required,uuid" example:"c4653bf9-5978-48b7-89c5-95704aebb7e2"`
|
AccountID string `json:"account_id" validate:"required,uuid" example:"c4653bf9-5978-48b7-89c5-95704aebb7e2"`
|
||||||
Roles *UserAccountRoles `json:"roles,omitempty" validate:"required,dive,oneof=admin user" enums:"admin,user" swaggertype:"array,string" example:"user"`
|
Roles *UserAccountRoles `json:"roles,omitempty" validate:"omitempty,dive,oneof=admin user" enums:"admin,user" swaggertype:"array,string" example:"user"`
|
||||||
Status *UserAccountStatus `json:"status,omitempty" validate:"omitempty,oneof=active invited disabled" enums:"active,invited,disabled" swaggertype:"string" example:"disabled"`
|
Status *UserAccountStatus `json:"status,omitempty" validate:"omitempty,oneof=active invited disabled" enums:"active,invited,disabled" swaggertype:"string" example:"disabled"`
|
||||||
unArchive bool `json:"-"` // Internal use only.
|
unArchive bool `json:"-"` // Internal use only.
|
||||||
}
|
}
|
||||||
|
@ -300,7 +300,7 @@ func Read(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, id string, i
|
|||||||
|
|
||||||
res, err := find(ctx, claims, dbConn, query, []interface{}{}, includedArchived)
|
res, err := find(ctx, claims, dbConn, query, []interface{}{}, includedArchived)
|
||||||
if res == nil || len(res) == 0 {
|
if res == nil || len(res) == 0 {
|
||||||
err = errors.WithMessagef(ErrNotFound, "account %s not found", id)
|
err = errors.WithMessagef(ErrNotFound, "user account %s not found", id)
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -152,9 +152,9 @@ func TestCreateValidation(t *testing.T) {
|
|||||||
func(req UserAccountCreateRequest, res *UserAccount) *UserAccount {
|
func(req UserAccountCreateRequest, res *UserAccount) *UserAccount {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
errors.New("Key: 'UserAccountCreateRequest.UserID' Error:Field validation for 'UserID' failed on the 'required' tag\n" +
|
errors.New("Key: 'UserAccountCreateRequest.user_id' Error:Field validation for 'user_id' failed on the 'required' tag\n" +
|
||||||
"Key: 'UserAccountCreateRequest.AccountID' Error:Field validation for 'AccountID' failed on the 'required' tag\n" +
|
"Key: 'UserAccountCreateRequest.account_id' Error:Field validation for 'account_id' failed on the 'required' tag\n" +
|
||||||
"Key: 'UserAccountCreateRequest.Roles' Error:Field validation for 'Roles' failed on the 'required' tag"),
|
"Key: 'UserAccountCreateRequest.roles' Error:Field validation for 'roles' failed on the 'required' tag"),
|
||||||
},
|
},
|
||||||
{"Valid Role",
|
{"Valid Role",
|
||||||
UserAccountCreateRequest{
|
UserAccountCreateRequest{
|
||||||
@ -165,7 +165,7 @@ func TestCreateValidation(t *testing.T) {
|
|||||||
func(req UserAccountCreateRequest, res *UserAccount) *UserAccount {
|
func(req UserAccountCreateRequest, res *UserAccount) *UserAccount {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
errors.New("Key: 'UserAccountCreateRequest.Roles[0]' Error:Field validation for 'Roles[0]' failed on the 'oneof' tag"),
|
errors.New("Key: 'UserAccountCreateRequest.roles[0]' Error:Field validation for 'roles[0]' failed on the 'oneof' tag"),
|
||||||
},
|
},
|
||||||
{"Valid Status",
|
{"Valid Status",
|
||||||
UserAccountCreateRequest{
|
UserAccountCreateRequest{
|
||||||
@ -177,7 +177,7 @@ func TestCreateValidation(t *testing.T) {
|
|||||||
func(req UserAccountCreateRequest, res *UserAccount) *UserAccount {
|
func(req UserAccountCreateRequest, res *UserAccount) *UserAccount {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
errors.New("Key: 'UserAccountCreateRequest.Status' Error:Field validation for 'Status' failed on the 'oneof' tag"),
|
errors.New("Key: 'UserAccountCreateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"),
|
||||||
},
|
},
|
||||||
{"Default Status",
|
{"Default Status",
|
||||||
UserAccountCreateRequest{
|
UserAccountCreateRequest{
|
||||||
@ -373,9 +373,8 @@ func TestUpdateValidation(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{"Required Fields",
|
{"Required Fields",
|
||||||
UserAccountUpdateRequest{},
|
UserAccountUpdateRequest{},
|
||||||
errors.New("Key: 'UserAccountUpdateRequest.UserID' Error:Field validation for 'UserID' failed on the 'required' tag\n" +
|
errors.New("Key: 'UserAccountUpdateRequest.user_id' Error:Field validation for 'user_id' failed on the 'required' tag\n" +
|
||||||
"Key: 'UserAccountUpdateRequest.AccountID' Error:Field validation for 'AccountID' failed on the 'required' tag\n" +
|
"Key: 'UserAccountUpdateRequest.account_id' Error:Field validation for 'account_id' failed on the 'required' tag"),
|
||||||
"Key: 'UserAccountUpdateRequest.Roles' Error:Field validation for 'Roles' failed on the 'required' tag"),
|
|
||||||
},
|
},
|
||||||
{"Valid Role",
|
{"Valid Role",
|
||||||
UserAccountUpdateRequest{
|
UserAccountUpdateRequest{
|
||||||
@ -383,7 +382,7 @@ func TestUpdateValidation(t *testing.T) {
|
|||||||
AccountID: uuid.NewRandom().String(),
|
AccountID: uuid.NewRandom().String(),
|
||||||
Roles: &UserAccountRoles{invalidRole},
|
Roles: &UserAccountRoles{invalidRole},
|
||||||
},
|
},
|
||||||
errors.New("Key: 'UserAccountUpdateRequest.Roles[0]' Error:Field validation for 'Roles[0]' failed on the 'oneof' tag"),
|
errors.New("Key: 'UserAccountUpdateRequest.roles[0]' Error:Field validation for 'roles[0]' failed on the 'oneof' tag"),
|
||||||
},
|
},
|
||||||
|
|
||||||
{"Valid Status",
|
{"Valid Status",
|
||||||
@ -393,7 +392,7 @@ func TestUpdateValidation(t *testing.T) {
|
|||||||
Roles: &UserAccountRoles{UserAccountRole_User},
|
Roles: &UserAccountRoles{UserAccountRole_User},
|
||||||
Status: &invalidStatus,
|
Status: &invalidStatus,
|
||||||
},
|
},
|
||||||
errors.New("Key: 'UserAccountUpdateRequest.Status' Error:Field validation for 'Status' failed on the 'oneof' tag"),
|
errors.New("Key: 'UserAccountUpdateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user