You've already forked golang-saas-starter-kit
mirror of
https://github.com/raseels-repos/golang-saas-starter-kit.git
synced 2025-06-25 00:46:51 +02:00
Complated web-api crud endpoints and unittests. unittest for find
endpoints still need to be implemented.
This commit is contained in:
example-project
cmd
web-api
internal
account
mid
platform
project
signup
user
user_account
@ -5,335 +5,507 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"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/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"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/pborman/uuid"
|
||||
)
|
||||
|
||||
func mockAccount() *account.Account {
|
||||
req := account.AccountCreateRequest{
|
||||
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) {
|
||||
// TestAccountCRUDAdmin tests all the account CRUD endpoints using an user with role admin.
|
||||
func TestAccountCRUDAdmin(t *testing.T) {
|
||||
defer tests.Recover(t)
|
||||
|
||||
t.Run("getAccount", getAccount)
|
||||
t.Run("patchAccount", patchAccount)
|
||||
}
|
||||
tr := roleTests[auth.RoleAdmin]
|
||||
|
||||
// getAccount validates get account by ID endpoint.
|
||||
func getAccount(t *testing.T) {
|
||||
s := newMockSignup()
|
||||
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()
|
||||
|
||||
// Both roles should be able to read the account.
|
||||
for rn, tr := range roleTests {
|
||||
acc := tr.SignupResult.Account
|
||||
|
||||
// Test 200.
|
||||
rtests = append(rtests, requestTest{
|
||||
fmt.Sprintf("Role %s 200", rn),
|
||||
http.MethodGet,
|
||||
fmt.Sprintf("/v1/accounts/%s", acc.ID),
|
||||
nil,
|
||||
req := mockUserCreateRequest()
|
||||
rt := requestTest{
|
||||
fmt.Sprintf("Create %d w/role %s", expectedStatus, tr.Role),
|
||||
http.MethodPost,
|
||||
"/v1/accounts",
|
||||
req,
|
||||
tr.Token,
|
||||
tr.Claims,
|
||||
http.StatusOK,
|
||||
expectedStatus,
|
||||
nil,
|
||||
func(treq requestTest, body []byte) bool {
|
||||
var actual account.AccountResponse
|
||||
if err := json.Unmarshal(body, &actual); err != nil {
|
||||
t.Logf("\t\tGot error : %+v", err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||
|
||||
// Add claims to the context so they can be retrieved later.
|
||||
ctx := context.WithValue(tests.Context(), auth.Key, tr.Claims)
|
||||
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)
|
||||
|
||||
expectedMap := map[string]interface{}{
|
||||
"updated_at": web.NewTimeResponse(ctx, acc.UpdatedAt),
|
||||
"id": acc.ID,
|
||||
"address2": acc.Address2,
|
||||
"region": acc.Region,
|
||||
"zipcode": acc.Zipcode,
|
||||
"timezone": acc.Timezone,
|
||||
"created_at": web.NewTimeResponse(ctx, acc.CreatedAt),
|
||||
"country": acc.Country,
|
||||
"billing_user_id": &acc.BillingUserID,
|
||||
"name": acc.Name,
|
||||
"address1": acc.Address1,
|
||||
"city": acc.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": &acc.SignupUserID,
|
||||
}
|
||||
expectedJson, err := json.Marshal(expectedMap)
|
||||
if err != nil {
|
||||
t.Logf("\t\tGot error : %+v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
var expected account.AccountResponse
|
||||
if err := json.Unmarshal([]byte(expectedJson), &expected); err != nil {
|
||||
t.Logf("\t\tGot error : %+v", err)
|
||||
printResultMap(ctx, body)
|
||||
return false
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(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 {
|
||||
printResultMap(ctx, body)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
})
|
||||
|
||||
// Test 404.
|
||||
invalidID := uuid.NewRandom().String()
|
||||
rtests = append(rtests, requestTest{
|
||||
fmt.Sprintf("Role %s 404 w/invalid ID", rn),
|
||||
http.MethodGet,
|
||||
fmt.Sprintf("/v1/accounts/%s", invalidID),
|
||||
nil,
|
||||
tr.Token,
|
||||
tr.Claims,
|
||||
http.StatusNotFound,
|
||||
web.ErrorResponse{
|
||||
Error: fmt.Sprintf("account %s not found: Entity not found", invalidID),
|
||||
},
|
||||
func(treq requestTest, body []byte) bool {
|
||||
return true
|
||||
},
|
||||
})
|
||||
|
||||
// Test 404 - Account exists but not allowed.
|
||||
rtests = append(rtests, requestTest{
|
||||
fmt.Sprintf("Role %s 404 w/random account ID", rn),
|
||||
http.MethodGet,
|
||||
fmt.Sprintf("/v1/accounts/%s", forbiddenAccount.ID),
|
||||
nil,
|
||||
tr.Token,
|
||||
tr.Claims,
|
||||
http.StatusNotFound,
|
||||
web.ErrorResponse{
|
||||
Error: fmt.Sprintf("account %s not found: Entity not found", forbiddenAccount.ID),
|
||||
},
|
||||
func(treq requestTest, body []byte) bool {
|
||||
return true
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
runRequestTests(t, rtests)
|
||||
}
|
||||
|
||||
// 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(),
|
||||
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)
|
||||
}
|
||||
|
||||
newName := rn + uuid.NewRandom().String() + strconv.Itoa(len(rtests))
|
||||
rtests = append(rtests, requestTest{
|
||||
fmt.Sprintf("Role %s %d", rn, expectedStatus),
|
||||
// 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,
|
||||
}
|
||||
|
||||
var expected account.AccountResponse
|
||||
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 {
|
||||
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/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.StatusNoContent
|
||||
|
||||
newName := uuid.NewRandom().String()
|
||||
rt := requestTest{
|
||||
fmt.Sprintf("Update %d w/role %s", expectedStatus, tr.Role),
|
||||
http.MethodPatch,
|
||||
"/v1/accounts",
|
||||
account.AccountUpdateRequest{
|
||||
ID: tr.SignupResult.Account.ID,
|
||||
ID: tr.Account.ID,
|
||||
Name: &newName,
|
||||
},
|
||||
tr.Token,
|
||||
tr.Claims,
|
||||
expectedStatus,
|
||||
expectedErr,
|
||||
func(treq requestTest, body []byte) bool {
|
||||
return true
|
||||
},
|
||||
})
|
||||
}
|
||||
nil,
|
||||
}
|
||||
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||
|
||||
// Test update an account with invalid data.
|
||||
// Admin role: 400
|
||||
// User role 400
|
||||
for rn, tr := range roleTests {
|
||||
var expectedStatus int
|
||||
var expectedErr interface{}
|
||||
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 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(),
|
||||
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,
|
||||
}
|
||||
|
||||
var expected account.AccountResponse
|
||||
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 {
|
||||
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/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,
|
||||
"/v1/accounts",
|
||||
account.AccountUpdateRequest{
|
||||
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")
|
||||
rtests = append(rtests, requestTest{
|
||||
fmt.Sprintf("Role %s %d w/invalid data", rn, expectedStatus),
|
||||
rt := requestTest{
|
||||
fmt.Sprintf("Update %d w/role %s using invalid data", expectedStatus, tr.Role),
|
||||
http.MethodPatch,
|
||||
"/v1/accounts",
|
||||
account.AccountUpdateRequest{
|
||||
ID: tr.SignupResult.User.ID,
|
||||
Status: &invalidStatus,
|
||||
ID: tr.Account.ID,
|
||||
Status: &invalidStatus,
|
||||
},
|
||||
tr.Token,
|
||||
tr.Claims,
|
||||
expectedStatus,
|
||||
expectedErr,
|
||||
func(treq requestTest, body []byte) bool {
|
||||
return true
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Test update an account for with an invalid ID.
|
||||
// Admin role: 403
|
||||
// User role 403
|
||||
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 {
|
||||
expectedStatus = http.StatusForbidden
|
||||
expectedErr = web.ErrorResponse{
|
||||
Error: mid.ErrForbidden.Error(),
|
||||
}
|
||||
nil,
|
||||
}
|
||||
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
|
||||
},
|
||||
})
|
||||
}
|
||||
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||
|
||||
// Test update an account for with random account ID.
|
||||
// Admin role: 403
|
||||
// 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 {
|
||||
expectedStatus = http.StatusForbidden
|
||||
expectedErr = web.ErrorResponse{
|
||||
Error: mid.ErrForbidden.Error(),
|
||||
}
|
||||
w, ok := executeRequestTest(t, rt, ctx)
|
||||
if !ok {
|
||||
t.Fatalf("\t%s\tExecute request failed.", tests.Failed)
|
||||
}
|
||||
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
|
||||
},
|
||||
})
|
||||
}
|
||||
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||
|
||||
runRequestTests(t, rtests)
|
||||
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: 'AccountUpdateRequest.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)
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,19 +1,30 @@
|
||||
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/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/signup"
|
||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/user"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"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 {
|
||||
return signup.SignupRequest{
|
||||
Account: signup.SignupAccount{
|
||||
@ -34,152 +45,199 @@ 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) {
|
||||
defer tests.Recover(t)
|
||||
|
||||
t.Run("postSigup", postSigup)
|
||||
}
|
||||
ctx := tests.Context()
|
||||
|
||||
// postSigup validates the signup endpoint.
|
||||
func postSigup(t *testing.T) {
|
||||
// Test signup.
|
||||
{
|
||||
expectedStatus := http.StatusCreated
|
||||
|
||||
var rtests []requestTest
|
||||
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)
|
||||
|
||||
// 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
|
||||
}
|
||||
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)
|
||||
|
||||
ctx := tests.Context()
|
||||
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)
|
||||
}
|
||||
|
||||
req := treq.request.(signup.SignupRequest )
|
||||
|
||||
expectedMap := map[string]interface{}{
|
||||
"user": map[string]interface{}{
|
||||
"id": actual.User.ID,
|
||||
"name": req.User.Name,
|
||||
"email": req.User.Email,
|
||||
"timezone": actual.User.Timezone,
|
||||
"created_at": web.NewTimeResponse(ctx, actual.User.CreatedAt.Value),
|
||||
"updated_at": web.NewTimeResponse(ctx, actual.User.UpdatedAt.Value),
|
||||
},
|
||||
"account": map[string]interface{}{
|
||||
"updated_at": web.NewTimeResponse(ctx, actual.Account.UpdatedAt.Value),
|
||||
"id": actual.Account.ID,
|
||||
"address2": req.Account.Address2,
|
||||
"region": req.Account.Region,
|
||||
"zipcode": req.Account.Zipcode,
|
||||
"timezone": actual.Account.Timezone,
|
||||
"created_at": web.NewTimeResponse(ctx, actual.Account.CreatedAt.Value),
|
||||
"country": req.Account.Country,
|
||||
"billing_user_id": &actual.Account.BillingUserID,
|
||||
"name": req.Account.Name,
|
||||
"address1": req.Account.Address1,
|
||||
"city": req.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": &actual.Account.SignupUserID,
|
||||
expectedMap := map[string]interface{}{
|
||||
"user": map[string]interface{}{
|
||||
"id": actual.User.ID,
|
||||
"name": req.User.Name,
|
||||
"email": req.User.Email,
|
||||
"timezone": actual.User.Timezone,
|
||||
"created_at": web.NewTimeResponse(ctx, actual.User.CreatedAt.Value),
|
||||
"updated_at": web.NewTimeResponse(ctx, actual.User.UpdatedAt.Value),
|
||||
},
|
||||
"account": map[string]interface{}{
|
||||
"updated_at": web.NewTimeResponse(ctx, actual.Account.UpdatedAt.Value),
|
||||
"id": actual.Account.ID,
|
||||
"address2": req.Account.Address2,
|
||||
"region": req.Account.Region,
|
||||
"zipcode": req.Account.Zipcode,
|
||||
"timezone": actual.Account.Timezone,
|
||||
"created_at": web.NewTimeResponse(ctx, actual.Account.CreatedAt.Value),
|
||||
"country": req.Account.Country,
|
||||
"billing_user_id": &actual.Account.BillingUserID,
|
||||
"name": req.Account.Name,
|
||||
"address1": req.Account.Address1,
|
||||
"city": req.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": &actual.Account.SignupUserID,
|
||||
},
|
||||
}
|
||||
|
||||
var expected signup.SignupResponse
|
||||
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
|
||||
}
|
||||
expectedJson, err := json.Marshal(expectedMap)
|
||||
if err != nil {
|
||||
t.Logf("\t\tGot error : %+v", err)
|
||||
return false
|
||||
}
|
||||
t.Fatalf("\t%s\tReceived expected result.", tests.Failed)
|
||||
}
|
||||
t.Logf("\t%s\tReceived expected result.", tests.Success)
|
||||
}
|
||||
|
||||
var expected signup.SignupResponse
|
||||
if err := json.Unmarshal([]byte(expectedJson), &expected); err != nil {
|
||||
t.Logf("\t\tGot error : %+v", err)
|
||||
printResultMap(ctx, body)
|
||||
return false
|
||||
}
|
||||
// Test signup w/empty request.
|
||||
{
|
||||
expectedStatus := http.StatusBadRequest
|
||||
|
||||
if diff := cmp.Diff(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)
|
||||
rt := requestTest{
|
||||
fmt.Sprintf("Signup %d w/empty request", expectedStatus),
|
||||
http.MethodPost,
|
||||
"/v1/signup",
|
||||
nil,
|
||||
user.Token{},
|
||||
auth.Claims{},
|
||||
expectedStatus,
|
||||
nil,
|
||||
}
|
||||
t.Logf("\tTest: %s - %s %s", rt.name, rt.method, rt.url)
|
||||
|
||||
expectedJSON, err := json.MarshalIndent(expected, "", " ")
|
||||
if err != nil {
|
||||
t.Logf("\t\tGot error : %+v", err)
|
||||
return false
|
||||
}
|
||||
t.Logf("\t\tExpected : %s\n", expectedJSON)
|
||||
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)
|
||||
|
||||
t.Logf("\t\tDiff : %s\n", diff)
|
||||
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)
|
||||
}
|
||||
|
||||
if len(expectedMap) == 0 {
|
||||
printResultMap(ctx, body)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
})
|
||||
|
||||
// Test 404 w/empty request.
|
||||
rtests = append(rtests, requestTest{
|
||||
"Empty request",
|
||||
http.MethodPost,
|
||||
"/v1/signup",
|
||||
nil,
|
||||
user.Token{},
|
||||
auth.Claims{},
|
||||
http.StatusBadRequest,
|
||||
web.ErrorResponse{
|
||||
expected := web.ErrorResponse{
|
||||
Error: "decode request body failed: EOF",
|
||||
},
|
||||
func(req requestTest, body []byte) bool {
|
||||
return true
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Test 404 w/validation errors.
|
||||
invalidReq := mockSignupRequest()
|
||||
invalidReq.User.Email = ""
|
||||
invalidReq.Account.Name = ""
|
||||
rtests = append(rtests, requestTest{
|
||||
"Invalid request",
|
||||
http.MethodPost,
|
||||
"/v1/signup",
|
||||
invalidReq,
|
||||
user.Token{},
|
||||
auth.Claims{},
|
||||
http.StatusBadRequest,
|
||||
web.ErrorResponse{
|
||||
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,
|
||||
"/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 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: "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"},
|
||||
},
|
||||
},
|
||||
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"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/web"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
@ -15,40 +14,44 @@ import (
|
||||
"testing"
|
||||
"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/internal/account"
|
||||
"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/signup"
|
||||
"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 test *tests.Test
|
||||
var authenticator *auth.Authenticator
|
||||
|
||||
// Information about the users we have created for testing.
|
||||
type roleTest struct {
|
||||
Token user.Token
|
||||
Claims auth.Claims
|
||||
SignupRequest *signup.SignupRequest
|
||||
SignupResult *signup.SignupResult
|
||||
User *user.User
|
||||
Account *account.Account
|
||||
Role string
|
||||
Token user.Token
|
||||
Claims auth.Claims
|
||||
User mockUser
|
||||
Account *account.Account
|
||||
ForbiddenUser mockUser
|
||||
ForbiddenAccount *account.Account
|
||||
}
|
||||
|
||||
type requestTest struct {
|
||||
name string
|
||||
method string
|
||||
url string
|
||||
request interface{}
|
||||
token user.Token
|
||||
claims auth.Claims
|
||||
statusCode int
|
||||
error interface{}
|
||||
expected func(req requestTest, result []byte) bool
|
||||
name string
|
||||
method string
|
||||
url string
|
||||
request interface{}
|
||||
token user.Token
|
||||
claims auth.Claims
|
||||
statusCode int
|
||||
error interface{}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
authenticator, err := auth.NewAuthenticatorMemory(now)
|
||||
var err error
|
||||
authenticator, err = auth.NewAuthenticatorMemory(now)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
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
|
||||
// initial account and user that we will use for admin validated endpoints.
|
||||
signupReq := signup.SignupRequest{
|
||||
Account: signup.SignupAccount{
|
||||
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)
|
||||
signupReq1 := mockSignupRequest()
|
||||
signup1, err := signup.Signup(tests.Context(), auth.Claims{}, test.MasterDB, signupReq1, now)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
expires := time.Now().UTC().Sub(signup.User.CreatedAt) + time.Hour
|
||||
adminTkn, err := user.Authenticate(tests.Context(), test.MasterDB, authenticator, signupReq.User.Email, signupReq.User.Password, expires, now)
|
||||
expires := time.Now().UTC().Sub(signup1.User.CreatedAt) + time.Hour
|
||||
adminTkn, err := user.Authenticate(tests.Context(), test.MasterDB, authenticator, signupReq1.User.Email, signupReq1.User.Password, expires, now)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -111,13 +102,22 @@ func testMain(m *testing.M) int {
|
||||
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{
|
||||
Token: adminTkn,
|
||||
Claims: adminClaims,
|
||||
SignupRequest: &signupReq,
|
||||
SignupResult: signup,
|
||||
User: signup.User,
|
||||
Account: signup.Account,
|
||||
Role: auth.RoleAdmin,
|
||||
Token: adminTkn,
|
||||
Claims: adminClaims,
|
||||
User: mockUser{signup1.User, signupReq1.User.Password},
|
||||
Account: signup1.Account,
|
||||
ForbiddenUser: mockUser{signup2.User, signupReq2.User.Password},
|
||||
ForbiddenAccount: signup2.Account,
|
||||
}
|
||||
|
||||
// Create a regular user to use when calling regular validated endpoints.
|
||||
@ -133,9 +133,9 @@ func testMain(m *testing.M) int {
|
||||
}
|
||||
|
||||
_, err = user_account.Create(tests.Context(), adminClaims, test.MasterDB, user_account.UserAccountCreateRequest{
|
||||
UserID: usr.ID,
|
||||
AccountID: signup.Account.ID,
|
||||
Roles: []user_account.UserAccountRole{user_account.UserAccountRole_User},
|
||||
UserID: usr.ID,
|
||||
AccountID: signup1.Account.ID,
|
||||
Roles: []user_account.UserAccountRole{user_account.UserAccountRole_User},
|
||||
// Status: use default value
|
||||
}, now)
|
||||
if err != nil {
|
||||
@ -152,83 +152,114 @@ func testMain(m *testing.M) int {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Second test will be for role User
|
||||
roleTests[auth.RoleUser] = roleTest{
|
||||
Token: userTkn,
|
||||
Claims: userClaims,
|
||||
SignupRequest: &signupReq,
|
||||
SignupResult: signup,
|
||||
Account: signup.Account,
|
||||
User: usr,
|
||||
Role: auth.RoleUser,
|
||||
Token: userTkn,
|
||||
Claims: userClaims,
|
||||
Account: signup1.Account,
|
||||
User: mockUser{usr, userReq.Password},
|
||||
ForbiddenUser: mockUser{signup2.User, signupReq2.User.Password},
|
||||
ForbiddenAccount: signup2.Account,
|
||||
}
|
||||
|
||||
return m.Run()
|
||||
}
|
||||
|
||||
|
||||
// runRequestTests helper function for testing endpoints.
|
||||
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 rr io.Reader
|
||||
if tt.request != nil {
|
||||
var ok bool
|
||||
req, ok = tt.request.([]byte)
|
||||
if !ok {
|
||||
var err error
|
||||
req, err = json.Marshal(tt.request)
|
||||
if err != nil {
|
||||
t.Logf("\t\tGot err : %+v", err)
|
||||
t.Fatalf("\t%s\tEncode request failed.", tests.Failed)
|
||||
}
|
||||
}
|
||||
rr = bytes.NewReader(req)
|
||||
// executeRequestTest provides request execution and basic response validation
|
||||
func executeRequestTest(t *testing.T, tt requestTest, ctx context.Context) (*httptest.ResponseRecorder, bool) {
|
||||
var req []byte
|
||||
var rr io.Reader
|
||||
if tt.request != nil {
|
||||
var ok bool
|
||||
req, ok = tt.request.([]byte)
|
||||
if !ok {
|
||||
var err error
|
||||
req, err = json.Marshal(tt.request)
|
||||
if err != nil {
|
||||
t.Logf("\t\tGot err : %+v", err)
|
||||
t.Logf("\t\tEncode request failed.")
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
rr = bytes.NewReader(req)
|
||||
}
|
||||
|
||||
r := httptest.NewRequest(tt.method, tt.url , rr)
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest(tt.method, tt.url, rr).WithContext(ctx)
|
||||
|
||||
r.Header.Set("Content-Type", web.MIMEApplicationJSONCharsetUTF8)
|
||||
if tt.token.AccessToken != "" {
|
||||
r.Header.Set("Authorization", tt.token.AuthorizationHeader())
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
a.ServeHTTP(w, r)
|
||||
r.Header.Set("Content-Type", web.MIMEApplicationJSONCharsetUTF8)
|
||||
if tt.token.AccessToken != "" {
|
||||
r.Header.Set("Authorization", tt.token.AuthorizationHeader())
|
||||
}
|
||||
|
||||
if w.Code != tt.statusCode {
|
||||
t.Logf("\t\tRequest : %s\n", string(req))
|
||||
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%s\tReceived valid status code of %d.", tests.Success, w.Code)
|
||||
a.ServeHTTP(w, r)
|
||||
|
||||
if tt.error != nil {
|
||||
if w.Code != tt.statusCode {
|
||||
t.Logf("\t\tRequest : %s\n", string(req))
|
||||
t.Logf("\t\tBody : %s\n", w.Body.String())
|
||||
t.Logf("\t\tShould receive a status code of %d for the response : %v", tt.statusCode, w.Code)
|
||||
return w, false
|
||||
}
|
||||
|
||||
if tt.error != nil {
|
||||
var actual web.ErrorResponse
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||
t.Logf("\t\tBody : %s\n", w.Body.String())
|
||||
t.Logf("\t\tGot error : %+v", err)
|
||||
t.Logf("\t\tShould get the expected error.")
|
||||
return w, false
|
||||
}
|
||||
|
||||
|
||||
var actual web.ErrorResponse
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
|
||||
t.Logf("\t\tBody : %s\n", w.Body.String())
|
||||
t.Logf("\t\tGot error : %+v", err)
|
||||
t.Fatalf("\t%s\tShould get the expected error.", tests.Failed)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(actual, tt.error); diff != "" {
|
||||
t.Logf("\t\tDiff : %s\n", diff)
|
||||
t.Fatalf("\t%s\tShould get the expected error.", tests.Failed)
|
||||
}
|
||||
}
|
||||
|
||||
if ok := tt.expected(tt, w.Body.Bytes()); !ok {
|
||||
t.Fatalf("\t%s\tShould get the expected result.", tests.Failed)
|
||||
}
|
||||
t.Logf("\t%s\tReceived expected result.", tests.Success)
|
||||
if diff := cmp.Diff(actual, tt.error); diff != "" {
|
||||
t.Logf("\t\tDiff : %s\n", diff)
|
||||
t.Logf("\t\tShould get the expected error.")
|
||||
return w, false
|
||||
}
|
||||
}
|
||||
|
||||
return w, true
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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)
|
||||
|
||||
for _, smv := range sm {
|
||||
printResultMapKeys(ctx, smv, depth +1)
|
||||
printResultMapKeys(ctx, smv, depth+1)
|
||||
}
|
||||
|
||||
fmt.Printf("%s},\n", strings.Repeat("\t", depth))
|
||||
} else if sm, ok := kv.(map[string]interface{}); ok {
|
||||
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))
|
||||
} else {
|
||||
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
Reference in New Issue
Block a user