2019-06-26 20:21:00 -08:00
|
|
|
package tests
|
|
|
|
|
|
|
|
import (
|
2019-06-27 04:48:18 -08:00
|
|
|
"context"
|
2019-06-26 20:21:00 -08:00
|
|
|
"encoding/json"
|
2019-06-27 04:48:18 -08:00
|
|
|
"fmt"
|
2019-06-26 20:21:00 -08:00
|
|
|
"net/http"
|
|
|
|
"testing"
|
2019-06-27 04:48:18 -08:00
|
|
|
"time"
|
2019-06-26 20:21:00 -08:00
|
|
|
|
2019-07-13 12:16:28 -08:00
|
|
|
"geeks-accelerator/oss/saas-starter-kit/internal/account"
|
|
|
|
"geeks-accelerator/oss/saas-starter-kit/internal/platform/auth"
|
|
|
|
"geeks-accelerator/oss/saas-starter-kit/internal/platform/tests"
|
|
|
|
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web"
|
2019-08-01 16:17:47 -08:00
|
|
|
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
|
2019-07-13 12:16:28 -08:00
|
|
|
"geeks-accelerator/oss/saas-starter-kit/internal/signup"
|
2019-08-04 14:48:43 -08:00
|
|
|
"geeks-accelerator/oss/saas-starter-kit/internal/user_auth"
|
2019-06-26 20:21:00 -08:00
|
|
|
"github.com/pborman/uuid"
|
|
|
|
)
|
|
|
|
|
2019-06-27 04:48:18 -08:00
|
|
|
type mockSignup struct {
|
|
|
|
account *account.Account
|
|
|
|
user mockUser
|
2019-08-04 14:48:43 -08:00
|
|
|
token user_auth.Token
|
2019-06-27 04:48:18 -08:00
|
|
|
claims auth.Claims
|
|
|
|
context context.Context
|
|
|
|
}
|
|
|
|
|
2019-06-26 20:21:00 -08:00
|
|
|
func mockSignupRequest() signup.SignupRequest {
|
|
|
|
return 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{
|
2019-08-01 16:17:47 -08:00
|
|
|
FirstName: "Lee",
|
|
|
|
LastName: "Brown",
|
2019-06-26 20:21:00 -08:00
|
|
|
Email: uuid.NewRandom().String() + "@geeksinthewoods.com",
|
|
|
|
Password: "akTechFr0n!ier",
|
|
|
|
PasswordConfirm: "akTechFr0n!ier",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-27 04:48:18 -08:00
|
|
|
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)
|
|
|
|
}
|
2019-06-26 20:21:00 -08:00
|
|
|
|
2019-06-27 04:48:18 -08:00
|
|
|
expires := time.Now().UTC().Sub(s.User.CreatedAt) + time.Hour
|
2019-08-05 17:12:28 -08:00
|
|
|
tkn, err := user_auth.Authenticate(tests.Context(), test.MasterDB, authenticator, user_auth.AuthenticateRequest{
|
|
|
|
Email: req.User.Email,
|
|
|
|
Password: req.User.Password,
|
|
|
|
}, expires, now)
|
2019-06-27 04:48:18 -08:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2019-06-26 20:21:00 -08:00
|
|
|
|
2019-06-27 04:48:18 -08:00
|
|
|
claims, err := authenticator.ParseClaims(tkn.AccessToken)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2019-06-26 20:21:00 -08:00
|
|
|
|
2019-06-27 04:48:18 -08:00
|
|
|
// Add claims to the context for the user.
|
|
|
|
ctx := context.WithValue(tests.Context(), auth.Key, claims)
|
2019-06-26 20:21:00 -08:00
|
|
|
|
2019-06-27 04:48:18 -08:00
|
|
|
return mockSignup{
|
|
|
|
account: s.Account,
|
|
|
|
user: mockUser{s.User, req.User.Password},
|
|
|
|
claims: claims,
|
|
|
|
token: tkn,
|
|
|
|
context: ctx,
|
|
|
|
}
|
|
|
|
}
|
2019-06-26 20:21:00 -08:00
|
|
|
|
2019-06-27 04:48:18 -08:00
|
|
|
// TestSignup validates the signup endpoint.
|
|
|
|
func TestSignup(t *testing.T) {
|
|
|
|
defer tests.Recover(t)
|
2019-06-26 20:21:00 -08:00
|
|
|
|
2019-06-27 04:48:18 -08:00
|
|
|
ctx := tests.Context()
|
|
|
|
|
|
|
|
// Test signup.
|
|
|
|
{
|
|
|
|
expectedStatus := http.StatusCreated
|
|
|
|
|
|
|
|
req := mockSignupRequest()
|
|
|
|
rt := requestTest{
|
|
|
|
fmt.Sprintf("Signup %d w/no authorization", expectedStatus),
|
|
|
|
http.MethodPost,
|
|
|
|
"/v1/signup",
|
|
|
|
req,
|
2019-08-04 14:48:43 -08:00
|
|
|
user_auth.Token{},
|
2019-06-27 04:48:18 -08:00
|
|
|
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{}{
|
|
|
|
"user": map[string]interface{}{
|
|
|
|
"id": actual.User.ID,
|
2019-08-04 14:48:43 -08:00
|
|
|
"name": req.User.FirstName + " " + req.User.LastName,
|
2019-08-01 16:17:47 -08:00
|
|
|
"first_name": req.User.FirstName,
|
|
|
|
"last_name": req.User.LastName,
|
2019-06-27 04:48:18 -08:00
|
|
|
"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),
|
2019-08-04 14:48:43 -08:00
|
|
|
"gravatar": web.NewGravatarResponse(ctx, actual.User.Email),
|
2019-06-27 04:48:18 -08:00
|
|
|
},
|
|
|
|
"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{}{
|
2019-08-05 17:12:28 -08:00
|
|
|
"value": "active",
|
|
|
|
"title": "Active",
|
|
|
|
"options": []map[string]interface{}{
|
|
|
|
{"selected": true, "title": "Active", "value": "active"},
|
|
|
|
{"selected": false, "title": "Pending", "value": "pending"},
|
|
|
|
{"selected": false, "title": "Disabled", "value": "disabled"},
|
|
|
|
},
|
2019-06-27 04:48:18 -08:00
|
|
|
},
|
|
|
|
"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)
|
|
|
|
}
|
|
|
|
|
2019-08-01 16:17:47 -08:00
|
|
|
if diff := cmpDiff(t, expected, actual); diff {
|
2019-06-27 04:48:18 -08:00
|
|
|
if len(expectedMap) == 0 {
|
|
|
|
printResultMap(ctx, w.Body.Bytes()) // used to help format expectedMap
|
2019-06-26 20:21:00 -08:00
|
|
|
}
|
2019-06-27 04:48:18 -08:00
|
|
|
t.Fatalf("\t%s\tReceived expected result.", tests.Failed)
|
|
|
|
}
|
|
|
|
t.Logf("\t%s\tReceived expected result.", tests.Success)
|
|
|
|
}
|
2019-06-26 20:21:00 -08:00
|
|
|
|
2019-06-27 04:48:18 -08:00
|
|
|
// Test signup w/empty request.
|
|
|
|
{
|
|
|
|
expectedStatus := http.StatusBadRequest
|
|
|
|
|
|
|
|
rt := requestTest{
|
|
|
|
fmt.Sprintf("Signup %d w/empty request", expectedStatus),
|
|
|
|
http.MethodPost,
|
|
|
|
"/v1/signup",
|
|
|
|
nil,
|
2019-08-04 14:48:43 -08:00
|
|
|
user_auth.Token{},
|
2019-06-27 04:48:18 -08:00
|
|
|
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)
|
|
|
|
|
2019-08-01 16:17:47 -08:00
|
|
|
var actual weberror.ErrorResponse
|
2019-06-27 04:48:18 -08:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2019-08-01 16:17:47 -08:00
|
|
|
expected := weberror.ErrorResponse{
|
2019-08-04 14:48:43 -08:00
|
|
|
StatusCode: expectedStatus,
|
|
|
|
Error: "decode request body failed",
|
|
|
|
Details: "EOF",
|
|
|
|
StackTrace: actual.StackTrace,
|
2019-06-27 04:48:18 -08:00
|
|
|
}
|
2019-06-26 20:21:00 -08:00
|
|
|
|
2019-08-01 16:17:47 -08:00
|
|
|
if diff := cmpDiff(t, expected, actual); diff {
|
2019-06-27 04:48:18 -08:00
|
|
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
|
|
|
}
|
|
|
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
|
|
|
}
|
2019-06-26 20:21:00 -08:00
|
|
|
|
2019-06-27 04:48:18 -08:00
|
|
|
// 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,
|
2019-08-04 14:48:43 -08:00
|
|
|
user_auth.Token{},
|
2019-06-27 04:48:18 -08:00
|
|
|
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)
|
|
|
|
|
2019-08-01 16:17:47 -08:00
|
|
|
var actual weberror.ErrorResponse
|
2019-06-27 04:48:18 -08:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2019-08-01 16:17:47 -08:00
|
|
|
expected := weberror.ErrorResponse{
|
2019-08-04 14:48:43 -08:00
|
|
|
StatusCode: expectedStatus,
|
|
|
|
Details: actual.Details,
|
|
|
|
Error: "Field validation error",
|
2019-08-01 16:17:47 -08:00
|
|
|
Fields: []weberror.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"},
|
|
|
|
|
|
|
|
{
|
|
|
|
Field: "name",
|
|
|
|
Value: "",
|
|
|
|
Tag: "required",
|
|
|
|
Error: "Name is a required field",
|
|
|
|
Display: "Name is a required field",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Field: "email",
|
|
|
|
Value: "",
|
|
|
|
Tag: "required",
|
|
|
|
Error: "email is a required field",
|
|
|
|
Display: "email is a required field",
|
|
|
|
},
|
2019-06-26 20:21:00 -08:00
|
|
|
},
|
2019-08-04 14:48:43 -08:00
|
|
|
StackTrace: actual.StackTrace,
|
2019-06-27 04:48:18 -08:00
|
|
|
}
|
2019-06-26 20:21:00 -08:00
|
|
|
|
2019-08-01 16:17:47 -08:00
|
|
|
if diff := cmpDiff(t, expected, actual); diff {
|
2019-06-27 04:48:18 -08:00
|
|
|
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
|
|
|
|
}
|
|
|
|
t.Logf("\t%s\tReceived expected error.", tests.Success)
|
|
|
|
}
|
2019-06-26 20:21:00 -08:00
|
|
|
}
|