2019-05-29 03:35:08 -05:00
package user
import (
"github.com/lib/pq"
"math/rand"
"strings"
"testing"
"time"
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/auth"
2019-05-29 15:05:17 -05:00
"geeks-accelerator/oss/saas-starter-kit/example-project/internal/platform/tests"
2019-05-29 03:35:08 -05:00
"github.com/dgrijalva/jwt-go"
2019-05-29 15:05:17 -05:00
"github.com/google/go-cmp/cmp"
2019-05-29 03:35:08 -05:00
"github.com/huandu/go-sqlbuilder"
"github.com/pborman/uuid"
"github.com/pkg/errors"
)
// TestAccountFindRequestQuery validates accountFindRequestQuery
func TestAccountFindRequestQuery ( t * testing . T ) {
where := "account_id = ? or user_id = ?"
var (
limit uint = 12
offset uint = 34
)
req := UserAccountFindRequest {
Where : & where ,
Args : [ ] interface { } {
"xy7" ,
"qwert" ,
} ,
Order : [ ] string {
"id asc" ,
"created_at desc" ,
} ,
Limit : & limit ,
Offset : & offset ,
}
expected := "SELECT " + usersAccountsMapColumns + " FROM " + usersAccountsTableName + " WHERE (account_id = ? or user_id = ?) ORDER BY id asc, created_at desc LIMIT 12 OFFSET 34"
res , args := accountFindRequestQuery ( req )
if diff := cmp . Diff ( res . String ( ) , expected ) ; diff != "" {
t . Fatalf ( "\t%s\tExpected result query to match. Diff:\n%s" , tests . Failed , diff )
}
if diff := cmp . Diff ( args , req . Args ) ; diff != "" {
t . Fatalf ( "\t%s\tExpected result query to match. Diff:\n%s" , tests . Failed , diff )
}
}
// TestApplyClaimsUserAccountSelect validates applyClaimsUserAccountSelect
func TestApplyClaimsUserAccountSelect ( t * testing . T ) {
var claimTests = [ ] struct {
name string
claims auth . Claims
expectedSql string
error error
} {
{ "EmptyClaims" ,
auth . Claims { } ,
"SELECT " + usersAccountsMapColumns + " FROM " + usersAccountsTableName ,
nil ,
} ,
{ "RoleUser" ,
auth . Claims {
Roles : [ ] string { auth . RoleUser } ,
StandardClaims : jwt . StandardClaims {
Subject : "user1" ,
Audience : "acc1" ,
} ,
} ,
"SELECT " + usersAccountsMapColumns + " FROM " + usersAccountsTableName + " WHERE user_id IN (SELECT user_id FROM " + usersAccountsTableName + " WHERE (account_id = 'acc1' OR user_id = 'user1'))" ,
nil ,
} ,
{ "RoleAdmin" ,
auth . Claims {
Roles : [ ] string { auth . RoleAdmin } ,
StandardClaims : jwt . StandardClaims {
Subject : "user1" ,
Audience : "acc1" ,
} ,
} ,
"SELECT " + usersAccountsMapColumns + " FROM " + usersAccountsTableName + " WHERE user_id IN (SELECT user_id FROM " + usersAccountsTableName + " WHERE (account_id = 'acc1' OR user_id = 'user1'))" ,
nil ,
} ,
}
t . Log ( "Given the need to validate ACLs are enforced by claims to a select query." )
{
for i , tt := range claimTests {
t . Logf ( "\tTest: %d\tWhen running test: %s" , i , tt . name )
{
ctx := tests . Context ( )
query := accountSelectQuery ( )
err := applyClaimsUserAccountSelect ( ctx , tt . claims , query )
if err != tt . error {
t . Logf ( "\t\tGot : %+v" , err )
t . Logf ( "\t\tWant: %+v" , tt . error )
t . Fatalf ( "\t%s\tapplyClaimsUserAccountSelect failed." , tests . Failed )
}
sql , args := query . Build ( )
// Use mysql flavor so placeholders will get replaced for comparison.
sql , err = sqlbuilder . MySQL . Interpolate ( sql , args )
if err != nil {
t . Log ( "\t\tGot :" , err )
t . Fatalf ( "\t%s\tapplyClaimsUserAccountSelect failed." , tests . Failed )
}
if diff := cmp . Diff ( sql , tt . expectedSql ) ; diff != "" {
t . Fatalf ( "\t%s\tExpected result query to match. Diff:\n%s" , tests . Failed , diff )
}
t . Logf ( "\t%s\tapplyClaimsUserAccountSelect ok." , tests . Success )
}
}
}
}
// TestAddAccountValidation ensures all the validation tags work on account add.
func TestAddAccountValidation ( t * testing . T ) {
invalidRole := UserAccountRole ( "moon" )
invalidStatus := UserAccountStatus ( "moon" )
var accountTests = [ ] struct {
name string
req AddAccountRequest
expected func ( req AddAccountRequest , res * UserAccount ) * UserAccount
error error
} {
{ "Required Fields" ,
AddAccountRequest { } ,
func ( req AddAccountRequest , res * UserAccount ) * UserAccount {
return nil
} ,
2019-05-29 15:05:17 -05:00
errors . New ( "Key: 'AddAccountRequest.UserID' Error:Field validation for 'UserID' failed on the 'required' tag\n" +
"Key: 'AddAccountRequest.AccountID' Error:Field validation for 'AccountID' failed on the 'required' tag\n" +
"Key: 'AddAccountRequest.Roles' Error:Field validation for 'Roles' failed on the 'required' tag" ) ,
2019-05-29 03:35:08 -05:00
} ,
{ "Valid Role" ,
AddAccountRequest {
2019-05-29 15:05:17 -05:00
UserID : uuid . NewRandom ( ) . String ( ) ,
2019-05-29 03:35:08 -05:00
AccountID : uuid . NewRandom ( ) . String ( ) ,
2019-05-29 15:05:17 -05:00
Roles : [ ] UserAccountRole { invalidRole } ,
2019-05-29 03:35:08 -05:00
} ,
func ( req AddAccountRequest , res * UserAccount ) * UserAccount {
return nil
} ,
errors . New ( "Key: 'AddAccountRequest.Roles[0]' Error:Field validation for 'Roles[0]' failed on the 'oneof' tag" ) ,
} ,
{ "Valid Status" ,
AddAccountRequest {
2019-05-29 15:05:17 -05:00
UserID : uuid . NewRandom ( ) . String ( ) ,
2019-05-29 03:35:08 -05:00
AccountID : uuid . NewRandom ( ) . String ( ) ,
2019-05-29 15:05:17 -05:00
Roles : [ ] UserAccountRole { UserAccountRole_User } ,
Status : & invalidStatus ,
2019-05-29 03:35:08 -05:00
} ,
func ( req AddAccountRequest , res * UserAccount ) * UserAccount {
return nil
} ,
errors . New ( "Key: 'AddAccountRequest.Status' Error:Field validation for 'Status' failed on the 'oneof' tag" ) ,
} ,
{ "Default Status" ,
AddAccountRequest {
2019-05-29 15:05:17 -05:00
UserID : uuid . NewRandom ( ) . String ( ) ,
2019-05-29 03:35:08 -05:00
AccountID : uuid . NewRandom ( ) . String ( ) ,
2019-05-29 15:05:17 -05:00
Roles : [ ] UserAccountRole { UserAccountRole_User } ,
2019-05-29 03:35:08 -05:00
} ,
func ( req AddAccountRequest , res * UserAccount ) * UserAccount {
return & UserAccount {
2019-05-29 15:05:17 -05:00
UserID : req . UserID ,
AccountID : req . AccountID ,
Roles : req . Roles ,
Status : UserAccountStatus_Active ,
2019-05-29 03:35:08 -05:00
// Copy this fields from the result.
2019-05-29 15:05:17 -05:00
ID : res . ID ,
CreatedAt : res . CreatedAt ,
UpdatedAt : res . UpdatedAt ,
2019-05-29 03:35:08 -05:00
//ArchivedAt: nil,
}
} ,
nil ,
} ,
}
now := time . Date ( 2018 , time . October , 1 , 0 , 0 , 0 , 0 , time . UTC )
t . Log ( "Given the need ensure all validation tags are working for add account." )
{
for i , tt := range accountTests {
t . Logf ( "\tTest: %d\tWhen running test: %s" , i , tt . name )
{
ctx := tests . Context ( )
res , err := AddAccount ( ctx , auth . Claims { } , test . MasterDB , tt . req , now )
if err != tt . error {
// TODO: need a better way to handle validation errors as they are
// of type interface validator.ValidationErrorsTranslations
var errStr string
if err != nil {
errStr = err . Error ( )
}
var expectStr string
if tt . error != nil {
expectStr = tt . error . Error ( )
}
if errStr != expectStr {
t . Logf ( "\t\tGot : %+v" , err )
t . Logf ( "\t\tWant: %+v" , tt . error )
t . Fatalf ( "\t%s\tAddAccount failed." , tests . Failed )
}
}
// If there was an error that was expected, then don't go any further
if tt . error != nil {
t . Logf ( "\t%s\tAddAccount ok." , tests . Success )
continue
}
expected := tt . expected ( tt . req , res )
if diff := cmp . Diff ( res , expected ) ; diff != "" {
t . Fatalf ( "\t%s\tAddAccount result should match. Diff:\n%s" , tests . Failed , diff )
}
t . Logf ( "\t%s\tAddAccount ok." , tests . Success )
}
}
}
}
// TestAddAccountExistingEntry validates emails must be unique on add account.
func TestAddAccountExistingEntry ( t * testing . T ) {
now := time . Date ( 2018 , time . October , 1 , 0 , 0 , 0 , 0 , time . UTC )
t . Log ( "Given the need ensure duplicate entries for the same user ID + account ID are updated and does not throw a duplicate key error." )
{
ctx := tests . Context ( )
req1 := AddAccountRequest {
2019-05-29 15:05:17 -05:00
UserID : uuid . NewRandom ( ) . String ( ) ,
2019-05-29 03:35:08 -05:00
AccountID : uuid . NewRandom ( ) . String ( ) ,
2019-05-29 15:05:17 -05:00
Roles : [ ] UserAccountRole { UserAccountRole_User } ,
2019-05-29 03:35:08 -05:00
}
ua1 , err := AddAccount ( ctx , auth . Claims { } , test . MasterDB , req1 , now )
if err != nil {
t . Log ( "\t\tGot :" , err )
t . Fatalf ( "\t%s\tAddAccount failed." , tests . Failed )
}
if diff := cmp . Diff ( ua1 . Roles , req1 . Roles ) ; diff != "" {
t . Fatalf ( "\t%s\tAddAccount roles should match request. Diff:\n%s" , tests . Failed , diff )
}
req2 := AddAccountRequest {
2019-05-29 15:05:17 -05:00
UserID : req1 . UserID ,
2019-05-29 03:35:08 -05:00
AccountID : req1 . AccountID ,
2019-05-29 15:05:17 -05:00
Roles : [ ] UserAccountRole { UserAccountRole_Admin } ,
2019-05-29 03:35:08 -05:00
}
ua2 , err := AddAccount ( ctx , auth . Claims { } , test . MasterDB , req2 , now )
if err != nil {
t . Log ( "\t\tGot :" , err )
t . Fatalf ( "\t%s\tAddAccount failed." , tests . Failed )
}
if diff := cmp . Diff ( ua2 . Roles , req2 . Roles ) ; diff != "" {
t . Fatalf ( "\t%s\tAddAccount roles should match request. Diff:\n%s" , tests . Failed , diff )
}
t . Logf ( "\t%s\tAddAccount ok." , tests . Success )
}
}
// TestUpdateAccountValidation ensures all the validation tags work on account update.
func TestUpdateAccountValidation ( t * testing . T ) {
invalidRole := UserAccountRole ( "moon" )
invalidStatus := UserAccountStatus ( "xxxxxxxxx" )
var accountTests = [ ] struct {
2019-05-29 15:05:17 -05:00
name string
req UpdateAccountRequest
error error
2019-05-29 03:35:08 -05:00
} {
{ "Required Fields" ,
UpdateAccountRequest { } ,
errors . New ( "Key: 'UpdateAccountRequest.UserID' Error:Field validation for 'UserID' failed on the 'required' tag\n" +
2019-05-29 15:05:17 -05:00
"Key: 'UpdateAccountRequest.AccountID' Error:Field validation for 'AccountID' failed on the 'required' tag\n" +
"Key: 'UpdateAccountRequest.Roles' Error:Field validation for 'Roles' failed on the 'required' tag" ) ,
2019-05-29 03:35:08 -05:00
} ,
{ "Valid Role" ,
UpdateAccountRequest {
2019-05-29 15:05:17 -05:00
UserID : uuid . NewRandom ( ) . String ( ) ,
2019-05-29 03:35:08 -05:00
AccountID : uuid . NewRandom ( ) . String ( ) ,
2019-05-29 15:05:17 -05:00
Roles : & UserAccountRoles { invalidRole } ,
2019-05-29 03:35:08 -05:00
} ,
errors . New ( "Key: 'UpdateAccountRequest.Roles[0]' Error:Field validation for 'Roles[0]' failed on the 'oneof' tag" ) ,
} ,
{ "Valid Status" ,
UpdateAccountRequest {
2019-05-29 15:05:17 -05:00
UserID : uuid . NewRandom ( ) . String ( ) ,
2019-05-29 03:35:08 -05:00
AccountID : uuid . NewRandom ( ) . String ( ) ,
2019-05-29 15:05:17 -05:00
Roles : & UserAccountRoles { UserAccountRole_User } ,
Status : & invalidStatus ,
2019-05-29 03:35:08 -05:00
} ,
2019-05-29 15:05:17 -05:00
errors . New ( "Key: 'UpdateAccountRequest.Status' Error:Field validation for 'Status' failed on the 'oneof' tag" ) ,
2019-05-29 03:35:08 -05:00
} ,
}
now := time . Date ( 2018 , time . October , 1 , 0 , 0 , 0 , 0 , time . UTC )
t . Log ( "Given the need ensure all validation tags are working for update account." )
{
for i , tt := range accountTests {
t . Logf ( "\tTest: %d\tWhen running test: %s" , i , tt . name )
{
ctx := tests . Context ( )
err := UpdateAccount ( ctx , auth . Claims { } , test . MasterDB , tt . req , now )
if err != tt . error {
// TODO: need a better way to handle validation errors as they are
// of type interface validator.ValidationErrorsTranslations
var errStr string
if err != nil {
errStr = err . Error ( )
}
var expectStr string
if tt . error != nil {
expectStr = tt . error . Error ( )
}
if errStr != expectStr {
t . Logf ( "\t\tGot : %+v" , err )
t . Logf ( "\t\tWant: %+v" , tt . error )
t . Fatalf ( "\t%s\tUpdateAccount failed." , tests . Failed )
}
}
// If there was an error that was expected, then don't go any further
if tt . error != nil {
t . Logf ( "\t%s\tUpdateAccount ok." , tests . Success )
continue
}
t . Logf ( "\t%s\tUpdateAccount ok." , tests . Success )
}
}
}
}
// TestAccountCrud validates the full set of CRUD operations for user accounts and
// ensures ACLs are correctly applied by claims.
func TestAccountCrud ( t * testing . T ) {
defer tests . Recover ( t )
type accountTest struct {
name string
claims func ( string , string ) auth . Claims
updateErr error
findErr error
}
var accountTests [ ] accountTest
// Internal request, should bypass ACL.
accountTests = append ( accountTests , accountTest { "EmptyClaims" ,
func ( userID , accountId string ) auth . Claims {
return auth . Claims { }
} ,
nil ,
nil ,
} )
// Role of user but claim user does not match update user so forbidden.
accountTests = append ( accountTests , accountTest { "RoleUserDiffUser" ,
func ( userID , accountId string ) auth . Claims {
return auth . Claims {
Roles : [ ] string { auth . RoleUser } ,
StandardClaims : jwt . StandardClaims {
Subject : uuid . NewRandom ( ) . String ( ) ,
Audience : accountId ,
} ,
}
} ,
ErrForbidden ,
ErrNotFound ,
} )
// Role of user AND claim user matches update user so OK.
accountTests = append ( accountTests , accountTest { "RoleUserSameUser" ,
func ( userID , accountId string ) auth . Claims {
return auth . Claims {
Roles : [ ] string { auth . RoleUser } ,
StandardClaims : jwt . StandardClaims {
Subject : userID ,
Audience : accountId ,
} ,
}
} ,
nil ,
nil ,
} )
// Role of admin but claim account does not match update user so forbidden.
accountTests = append ( accountTests , accountTest { "RoleAdminDiffUser" ,
func ( userID , accountId string ) auth . Claims {
return auth . Claims {
Roles : [ ] string { auth . RoleAdmin } ,
StandardClaims : jwt . StandardClaims {
Subject : uuid . NewRandom ( ) . String ( ) ,
Audience : uuid . NewRandom ( ) . String ( ) ,
} ,
}
} ,
ErrForbidden ,
ErrNotFound ,
} )
// Role of admin and claim account matches update user so ok.
accountTests = append ( accountTests , accountTest { "RoleAdminSameAccount" ,
func ( userID , accountId string ) auth . Claims {
return auth . Claims {
Roles : [ ] string { auth . RoleAdmin } ,
StandardClaims : jwt . StandardClaims {
Subject : uuid . NewRandom ( ) . String ( ) ,
Audience : accountId ,
} ,
}
} ,
nil ,
nil ,
} )
t . Log ( "Given the need to validate CRUD functionality for user accounts and ensure claims are applied as ACL." )
{
now := time . Date ( 2018 , time . October , 1 , 0 , 0 , 0 , 0 , time . UTC )
for i , tt := range accountTests {
t . Logf ( "\tTest: %d\tWhen running test: %s" , i , tt . name )
{
// Always create the new user with empty claims, testing claims for create user
// will be handled separately.
user , err := Create ( tests . Context ( ) , auth . Claims { } , test . MasterDB , CreateUserRequest {
Name : "Lee Brown" ,
Email : uuid . NewRandom ( ) . String ( ) + "@geeksinthewoods.com" ,
Password : "akTechFr0n!ier" ,
PasswordConfirm : "akTechFr0n!ier" ,
} , now )
if err != nil {
t . Log ( "\t\tGot :" , err )
t . Fatalf ( "\t%s\tCreate user failed." , tests . Failed )
}
// Create a new random account and associate that with the user.
accountID := uuid . NewRandom ( ) . String ( )
createReq := AddAccountRequest {
2019-05-29 15:05:17 -05:00
UserID : user . ID ,
2019-05-29 03:35:08 -05:00
AccountID : accountID ,
2019-05-29 15:05:17 -05:00
Roles : [ ] UserAccountRole { UserAccountRole_User } ,
2019-05-29 03:35:08 -05:00
}
ua , err := AddAccount ( tests . Context ( ) , tt . claims ( user . ID , accountID ) , test . MasterDB , createReq , now )
if err != nil && errors . Cause ( err ) != tt . updateErr {
t . Logf ( "\t\tGot : %+v" , err )
t . Logf ( "\t\tWant: %+v" , tt . updateErr )
t . Fatalf ( "\t%s\tUpdateAccount failed." , tests . Failed )
} else if tt . updateErr == nil {
if diff := cmp . Diff ( ua . Roles , createReq . Roles ) ; diff != "" {
t . Fatalf ( "\t%s\tExpected find result to match update. Diff:\n%s" , tests . Failed , diff )
}
t . Logf ( "\t%s\tAddAccount ok." , tests . Success )
}
// Update the account.
updateReq := UpdateAccountRequest {
2019-05-29 15:05:17 -05:00
UserID : user . ID ,
2019-05-29 03:35:08 -05:00
AccountID : accountID ,
2019-05-29 15:05:17 -05:00
Roles : & UserAccountRoles { UserAccountRole_Admin } ,
2019-05-29 03:35:08 -05:00
}
err = UpdateAccount ( tests . Context ( ) , tt . claims ( user . ID , accountID ) , test . MasterDB , updateReq , now )
if err != nil && errors . Cause ( err ) != tt . updateErr {
t . Logf ( "\t\tGot : %+v" , err )
t . Logf ( "\t\tWant: %+v" , tt . updateErr )
t . Fatalf ( "\t%s\tUpdateAccount failed." , tests . Failed )
}
t . Logf ( "\t%s\tUpdateAccount ok." , tests . Success )
// Find the account for the user to verify the updates where made. There should only
// be one account associated with the user for this test.
findRes , err := FindAccountsByUserID ( tests . Context ( ) , tt . claims ( user . ID , accountID ) , test . MasterDB , user . ID , false )
if err != nil && errors . Cause ( err ) != tt . findErr {
t . Logf ( "\t\tGot : %+v" , err )
t . Logf ( "\t\tWant: %+v" , tt . findErr )
t . Fatalf ( "\t%s\tVerify UpdateAccount failed." , tests . Failed )
} else if tt . findErr == nil {
expected := [ ] * UserAccount {
& UserAccount {
2019-05-29 15:05:17 -05:00
ID : ua . ID ,
UserID : ua . UserID ,
2019-05-29 03:35:08 -05:00
AccountID : ua . AccountID ,
2019-05-29 15:05:17 -05:00
Roles : * updateReq . Roles ,
Status : ua . Status ,
CreatedAt : ua . CreatedAt ,
2019-05-29 03:35:08 -05:00
UpdatedAt : now ,
} ,
}
if diff := cmp . Diff ( findRes , expected ) ; diff != "" {
t . Fatalf ( "\t%s\tExpected find result to match update. Diff:\n%s" , tests . Failed , diff )
}
t . Logf ( "\t%s\tVerify UpdateAccount ok." , tests . Success )
}
// Archive (soft-delete) the user account.
err = RemoveAccount ( tests . Context ( ) , tt . claims ( user . ID , accountID ) , test . MasterDB , RemoveAccountRequest {
2019-05-29 15:05:17 -05:00
UserID : user . ID ,
2019-05-29 03:35:08 -05:00
AccountID : accountID ,
} , now )
if err != nil && errors . Cause ( err ) != tt . updateErr {
t . Logf ( "\t\tGot : %+v" , err )
t . Logf ( "\t\tWant: %+v" , tt . updateErr )
t . Fatalf ( "\t%s\tRemoveAccount failed." , tests . Failed )
} else if tt . updateErr == nil {
// Trying to find the archived user with the includeArchived false should result in not found.
_ , err = FindAccountsByUserID ( tests . Context ( ) , tt . claims ( user . ID , accountID ) , test . MasterDB , user . ID , false )
if errors . Cause ( err ) != ErrNotFound {
t . Logf ( "\t\tGot : %+v" , err )
t . Logf ( "\t\tWant: %+v" , ErrNotFound )
t . Fatalf ( "\t%s\tVerify RemoveAccount failed when excluding archived." , tests . Failed )
}
// Trying to find the archived user with the includeArchived true should result no error.
findRes , err = FindAccountsByUserID ( tests . Context ( ) , tt . claims ( user . ID , accountID ) , test . MasterDB , user . ID , true )
if err != nil {
t . Logf ( "\t\tGot : %+v" , err )
t . Fatalf ( "\t%s\tVerify RemoveAccount failed when including archived." , tests . Failed )
}
expected := [ ] * UserAccount {
& UserAccount {
2019-05-29 15:05:17 -05:00
ID : ua . ID ,
UserID : ua . UserID ,
AccountID : ua . AccountID ,
Roles : * updateReq . Roles ,
Status : ua . Status ,
CreatedAt : ua . CreatedAt ,
UpdatedAt : now ,
ArchivedAt : pq . NullTime { Time : now , Valid : true } ,
2019-05-29 03:35:08 -05:00
} ,
}
if diff := cmp . Diff ( findRes , expected ) ; diff != "" {
t . Fatalf ( "\t%s\tExpected find result to be archived. Diff:\n%s" , tests . Failed , diff )
}
}
t . Logf ( "\t%s\tRemoveAccount ok." , tests . Success )
// Delete (hard-delete) the user account.
err = DeleteAccount ( tests . Context ( ) , tt . claims ( user . ID , accountID ) , test . MasterDB , DeleteAccountRequest {
2019-05-29 15:05:17 -05:00
UserID : user . ID ,
2019-05-29 03:35:08 -05:00
AccountID : accountID ,
} )
if err != nil && errors . Cause ( err ) != tt . updateErr {
t . Logf ( "\t\tGot : %+v" , err )
t . Logf ( "\t\tWant: %+v" , tt . updateErr )
t . Fatalf ( "\t%s\tDeleteAccount failed." , tests . Failed )
} else if tt . updateErr == nil {
// Trying to find the deleted user with the includeArchived true should result in not found.
_ , err = FindAccountsByUserID ( tests . Context ( ) , tt . claims ( user . ID , accountID ) , test . MasterDB , user . ID , true )
if errors . Cause ( err ) != ErrNotFound {
t . Logf ( "\t\tGot : %+v" , err )
t . Logf ( "\t\tWant: %+v" , ErrNotFound )
t . Fatalf ( "\t%s\tVerify DeleteAccount failed when including archived." , tests . Failed )
}
}
t . Logf ( "\t%s\tDeleteAccount ok." , tests . Success )
}
}
}
}
// TestAccountFind validates all the request params are correctly parsed into a select query.
func TestAccountFind ( t * testing . T ) {
2019-05-29 15:05:17 -05:00
now := time . Now ( ) . Add ( time . Hour * - 2 ) . UTC ( )
2019-05-29 03:35:08 -05:00
2019-05-29 15:05:17 -05:00
startTime := now . Truncate ( time . Millisecond )
var endTime time . Time
2019-05-29 03:35:08 -05:00
var userAccounts [ ] * UserAccount
for i := 0 ; i <= 4 ; i ++ {
user , err := Create ( tests . Context ( ) , auth . Claims { } , test . MasterDB , CreateUserRequest {
Name : "Lee Brown" ,
Email : uuid . NewRandom ( ) . String ( ) + "@geeksinthewoods.com" ,
Password : "akTechFr0n!ier" ,
PasswordConfirm : "akTechFr0n!ier" ,
} , now . Add ( time . Second * time . Duration ( i ) ) )
if err != nil {
t . Logf ( "\t\tGot : %+v" , err )
t . Fatalf ( "\t%s\tCreate user failed." , tests . Failed )
}
// Create a new random account and associate that with the user.
accountID := uuid . NewRandom ( ) . String ( )
ua , err := AddAccount ( tests . Context ( ) , auth . Claims { } , test . MasterDB , AddAccountRequest {
2019-05-29 15:05:17 -05:00
UserID : user . ID ,
2019-05-29 03:35:08 -05:00
AccountID : accountID ,
2019-05-29 15:05:17 -05:00
Roles : [ ] UserAccountRole { UserAccountRole_User } ,
2019-05-29 03:35:08 -05:00
} , now . Add ( time . Second * time . Duration ( i ) ) )
if err != nil {
t . Logf ( "\t\tGot : %+v" , err )
t . Fatalf ( "\t%s\tAdd account failed." , tests . Failed )
}
userAccounts = append ( userAccounts , ua )
2019-05-29 15:05:17 -05:00
endTime = user . CreatedAt
2019-05-29 03:35:08 -05:00
}
type accountTest struct {
name string
req UserAccountFindRequest
expected [ ] * UserAccount
error error
}
var accountTests [ ] accountTest
2019-05-29 15:05:17 -05:00
createdFilter := "created_at BETWEEN ? AND ?"
2019-05-29 03:35:08 -05:00
// Test sort users.
accountTests = append ( accountTests , accountTest { "Find all order by created_at asx" ,
UserAccountFindRequest {
2019-05-29 15:05:17 -05:00
Where : & createdFilter ,
Args : [ ] interface { } { startTime , endTime } ,
2019-05-29 03:35:08 -05:00
Order : [ ] string { "created_at" } ,
} ,
userAccounts ,
nil ,
} )
// Test reverse sorted user accounts.
var expected [ ] * UserAccount
for i := len ( userAccounts ) - 1 ; i >= 0 ; i -- {
expected = append ( expected , userAccounts [ i ] )
}
accountTests = append ( accountTests , accountTest { "Find all order by created_at desc" ,
UserAccountFindRequest {
2019-05-29 15:05:17 -05:00
Where : & createdFilter ,
Args : [ ] interface { } { startTime , endTime } ,
2019-05-29 03:35:08 -05:00
Order : [ ] string { "created_at desc" } ,
} ,
expected ,
nil ,
} )
// Test limit.
var limit uint = 2
accountTests = append ( accountTests , accountTest { "Find limit" ,
UserAccountFindRequest {
2019-05-29 15:05:17 -05:00
Where : & createdFilter ,
Args : [ ] interface { } { startTime , endTime } ,
2019-05-29 03:35:08 -05:00
Order : [ ] string { "created_at" } ,
Limit : & limit ,
} ,
userAccounts [ 0 : 2 ] ,
nil ,
} )
// Test offset.
var offset uint = 3
accountTests = append ( accountTests , accountTest { "Find limit, offset" ,
UserAccountFindRequest {
2019-05-29 15:05:17 -05:00
Where : & createdFilter ,
Args : [ ] interface { } { startTime , endTime } ,
2019-05-29 03:35:08 -05:00
Order : [ ] string { "created_at" } ,
Limit : & limit ,
Offset : & offset ,
} ,
userAccounts [ 3 : 5 ] ,
nil ,
} )
// Test where filter.
whereParts := [ ] string { }
2019-05-29 15:05:17 -05:00
whereArgs := [ ] interface { } { startTime , endTime }
2019-05-29 03:35:08 -05:00
expected = [ ] * UserAccount { }
2019-05-29 15:05:17 -05:00
for i := 0 ; i <= len ( userAccounts ) ; i ++ {
if rand . Intn ( 100 ) < 50 {
2019-05-29 03:35:08 -05:00
continue
}
2019-05-29 15:05:17 -05:00
ua := * userAccounts [ i ]
2019-05-29 03:35:08 -05:00
whereParts = append ( whereParts , "id = ?" )
2019-05-29 15:05:17 -05:00
whereArgs = append ( whereArgs , ua . ID )
expected = append ( expected , & ua )
2019-05-29 03:35:08 -05:00
}
2019-05-29 15:05:17 -05:00
where := createdFilter + " AND (" + strings . Join ( whereParts , " OR " ) + ")"
2019-05-29 03:35:08 -05:00
accountTests = append ( accountTests , accountTest { "Find where" ,
UserAccountFindRequest {
Where : & where ,
Args : whereArgs ,
2019-05-29 15:05:17 -05:00
Order : [ ] string { "created_at" } ,
2019-05-29 03:35:08 -05:00
} ,
expected ,
nil ,
} )
t . Log ( "Given the need to ensure find users returns the expected results." )
{
for i , tt := range accountTests {
t . Logf ( "\tTest: %d\tWhen running test: %s" , i , tt . name )
{
ctx := tests . Context ( )
res , err := FindAccounts ( ctx , auth . Claims { } , test . MasterDB , tt . req )
if err != nil && errors . Cause ( err ) != tt . error {
t . Logf ( "\t\tGot : %+v" , err )
t . Logf ( "\t\tWant: %+v" , tt . error )
t . Fatalf ( "\t%s\tFind failed." , tests . Failed )
} else if diff := cmp . Diff ( res , tt . expected ) ; diff != "" {
t . Logf ( "\t\tGot: %d items" , len ( res ) )
t . Logf ( "\t\tWant: %d items" , len ( tt . expected ) )
t . Fatalf ( "\t%s\tExpected find result to match expected. Diff:\n%s" , tests . Failed , diff )
}
t . Logf ( "\t%s\tFind ok." , tests . Success )
}
}
}
}